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:
YRabbit 2023-07-23 16:46:04 +10:00 committed by myrtle
parent 49f8620ac9
commit df13104384
7 changed files with 164 additions and 7 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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);
}

View File

@ -146,6 +146,7 @@ void GowinImpl::pack()
}
gowin_pack(ctx);
}
void GowinImpl::prePlace() { assign_cell_info(); }
void GowinImpl::postPlace()
{

View File

@ -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,

View File

@ -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()

View File

@ -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();