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)
|
||||
|
||||
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")
|
||||
for i, tt in enumerate(self.tile_types):
|
||||
@ -573,8 +577,11 @@ class Chip:
|
||||
bba.u32(0)
|
||||
# db-defined constids
|
||||
bba.ref("constids")
|
||||
# extra data: not yet used
|
||||
bba.u32(0)
|
||||
# extra data
|
||||
if self.extra_data is not None:
|
||||
bba.ref("extra_data")
|
||||
else:
|
||||
bba.u32(0)
|
||||
|
||||
def write_bba(self, filename):
|
||||
with open(filename, "w") as f:
|
||||
|
@ -1060,6 +1060,8 @@ X(router)
|
||||
X(GOWIN_GND)
|
||||
X(GOWIN_VCC)
|
||||
X(PLL)
|
||||
X(BOTTOM_IO_PORT_A)
|
||||
X(BOTTOM_IO_PORT_B)
|
||||
|
||||
// wire types
|
||||
X(GLOBAL_CLK)
|
||||
|
@ -47,7 +47,7 @@ struct GowinCstReader
|
||||
row = col;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -146,6 +146,7 @@ void GowinImpl::pack()
|
||||
}
|
||||
gowin_pack(ctx);
|
||||
}
|
||||
|
||||
void GowinImpl::prePlace() { assign_cell_info(); }
|
||||
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
|
||||
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); }
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
RAMW_Z = 36, // RAM16SDP4
|
||||
|
||||
IOBA_Z = 50,
|
||||
IOBB_Z = 51, // +IOBC...IOBL
|
||||
|
||||
PLL_Z = 275,
|
||||
GSR_Z = 276,
|
||||
VCC_Z = 277,
|
||||
|
@ -22,11 +22,17 @@ MUX27_Z = 29
|
||||
ALU0_Z = 30 # : 35, 6 ALUs
|
||||
RAMW_Z = 36 # RAM16SDP4
|
||||
|
||||
IOBA_Z = 50
|
||||
IOBB_Z = 51
|
||||
|
||||
PLL_Z = 275
|
||||
GSR_Z = 276
|
||||
VCC_Z = 277
|
||||
GND_Z = 278
|
||||
|
||||
# =======================================
|
||||
# Chipdb additional info
|
||||
# =======================================
|
||||
@dataclass
|
||||
class TileExtraData(BBAStruct):
|
||||
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):
|
||||
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()
|
||||
|
||||
# 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['O'], "IO_O")
|
||||
# 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, "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)
|
||||
return (ttyp, tt)
|
||||
|
||||
@ -425,6 +478,13 @@ def create_packages(chip: Chip, db: chipdb):
|
||||
bank = int(db.pin_bank[io_loc])
|
||||
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():
|
||||
parser = argparse.ArgumentParser(description='Make Gowin BBA')
|
||||
parser.add_argument('-d', '--device', required=True)
|
||||
@ -492,6 +552,7 @@ def main():
|
||||
|
||||
# Create nodes between tiles
|
||||
create_nodes(ch, db)
|
||||
create_extra_data(ch, db)
|
||||
ch.write_bba(args.output)
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -21,9 +21,37 @@ struct GowinPacker
|
||||
// ===================================
|
||||
// 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
|
||||
const pool<CellTypePort> top_ports{
|
||||
CellTypePort(id_IBUF, id_I),
|
||||
@ -62,6 +90,34 @@ struct GowinPacker
|
||||
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
|
||||
// ===================================
|
||||
@ -570,8 +626,8 @@ struct GowinPacker
|
||||
|
||||
void run(void)
|
||||
{
|
||||
pack_iobs();
|
||||
handle_constants();
|
||||
pack_iobs();
|
||||
pack_gsr();
|
||||
pack_wideluts();
|
||||
pack_alus();
|
||||
|
Loading…
Reference in New Issue
Block a user