diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 57938b0a..df333f71 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -885,6 +885,27 @@ X(DIC) X(DID) X(WRE) +// BSRAM +X(BSRAM_SUBTYPE) +X(BIT_WIDTH) +X(ROM) +X(SP) +X(SPX9) +X(pROM) +X(pROMX9) +X(BSRAM) +X(OCE) +X(OCEA) +X(OCEB) +X(CEA) +X(CEB) +X(RESETA) +X(RESETB) +X(WREA) +X(WREB) +X(CLKA) +X(CLKB) + // IOB types X(IBUF) X(OBUF) @@ -1064,6 +1085,8 @@ X(BOTTOM_IO_PORT_A) X(BOTTOM_IO_PORT_B) X(IOLOGIC_DUMMY) +// + // wire types X(GLOBAL_CLK) X(TILE_CLK) diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index ed2c3fcc..920d86fa 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -266,6 +266,9 @@ IdString GowinImpl::getBelBucketForCellType(IdString cell_type) const if (type_is_iologic(cell_type)) { return id_IOLOGIC; } + if (type_is_bsram(cell_type)) { + return id_BSRAM; + } if (cell_type == id_GOWIN_GND) { return id_GND; } @@ -293,6 +296,9 @@ bool GowinImpl::isValidBelForCellType(IdString cell_type, BelId bel) const if (bel_type == id_IOLOGIC) { return type_is_iologic(cell_type); } + if (bel_type == id_BSRAM) { + return type_is_bsram(cell_type); + } if (bel_type == id_GND) { return cell_type == id_GOWIN_GND; } diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index f92049a5..842bf34d 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -39,6 +39,10 @@ inline bool is_iologic(const CellInfo *cell) { return type_is_iologic(cell->type 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); } +// Return true if a cell is a SSRAM +inline bool type_is_bsram(IdString cell_type) { return cell_type.in(id_SP, id_SPX9, id_pROM, id_pROMX9, id_ROM); } +inline bool is_bsram(const CellInfo *cell) { return type_is_bsram(cell->type); } + // ========================================== // extra data in the chip db // ========================================== @@ -89,6 +93,7 @@ enum OSER16_Z = 73, BUFG_Z = 74, // : 81 reserve just in case + BSRAM_Z = 100, OSC_Z = 274, PLL_Z = 275, diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index be507f38..f5373644 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -33,6 +33,7 @@ IDES16_Z = 72 OSER16_Z = 73 BUFG_Z = 74 # : 81 reserve just in case +BSRAM_Z = 100 OSC_Z = 274 PLL_Z = 275 @@ -561,9 +562,49 @@ def create_ssram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tde tt.add_bel_pin(ff, f"RAD[{i}]", f"{lut_inputs[i]}0", PinType.INPUT) tt.add_bel_pin(ff, f"DO[{i}]", f"F{i}", PinType.OUTPUT) - tt.add_bel_pin(ff, f"CLK", "CLK2", PinType.INPUT) - tt.add_bel_pin(ff, f"CE", "CE2", PinType.INPUT) - tt.add_bel_pin(ff, f"WRE", "LSR2", PinType.INPUT) + tt.add_bel_pin(ff, "CLK", "CLK2", PinType.INPUT) + tt.add_bel_pin(ff, "CE", "CE2", PinType.INPUT) + tt.add_bel_pin(ff, "WRE", "LSR2", PinType.INPUT) + return tt + +# BSRAM +_bsram_inputs = {'CLK', 'OCE', 'CE', 'RESET', 'WRE'} +def create_bsram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc): + typename = "BSRAM" + tiletype = f"{typename}_{ttyp}" + if tdesc.sfx != 0: + tiletype += f"_{tdesc.sfx}" + tt = chip.create_tile_type(tiletype) + tt.extra_data = TileExtraData(chip.strs.id(typename)) + + portmap = db.grid[y][x].bels['BSRAM'].portmap + bsram = tt.create_bel("BSRAM", "BSRAM", z = BSRAM_Z) + + def add_port_wire(tt, bel, name, wire_type = "BSRAM_I", port_type = PinType.INPUT): + wire = portmap[name] + if not tt.has_wire(wire): + if name.startswith('CLK'): + tt.create_wire(wire, "TILE_CLK") + else: + tt.create_wire(wire, wire_type) + tt.add_bel_pin(bel, name, wire, port_type) + + for sfx in {'', 'A', 'B'}: + for inp in _bsram_inputs: + add_port_wire(tt, bsram, f"{inp}{sfx}") + for idx in range(3): + add_port_wire(tt, bsram, f"BLKSEL{sfx}{idx}") + for idx in range(14): + add_port_wire(tt, bsram, f"AD{sfx}{idx}") + for idx in range(18): + add_port_wire(tt, bsram, f"DI{sfx}{idx}") + add_port_wire(tt, bsram, f"DO{sfx}{idx}", "BSRAM_O", PinType.OUTPUT) + if not sfx: + for idx in range(18, 36): + add_port_wire(tt, bsram, f"DI{idx}") + add_port_wire(tt, bsram, f"DO{idx}", "BSRAM_O", PinType.OUTPUT) + + tdesc.tiletype = tiletype return tt # PLL main tile @@ -687,6 +728,7 @@ def main(): io_tiletypes = db.tile_types['I'] ssram_tiletypes = db.tile_types['M'] pll_tiletypes = db.tile_types['P'] + bsram_tiletypes = db.tile_types['B'] # Setup tile grid for x in range(X): @@ -704,6 +746,8 @@ def main(): create_tiletype(create_io_tiletype, ch, db, x, y, ttyp) elif ttyp in pll_tiletypes: create_tiletype(create_pll_tiletype, ch, db, x, y, ttyp) + elif ttyp in bsram_tiletypes: + create_tiletype(create_bsram_tiletype, ch, db, x, y, ttyp) else: create_tiletype(create_null_tiletype, ch, db, x, y, ttyp) diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 621c7fff..78799401 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1191,7 +1191,6 @@ struct GowinPacker // =================================== // SSRAM cluster // =================================== - // create ALU filler block std::unique_ptr ssram_make_lut(Context *ctx, CellInfo *ci, int index) { IdString name_id = ctx->idf("%s_LUT%d", ci->name.c_str(ctx), index); @@ -1273,6 +1272,82 @@ struct GowinPacker } } + // =================================== + // Block RAM + // =================================== + void pack_ROM(CellInfo *ci) + { + // use block 111 + ci->setParam(ctx->id("BLK_SEL"), Property(7, 32)); + if (ci->type == id_pROM) { + ci->setAttr(id_BSRAM_SUBTYPE, Property("")); + } else { + ci->setAttr(id_BSRAM_SUBTYPE, Property("X9")); + } + + NetInfo *vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC")).get(); + NetInfo *vss_net = ctx->nets.at(ctx->id("$PACKER_GND")).get(); + for (int i = 0; i < 3; ++i) { + IdString port = ctx->idf("BLKSEL%d", i); + ci->addInput(port); + ci->connectPort(port, vcc_net); + port = ctx->idf("BLKSELB%d", i); + ci->addInput(port); + ci->connectPort(port, vcc_net); + } + // use port B + ci->renamePort(id_CLK, id_CLKB); + ci->renamePort(id_OCE, id_OCEB); + ci->renamePort(id_CE, id_CEB); + ci->renamePort(id_RESET, id_RESETB); + ci->addInput(id_WRE); + ci->connectPort(id_WRE, vss_net); + ci->addInput(id_WREB); + ci->connectPort(id_WREB, vss_net); + + if (!ci->params.count(id_BIT_WIDTH)) { + ci->setParam(id_BIT_WIDTH, Property(32, 32)); + } + int bit_width = ci->params[id_BIT_WIDTH].as_int64(); + if (bit_width == 32 || bit_width == 36) { + log_error("Bit width %d is not supported\n", bit_width); + } + for (int i = 0; i < 14; ++i) { + ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADB%d", i)); + } + int out_num = (bit_width == 9 || bit_width == 18) ? 36 : 32; + for (int i = 0, j = 18; i < out_num; ++i, ++j) { + if (((i + 1) % 9) == 0 && bit_width == 16) { + ++j; + } + ci->renamePort(ctx->idf("DO[%d]", i), ctx->idf("DO%d", j % 36)); + } + } + + void pack_bsram(void) + { + log_info("Pack BSRAMs...\n"); + + for (auto &cell : ctx->cells) { + auto ci = cell.second.get(); + + if (is_bsram(ci)) { + if (ctx->verbose) { + log_info(" pack %s\n", ci->type.c_str(ctx)); + } + switch (ci->type.hash()) { + case ID_pROM: /* fallthrough */ + case ID_pROMX9: + pack_ROM(ci); + ci->type = id_ROM; + break; + default: + log_error("Unsupported BSRAM type '%s'\n", ci->type.c_str(ctx)); + } + } + } + } + // =================================== // Global set/reset // =================================== @@ -1397,6 +1472,9 @@ struct GowinPacker pack_ram16sdp4(); ctx->check(); + pack_bsram(); + ctx->check(); + pack_buffered_nets(); ctx->fixupHierarchy();