gowin: Himbaechel. Add extra chip data
To implement unusual IOs that have a dynamically changing configuration it is convenient to store the switching method in the additional chip data. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
49f8620ac9
commit
df13104384
@ -531,6 +531,10 @@ class Chip:
|
|||||||
tinst.serialise_lists(f"tinst_{x}_{y}", bba)
|
tinst.serialise_lists(f"tinst_{x}_{y}", bba)
|
||||||
|
|
||||||
self.strs.serialise_lists(f"constids", bba)
|
self.strs.serialise_lists(f"constids", bba)
|
||||||
|
if self.extra_data is not None:
|
||||||
|
self.extra_data.serialise_lists("extra_data", bba)
|
||||||
|
bba.label("extra_data")
|
||||||
|
self.extra_data.serialise("extra_data", bba)
|
||||||
|
|
||||||
bba.label(f"tile_types")
|
bba.label(f"tile_types")
|
||||||
for i, tt in enumerate(self.tile_types):
|
for i, tt in enumerate(self.tile_types):
|
||||||
@ -573,7 +577,10 @@ class Chip:
|
|||||||
bba.u32(0)
|
bba.u32(0)
|
||||||
# db-defined constids
|
# db-defined constids
|
||||||
bba.ref("constids")
|
bba.ref("constids")
|
||||||
# extra data: not yet used
|
# extra data
|
||||||
|
if self.extra_data is not None:
|
||||||
|
bba.ref("extra_data")
|
||||||
|
else:
|
||||||
bba.u32(0)
|
bba.u32(0)
|
||||||
|
|
||||||
def write_bba(self, filename):
|
def write_bba(self, filename):
|
||||||
|
@ -1060,6 +1060,8 @@ X(router)
|
|||||||
X(GOWIN_GND)
|
X(GOWIN_GND)
|
||||||
X(GOWIN_VCC)
|
X(GOWIN_VCC)
|
||||||
X(PLL)
|
X(PLL)
|
||||||
|
X(BOTTOM_IO_PORT_A)
|
||||||
|
X(BOTTOM_IO_PORT_B)
|
||||||
|
|
||||||
// wire types
|
// wire types
|
||||||
X(GLOBAL_CLK)
|
X(GLOBAL_CLK)
|
||||||
|
@ -47,7 +47,7 @@ struct GowinCstReader
|
|||||||
row = col;
|
row = col;
|
||||||
col = 1;
|
col = 1;
|
||||||
}
|
}
|
||||||
int z = match[3].str()[0] - 'A';
|
int z = match[3].str()[0] - 'A' + BelZ::IOBA_Z;
|
||||||
return Loc(col - 1, row - 1, z);
|
return Loc(col - 1, row - 1, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ void GowinImpl::pack()
|
|||||||
}
|
}
|
||||||
gowin_pack(ctx);
|
gowin_pack(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GowinImpl::prePlace() { assign_cell_info(); }
|
void GowinImpl::prePlace() { assign_cell_info(); }
|
||||||
void GowinImpl::postPlace()
|
void GowinImpl::postPlace()
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,33 @@ inline bool is_alu(const CellInfo *cell) { return type_is_alu(cell->type); }
|
|||||||
// Return true if a cell is a SSRAM
|
// Return true if a cell is a SSRAM
|
||||||
inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); }
|
inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); }
|
||||||
inline bool is_ssram(const CellInfo *cell) { return type_is_ssram(cell->type); }
|
inline bool is_ssram(const CellInfo *cell) { return type_is_ssram(cell->type); }
|
||||||
|
|
||||||
|
// extra data in the chip db
|
||||||
|
NPNR_PACKED_STRUCT(struct Bottom_io_cnd_POD {
|
||||||
|
int32_t wire_a_net;
|
||||||
|
int32_t wire_b_net;
|
||||||
|
});
|
||||||
|
|
||||||
|
NPNR_PACKED_STRUCT(struct Bottom_io_POD {
|
||||||
|
// simple OBUF
|
||||||
|
static constexpr int8_t NORMAL = 0;
|
||||||
|
RelSlice<Bottom_io_cnd_POD> conditions;
|
||||||
|
});
|
||||||
|
|
||||||
|
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { Bottom_io_POD bottom_io; });
|
||||||
|
|
||||||
|
inline IdString get_bottom_io_wire_a_net(const ChipInfoPOD *chip, int8_t condition)
|
||||||
|
{
|
||||||
|
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(chip->extra_data.get());
|
||||||
|
return IdString(extra->bottom_io.conditions[condition].wire_a_net);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IdString get_bottom_io_wire_b_net(const ChipInfoPOD *chip, int8_t condition)
|
||||||
|
{
|
||||||
|
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(chip->extra_data.get());
|
||||||
|
return IdString(extra->bottom_io.conditions[condition].wire_b_net);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Bels Z ranges. It is desirable that these numbers be synchronized with the chipdb generator
|
// Bels Z ranges. It is desirable that these numbers be synchronized with the chipdb generator
|
||||||
@ -39,6 +66,9 @@ enum
|
|||||||
ALU0_Z = 30, // :35, 6 ALU
|
ALU0_Z = 30, // :35, 6 ALU
|
||||||
RAMW_Z = 36, // RAM16SDP4
|
RAMW_Z = 36, // RAM16SDP4
|
||||||
|
|
||||||
|
IOBA_Z = 50,
|
||||||
|
IOBB_Z = 51, // +IOBC...IOBL
|
||||||
|
|
||||||
PLL_Z = 275,
|
PLL_Z = 275,
|
||||||
GSR_Z = 276,
|
GSR_Z = 276,
|
||||||
VCC_Z = 277,
|
VCC_Z = 277,
|
||||||
|
@ -22,11 +22,17 @@ MUX27_Z = 29
|
|||||||
ALU0_Z = 30 # : 35, 6 ALUs
|
ALU0_Z = 30 # : 35, 6 ALUs
|
||||||
RAMW_Z = 36 # RAM16SDP4
|
RAMW_Z = 36 # RAM16SDP4
|
||||||
|
|
||||||
|
IOBA_Z = 50
|
||||||
|
IOBB_Z = 51
|
||||||
|
|
||||||
PLL_Z = 275
|
PLL_Z = 275
|
||||||
GSR_Z = 276
|
GSR_Z = 276
|
||||||
VCC_Z = 277
|
VCC_Z = 277
|
||||||
GND_Z = 278
|
GND_Z = 278
|
||||||
|
|
||||||
|
# =======================================
|
||||||
|
# Chipdb additional info
|
||||||
|
# =======================================
|
||||||
@dataclass
|
@dataclass
|
||||||
class TileExtraData(BBAStruct):
|
class TileExtraData(BBAStruct):
|
||||||
tile_class: IdString # The general functionality of the slightly different tiles,
|
tile_class: IdString # The general functionality of the slightly different tiles,
|
||||||
@ -38,6 +44,45 @@ class TileExtraData(BBAStruct):
|
|||||||
def serialise(self, context: str, bba: BBAWriter):
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
bba.u32(self.tile_class.index)
|
bba.u32(self.tile_class.index)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BottomIOCnd(BBAStruct):
|
||||||
|
wire_a_net: IdString
|
||||||
|
wire_b_net: IdString
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
pass
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
bba.u32(self.wire_a_net.index)
|
||||||
|
bba.u32(self.wire_b_net.index)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BottomIO(BBAStruct):
|
||||||
|
conditions: list[BottomIOCnd] = field(default_factory = list)
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
bba.label(f"{context}_conditions")
|
||||||
|
for i, cnd in enumerate(self.conditions):
|
||||||
|
cnd.serialise(f"{context}_cnd{i}", bba)
|
||||||
|
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
bba.slice(f"{context}_conditions", len(self.conditions))
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ChipExtraData(BBAStruct):
|
||||||
|
strs: StringPool
|
||||||
|
bottom_io: BottomIO
|
||||||
|
|
||||||
|
def create_bottom_io(self):
|
||||||
|
self.bottom_io = BottomIO()
|
||||||
|
|
||||||
|
def add_bottom_io_cnd(self, net_a: str, net_b: str):
|
||||||
|
self.bottom_io.conditions.append(BottomIOCnd(self.strs.id(net_a), self.strs.id(net_b)))
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
self.bottom_io.serialise_lists(f"{context}_bottom_io", bba)
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
self.bottom_io.serialise(f"{context}_bottom_io", bba)
|
||||||
|
|
||||||
created_tiletypes = set()
|
created_tiletypes = set()
|
||||||
|
|
||||||
# u-turn at the rim
|
# u-turn at the rim
|
||||||
@ -224,9 +269,17 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
|
|||||||
tt.create_wire(portmap['I'], "IO_I")
|
tt.create_wire(portmap['I'], "IO_I")
|
||||||
tt.create_wire(portmap['O'], "IO_O")
|
tt.create_wire(portmap['O'], "IO_O")
|
||||||
# bels
|
# bels
|
||||||
io = tt.create_bel(name, "IOB", z = i)
|
io = tt.create_bel(name, "IOB", z = IOBA_Z + i)
|
||||||
tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT)
|
tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT)
|
||||||
tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT)
|
tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT)
|
||||||
|
# bottom io
|
||||||
|
if 'BOTTOM_IO_PORT_A' in portmap.keys():
|
||||||
|
if not tt.has_wire(portmap['BOTTOM_IO_PORT_A']):
|
||||||
|
tt.create_wire(portmap['BOTTOM_IO_PORT_A'], "IO_I")
|
||||||
|
tt.create_wire(portmap['BOTTOM_IO_PORT_B'], "IO_I")
|
||||||
|
tt.add_bel_pin(io, "BOTTOM_IO_PORT_A", portmap['BOTTOM_IO_PORT_A'], PinType.INPUT)
|
||||||
|
tt.add_bel_pin(io, "BOTTOM_IO_PORT_B", portmap['BOTTOM_IO_PORT_B'], PinType.INPUT)
|
||||||
|
|
||||||
create_switch_matrix(tt, db, x, y)
|
create_switch_matrix(tt, db, x, y)
|
||||||
return (ttyp, tt)
|
return (ttyp, tt)
|
||||||
|
|
||||||
@ -425,6 +478,13 @@ def create_packages(chip: Chip, db: chipdb):
|
|||||||
bank = int(db.pin_bank[io_loc])
|
bank = int(db.pin_bank[io_loc])
|
||||||
pad = pkg.create_pad(pinno, tile, bel, pad_func, bank)
|
pad = pkg.create_pad(pinno, tile, bel, pad_func, bank)
|
||||||
|
|
||||||
|
# Extra chip data
|
||||||
|
def create_extra_data(chip: Chip, db: chipdb):
|
||||||
|
chip.extra_data = ChipExtraData(chip.strs, None)
|
||||||
|
chip.extra_data.create_bottom_io()
|
||||||
|
for net_a, net_b in db.bottom_io[2]:
|
||||||
|
chip.extra_data.add_bottom_io_cnd(net_a, net_b)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Make Gowin BBA')
|
parser = argparse.ArgumentParser(description='Make Gowin BBA')
|
||||||
parser.add_argument('-d', '--device', required=True)
|
parser.add_argument('-d', '--device', required=True)
|
||||||
@ -492,6 +552,7 @@ def main():
|
|||||||
|
|
||||||
# Create nodes between tiles
|
# Create nodes between tiles
|
||||||
create_nodes(ch, db)
|
create_nodes(ch, db)
|
||||||
|
create_extra_data(ch, db)
|
||||||
ch.write_bba(args.output)
|
ch.write_bba(args.output)
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -21,9 +21,37 @@ struct GowinPacker
|
|||||||
// ===================================
|
// ===================================
|
||||||
// IO
|
// IO
|
||||||
// ===================================
|
// ===================================
|
||||||
void pack_iobs(void)
|
void config_bottom_row(CellInfo &ci, Loc loc, uint8_t cnd = Bottom_io_POD::NORMAL)
|
||||||
|
{
|
||||||
|
if (!ci.type.in(id_OBUF, id_TBUF, id_IOBUF)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cnd == Bottom_io_POD::NORMAL && loc.z != BelZ::IOBA_Z) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto connect_io_wire = [&](IdString port, IdString net_name) {
|
||||||
|
// XXX it is very convenient that nothing terrible happens in case
|
||||||
|
// of absence/presence of a port
|
||||||
|
ci.disconnectPort(port);
|
||||||
|
ci.addInput(port);
|
||||||
|
if (net_name == id_VSS) {
|
||||||
|
ci.connectPort(port, ctx->nets[ctx->id("$PACKER_GND")].get());
|
||||||
|
} else {
|
||||||
|
NPNR_ASSERT(net_name == id_VCC);
|
||||||
|
ci.connectPort(port, ctx->nets[ctx->id("$PACKER_VCC")].get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IdString wire_a_net = get_bottom_io_wire_a_net(ctx->chip_info, cnd);
|
||||||
|
connect_io_wire(id_BOTTOM_IO_PORT_A, wire_a_net);
|
||||||
|
|
||||||
|
IdString wire_b_net = get_bottom_io_wire_b_net(ctx->chip_info, cnd);
|
||||||
|
connect_io_wire(id_BOTTOM_IO_PORT_B, wire_b_net);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes of deleted cells are copied
|
||||||
|
void trim_nextpnr_iobs(void)
|
||||||
{
|
{
|
||||||
log_info("Pack IOBs...\n");
|
|
||||||
// Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis
|
// Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis
|
||||||
const pool<CellTypePort> top_ports{
|
const pool<CellTypePort> top_ports{
|
||||||
CellTypePort(id_IBUF, id_I),
|
CellTypePort(id_IBUF, id_I),
|
||||||
@ -62,6 +90,34 @@ struct GowinPacker
|
|||||||
ctx->cells.erase(cell_name);
|
ctx->cells.erase(cell_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BelId bind_io(CellInfo &ci)
|
||||||
|
{
|
||||||
|
BelId bel = ctx->getBelByName(IdStringList::parse(ctx, ci.attrs.at(id_BEL).as_string()));
|
||||||
|
ci.unsetAttr(id_BEL);
|
||||||
|
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
|
||||||
|
return bel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pack_iobs(void)
|
||||||
|
{
|
||||||
|
log_info("Pack IOBs...\n");
|
||||||
|
trim_nextpnr_iobs();
|
||||||
|
|
||||||
|
for (auto &cell : ctx->cells) {
|
||||||
|
CellInfo &ci = *cell.second;
|
||||||
|
if (!ci.type.in(id_IBUF, id_OBUF, id_IOBUF)) // XXX TBUF
|
||||||
|
continue;
|
||||||
|
if (ci.attrs.count(id_BEL) == 0) {
|
||||||
|
log_error("Unconstrained IO:%s\n", ctx->nameOf(&ci));
|
||||||
|
}
|
||||||
|
BelId io_bel = bind_io(ci);
|
||||||
|
Loc io_loc = ctx->getBelLocation(io_bel);
|
||||||
|
if (io_loc.y == ctx->getGridDimY() - 1) {
|
||||||
|
config_bottom_row(ci, io_loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===================================
|
// ===================================
|
||||||
// Constant nets
|
// Constant nets
|
||||||
// ===================================
|
// ===================================
|
||||||
@ -570,8 +626,8 @@ struct GowinPacker
|
|||||||
|
|
||||||
void run(void)
|
void run(void)
|
||||||
{
|
{
|
||||||
pack_iobs();
|
|
||||||
handle_constants();
|
handle_constants();
|
||||||
|
pack_iobs();
|
||||||
pack_gsr();
|
pack_gsr();
|
||||||
pack_wideluts();
|
pack_wideluts();
|
||||||
pack_alus();
|
pack_alus();
|
||||||
|
Loading…
Reference in New Issue
Block a user