From 03c413a27a93ad2f1b69a246ff9733e8b78a9842 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 25 Jul 2023 13:25:33 +1000 Subject: [PATCH] gowin: Himbaechel. Add simplified IO Add processing IO located on the sides of some chips. These are IOBUF, which are converted into IBUF and OBUF not by fuses, but by signaling to OE. Also added the creation of a Global Set / Reset for all chips, instead of a list of tile types, information from the apicula database is used, and minor fixes. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/globals.cc | 2 +- himbaechel/uarch/gowin/gowin.h | 14 ++++++++ himbaechel/uarch/gowin/gowin_arch_gen.py | 38 ++++++++++++++++++---- himbaechel/uarch/gowin/pack.cc | 41 +++++++++++++++++++----- 4 files changed, 79 insertions(+), 16 deletions(-) diff --git a/himbaechel/uarch/gowin/globals.cc b/himbaechel/uarch/gowin/globals.cc index 01ebaf8c..ecb99e43 100644 --- a/himbaechel/uarch/gowin/globals.cc +++ b/himbaechel/uarch/gowin/globals.cc @@ -52,7 +52,7 @@ struct GowinGlobalRouter bool src_valid = src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O); bool dst_valid = dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I); - if (ctx->debug) { + if (ctx->debug && false) { log_info("%s <- %s [%s <- %s]\n", ctx->getWireName(ctx->getPipDstWire(pip)).str(ctx).c_str(), ctx->getWireName(ctx->getPipSrcWire(pip)).str(ctx).c_str(), dst_type.c_str(ctx), src_type.c_str(ctx)); diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 2a931480..8f21c23a 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -5,6 +5,10 @@ NEXTPNR_NAMESPACE_BEGIN +namespace BelFlags { +static constexpr uint32_t FLAG_SIMPLE_IO = 0x100; +} + namespace { // Return true if a cell is a LUT inline bool type_is_lut(IdString cell_type) { return cell_type.in(id_LUT1, id_LUT2, id_LUT3, id_LUT4); } @@ -39,6 +43,12 @@ NPNR_PACKED_STRUCT(struct Bottom_io_POD { NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { Bottom_io_POD bottom_io; }); +inline bool have_bottom_io_cnds(const ChipInfoPOD *chip) +{ + const Extra_chip_data_POD *extra = reinterpret_cast(chip->extra_data.get()); + return extra->bottom_io.conditions.size() != 0; +} + inline IdString get_bottom_io_wire_a_net(const ChipInfoPOD *chip, int8_t condition) { const Extra_chip_data_POD *extra = reinterpret_cast(chip->extra_data.get()); @@ -51,6 +61,10 @@ inline IdString get_bottom_io_wire_b_net(const ChipInfoPOD *chip, int8_t conditi return IdString(extra->bottom_io.conditions[condition].wire_b_net); } +inline bool getBelSimpleIO(const ChipInfoPOD *chip, BelId bel) +{ + return chip_bel_info(chip, bel).flags & BelFlags::FLAG_SIMPLE_IO; +} } // namespace // Bels Z ranges. It is desirable that these numbers be synchronized with the chipdb generator diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 1fee760b..d2482ad7 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -11,6 +11,9 @@ sys.path.append(path.join(path.dirname(__file__), "../..")) from himbaechel_dbgen.chip import * from apycula import chipdb +# Bel flags +BEL_FLAG_SIMPLE_IO = 0x100 + # Z of the bels # sync with C++ part! LUT0_Z = 0 # z(DFFx) = z(LUTx) + 1 @@ -171,7 +174,10 @@ def create_nodes(chip: Chip, db: chipdb): wire_type, node = node_hdr for y, x, wire in node: if wire_type: - chip.tile_type_at(x, y).set_wire_type(wire, wire_type) + if not chip.tile_type_at(x, y).has_wire(wire): + chip.tile_type_at(x, y).create_wire(wire, wire_type) + else: + chip.tile_type_at(x, y).set_wire_type(wire, wire_type) new_node = NodeWire(x, y, wire) gl_nodes = global_nodes.setdefault(node_name, []) if new_node not in gl_nodes: @@ -200,7 +206,7 @@ def create_switch_matrix(tt: TileType, db: chipdb, x: int, y: int): tt.create_wire(src, get_wire_type(src)) tt.create_pip(src, dst) # clock wires - for dst, srcs in db.grid[y][x].clock_pips.items(): + for dst, srcs in db.grid[y][x].pure_clock_pips.items(): if not tt.has_wire(dst): tt.create_wire(dst, "GLOBAL_CLK") for src in srcs.keys(): @@ -234,6 +240,12 @@ def create_corner_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int): tt.create_wire('VCC', 'VCC') gnd = tt.create_bel('VCC', 'VCC', z = VCC_Z) tt.add_bel_pin(gnd, "V", "VCC", PinType.OUTPUT) + # also here may be GSR + if 'GSR' in db.grid[y][x].bels.keys(): + portmap = db.grid[y][x].bels['GSR'].portmap + tt.create_wire(portmap['GSRI'], "GSRI") + io = tt.create_bel("GSR", "GSR", z = GSR_Z) + tt.add_bel_pin(io, "GSRI", portmap['GSRI'], PinType.INPUT) create_switch_matrix(tt, db, x, y) return (ttyp, tt) @@ -262,15 +274,27 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int): tt = chip.create_tile_type(f"{typename}_{ttyp}") tt.extra_data = TileExtraData(chip.strs.id(typename)) - for i in range(2): - name = ['IOBA', 'IOBB'][i] + simple_io = y in db.simplio_rows and chip.name in {'GW1N-1', 'GW1NZ-1'} + if simple_io: + rng = 10 + else: + rng = 2 + for i in range(rng): + name = 'IOB' + 'ABCDEFGHIJ'[i] + # XXX some IOBs excluded from generic chipdb for some reason + if name not in db.grid[y][x].bels.keys(): + continue # wires portmap = db.grid[y][x].bels[name].portmap tt.create_wire(portmap['I'], "IO_I") tt.create_wire(portmap['O'], "IO_O") + tt.create_wire(portmap['OE'], "IO_OE") # bels io = tt.create_bel(name, "IOB", z = IOBA_Z + i) + if simple_io: + io.flags |= BEL_FLAG_SIMPLE_IO tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT) + tt.add_bel_pin(io, "OE", portmap['OE'], PinType.INPUT) tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT) # bottom io if 'BOTTOM_IO_PORT_A' in portmap.keys(): @@ -510,11 +534,11 @@ def main(): # The manufacturer distinguishes by externally identical tiles, so keep # these differences (in case it turns out later that there is a slightly # different routing or something like that). - logic_tiletypes = {12, 13, 14, 15, 16} - io_tiletypes = {52, 53, 54, 55, 58, 59, 64, 65, 66} + logic_tiletypes = db.tile_types['C'] + io_tiletypes = db.tile_types['I'] ssram_tiletypes = {17, 18, 19} gsr_tiletypes = {1} - pll_tiletypes = {86, 87, 42, 45} + pll_tiletypes = db.tile_types['P'] # Setup tile grid for x in range(X): for y in range(Y): diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index c91763f5..ec8816cf 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -21,8 +21,26 @@ struct GowinPacker // =================================== // IO // =================================== + void config_simple_io(CellInfo &ci) + { + if (ci.type.in(id_TBUF, id_IOBUF)) { + return; + } + log_info("simple:%s\n", ctx->nameOf(&ci)); + ci.addInput(id_OE); + if (ci.type == id_OBUF) { + ci.connectPort(id_OE, ctx->nets[ctx->id("$PACKER_GND")].get()); + } else { + NPNR_ASSERT(ci.type == id_IBUF); + ci.connectPort(id_OE, ctx->nets[ctx->id("$PACKER_VCC")].get()); + } + } + void config_bottom_row(CellInfo &ci, Loc loc, uint8_t cnd = Bottom_io_POD::NORMAL) { + if (!have_bottom_io_cnds(ctx->chip_info)) { + return; + } if (!ci.type.in(id_OBUF, id_TBUF, id_IOBUF)) { return; } @@ -93,6 +111,7 @@ struct GowinPacker BelId bind_io(CellInfo &ci) { BelId bel = ctx->getBelByName(IdStringList::parse(ctx, ci.attrs.at(id_BEL).as_string())); + NPNR_ASSERT(bel != BelId()); ci.unsetAttr(id_BEL); ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED); return bel; @@ -115,6 +134,9 @@ struct GowinPacker if (io_loc.y == ctx->getGridDimY() - 1) { config_bottom_row(ci, io_loc); } + if (getBelSimpleIO(ctx->chip_info, io_bel)) { + config_simple_io(ci); + } } } @@ -138,10 +160,11 @@ struct GowinPacker NetInfo *constnet = net->second.get(); for (auto user : constnet->users) { CellInfo *uc = user.cell; - if (ctx->debug) - log_info("%s user %s/%s\n", ctx->nameOf(constnet), ctx->nameOf(uc), user.port.c_str(ctx)); - if (is_lut(uc) && (user.port.str(ctx).at(0) == 'I')) { + if (ctx->debug) { + log_info("%s user %s/%s\n", ctx->nameOf(constnet), ctx->nameOf(uc), user.port.c_str(ctx)); + } + auto it_param = uc->params.find(id_INIT); if (it_param == uc->params.end()) log_error("No initialization for lut found.\n"); @@ -318,9 +341,9 @@ struct GowinPacker // CIN from logic cin_ci->addInput(id_I1); cin_ci->addInput(id_I3); - cin_ci->addInput(id_I2); cin_ci->connectPort(id_I1, cin_net); cin_ci->connectPort(id_I3, cin_net); + cin_ci->addInput(id_I2); cin_ci->connectPort(id_I2, ctx->nets[ctx->id("$PACKER_VCC")].get()); cin_ci->params[id_ALU_MODE] = std::string("0"); // ADD return cin_ci; @@ -342,6 +365,8 @@ struct GowinPacker cout_ci->connectPort(id_CIN, cin_net); cout_ci->addOutput(id_SUM); cout_ci->connectPort(id_SUM, cout_net); + cout_ci->addInput(id_I2); + cout_ci->connectPort(id_I2, ctx->nets[ctx->id("$PACKER_VCC")].get()); cout_ci->params[id_ALU_MODE] = std::string("C2L"); return cout_ci; @@ -425,8 +450,8 @@ struct GowinPacker cout_block_ci->constr_y = 0; cout_block_ci->constr_z = alu_chain_len % 6; if (ctx->debug) { - log_info("Add ALU carry out to the chain (len:%d): %s\n", alu_chain_len, - ctx->nameOf(cout_block_ci)); + log_info("Add ALU carry out to the chain (len:%d): %s COUT-net: %s\n", alu_chain_len, + ctx->nameOf(cout_block_ci), ctx->nameOf(cout_net)); } ++alu_chain_len; @@ -566,7 +591,7 @@ struct GowinPacker // =================================== void pack_gsr(void) { - log_info("Packing GSR..\n"); + log_info("Pack GSR..\n"); bool user_gsr = false; for (auto &cell : ctx->cells) { @@ -603,7 +628,7 @@ struct GowinPacker // =================================== void pack_pll(void) { - log_info("Packing PLL..\n"); + log_info("Pack PLL..\n"); for (auto &cell : ctx->cells) { auto &ci = *cell.second;