From 90d4863dd43cdeeefec3848e35f0d87ce43100f9 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Mon, 20 Nov 2023 12:27:56 +1000 Subject: [PATCH] gowin: Himbaechel. Add GW1NZ-1 BSRAM. The following primitives are implemented for the GW1NZ-1 chip: * pROM - read only memory - (bitwidth: 1, 2, 4, 8, 16, 32). * pROMX9 - read only memory - (bitwidth: 9, 18, 36). * SDPB - semidual port - (bitwidth: 1, 2, 4, 8, 16, 32). * SDPX9B - semidual port - (bitwidth: 9, 18, 36). * DPB - dual port - (bitwidth: 16). * DPX9B - dual port - (bitwidth: 18). * SP - single port - (bitwidth: 1, 2, 4, 8, 16, 32). * SPX9 - single port - (bitwidth: 9, 18, 36). Also: - The creation of databases for GW1NS-2 has been removed - this was not planned to be supported in Himbaechel from the very beginning and even examples were not created in apicula for this chip due to the lack of boards with it on sale. - It is temporarily prohibited to connect DFFs and LUTs into clusters because for some reason this prevents the creation of images on lower chips (placer cannot find the placement), although without these clusters the images are quite working. Requires further research. - Added creation of ALU with mode 0 - addition. Such an element is not generated by Yosys, but it is a favorite vendor element and its support here greatly simplifies the compilation of vendor netlists. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/CMakeLists.txt | 2 +- himbaechel/uarch/gowin/constids.inc | 9 + himbaechel/uarch/gowin/gowin.h | 6 +- himbaechel/uarch/gowin/gowin_arch_gen.py | 2 +- himbaechel/uarch/gowin/gowin_utils.h | 3 + himbaechel/uarch/gowin/pack.cc | 203 +++++++++++++++++++++-- 6 files changed, 205 insertions(+), 20 deletions(-) diff --git a/himbaechel/uarch/gowin/CMakeLists.txt b/himbaechel/uarch/gowin/CMakeLists.txt index 99eba633..c45628be 100644 --- a/himbaechel/uarch/gowin/CMakeLists.txt +++ b/himbaechel/uarch/gowin/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5) project(himbaechel-gowin-chipdb NONE) find_package(Python3 3.5 REQUIRED COMPONENTS Interpreter) -set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1NS-2 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C) +set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C) set(HIMBAECHEL_GOWIN_DEVICES "" CACHE STRING "Include support for these Gowin devices (available: ${ALL_HIMBAECHEL_GOWIN_DEVICES})") if(HIMBAECHEL_GOWIN_DEVICES STREQUAL "all") diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index df333f71..178e625b 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -685,6 +685,7 @@ X(IOBIS) X(IOBJS) // long wires +X(LONGWIRE) X(BUFS) X(BUFS0) X(BUFS1) @@ -888,9 +889,17 @@ X(WRE) // BSRAM X(BSRAM_SUBTYPE) X(BIT_WIDTH) +X(BIT_WIDTH_0) +X(BIT_WIDTH_1) X(ROM) +X(DP) +X(DPB) +X(DPX9B) X(SP) X(SPX9) +X(SDP) +X(SDPB) +X(SDPX9B) X(pROM) X(pROMX9) X(BSRAM) diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 842bf34d..3e8a3ec6 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -40,7 +40,11 @@ inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1 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 type_is_bsram(IdString cell_type) +{ + return cell_type.in(id_SP, id_SPX9, id_pROM, id_pROMX9, id_ROM, id_SDP, id_SDPB, id_SDPX9B, id_DP, id_DPB, + id_DPX9B); +} inline bool is_bsram(const CellInfo *cell) { return type_is_bsram(cell->type); } // ========================================== diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index f5373644..533928b3 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -728,7 +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'] + bsram_tiletypes = db.tile_types.get('B', set()) # Setup tile grid for x in range(X): diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index b88e9b7a..3dbb7010 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -35,6 +35,9 @@ struct GowinUtils bool have_bottom_io_cnds(void); IdString get_bottom_io_wire_a_net(int8_t condition); IdString get_bottom_io_wire_b_net(int8_t condition); + + // wires + inline bool is_wire_type_default(IdString wire_type) { return wire_type == IdString(); } }; NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 78799401..b3080793 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1023,6 +1023,8 @@ struct GowinPacker return cin_ci; } // CIN from logic + cin_ci->addInput(id_I0); + cin_ci->connectPort(id_I0, ctx->nets.at(ctx->id("$PACKER_GND")).get()); cin_ci->addInput(id_I1); cin_ci->addInput(id_I3); cin_ci->connectPort(id_I1, cin_net); @@ -1113,6 +1115,12 @@ struct GowinPacker ci->constr_x = alu_chain_len / 6; ci->constr_y = 0; ci->constr_z = alu_chain_len % 6; + // XXX mode 0 - ADD + if (ci->params[id_ALU_MODE].as_int64() == 0) { + ci->renamePort(id_I3, id_I2); + ci->renamePort(id_I0, id_I3); + ci->renamePort(id_I2, id_I0); + } // XXX I2 is pin C which must be set to 1 for all ALU modes except MUL // we use only mode 2 ADDSUB so create and connect this pin ci->addInput(id_I2); @@ -1184,7 +1192,7 @@ struct GowinPacker {id_DFFP, id_D}, {id_DFFPE, id_D}, {id_DFFNP, id_D}, {id_DFFNPE, id_D}, {id_DFFC, id_D}, {id_DFFCE, id_D}, {id_DFFNC, id_D}, {id_DFFNCE, id_D}}; - int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 1); + int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 0); log_info("Constrained %d LUTFF pairs.\n", lutffs); } @@ -1275,9 +1283,20 @@ struct GowinPacker // =================================== // Block RAM // =================================== + void bsram_rename_ports(CellInfo *ci, int bit_width, char const *from, char const *to, int offset = 0) + { + int num = (bit_width == 9 || bit_width == 18 || bit_width == 36) ? 36 : 32; + for (int i = 0, j = offset; i < num; ++i, ++j) { + if (((i + 1) % 9) == 0 && (bit_width == 16 || bit_width == 32)) { + ++j; + } + ci->renamePort(ctx->idf(from, i), ctx->idf(to, offset ? j % 36 : j)); + } + } + void pack_ROM(CellInfo *ci) { - // use block 111 + // XXX use block 111 ci->setParam(ctx->id("BLK_SEL"), Property(7, 32)); if (ci->type == id_pROM) { ci->setAttr(id_BSRAM_SUBTYPE, Property("")); @@ -1295,11 +1314,7 @@ struct GowinPacker 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); @@ -1308,20 +1323,158 @@ struct GowinPacker 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) { + ci->copyPortTo(id_CLK, ci, id_CLKB); + ci->copyPortTo(id_CE, ci, id_CEB); + ci->copyPortTo(id_OCE, ci, id_OCEB); + ci->copyPortTo(id_RESET, ci, id_RESETB); + + for (int i = 0; i < 14; ++i) { + ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADA%d", i)); + ci->copyPortTo(ctx->idf("ADA%d", i), ci, ctx->idf("ADB%d", i)); + } + bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d"); + } else { + // 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_CEA); + ci->connectPort(id_CEA, vss_net); + for (int i = 0; i < 14; ++i) { + ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADB%d", i)); + } + bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d", 18); + } + } + + void pack_SDPB(CellInfo *ci) + { + if (ci->type == id_SDPB) { + 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 < 14; ++i) { + ci->renamePort(ctx->idf("ADA[%d]", i), ctx->idf("ADA%d", i)); + ci->renamePort(ctx->idf("ADB[%d]", i), ctx->idf("ADB%d", i)); + } + + for (int i = 0; i < 3; ++i) { + ci->renamePort(ctx->idf("BLKSELA[%d]", i), ctx->idf("BLKSELA%d", i)); + ci->renamePort(ctx->idf("BLKSELB[%d]", i), ctx->idf("BLKSELB%d", i)); + } + + ci->copyPortTo(id_OCE, ci, id_OCEB); + + // Port A + ci->addInput(id_WRE); + ci->connectPort(id_WRE, vcc_net); + + if (!ci->params.count(id_BIT_WIDTH_0)) { + ci->setParam(id_BIT_WIDTH_0, Property(32, 32)); + } + + int bit_width = ci->params[id_BIT_WIDTH_0].as_int64(); + bsram_rename_ports(ci, bit_width, "DI[%d]", "DI%d"); + + // Port B + ci->addInput(id_WREB); + if (!ci->params.count(id_BIT_WIDTH_1)) { + ci->setParam(id_BIT_WIDTH_1, Property(32, 32)); + } + bit_width = ci->params[id_BIT_WIDTH_1].as_int64(); + if (bit_width == 32 || bit_width == 36) { + ci->connectPort(id_WREB, vcc_net); + bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d"); + } else { + ci->connectPort(id_WREB, vss_net); + bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d", 18); + } + } + + void pack_DPB(CellInfo *ci) + { + if (ci->type == id_DPB) { + ci->setAttr(id_BSRAM_SUBTYPE, Property("")); + } else { + ci->setAttr(id_BSRAM_SUBTYPE, Property("X9")); + } + + for (int i = 0; i < 14; ++i) { + ci->renamePort(ctx->idf("ADA[%d]", i), ctx->idf("ADA%d", i)); + ci->renamePort(ctx->idf("ADB[%d]", i), ctx->idf("ADB%d", i)); + } + + for (int i = 0; i < 3; ++i) { + ci->renamePort(ctx->idf("BLKSELA[%d]", i), ctx->idf("BLKSELA%d", i)); + ci->renamePort(ctx->idf("BLKSELB[%d]", i), ctx->idf("BLKSELB%d", i)); + } + + if (!ci->params.count(id_BIT_WIDTH_0)) { + ci->setParam(id_BIT_WIDTH_0, Property(16, 32)); + } + int bit_width = ci->params[id_BIT_WIDTH_0].as_int64(); if (bit_width == 32 || bit_width == 36) { log_error("Bit width %d is not supported\n", bit_width); } + bsram_rename_ports(ci, bit_width, "DIA[%d]", "DIA%d"); + bsram_rename_ports(ci, bit_width, "DOA[%d]", "DOA%d"); + + if (!ci->params.count(id_BIT_WIDTH_1)) { + ci->setParam(id_BIT_WIDTH_1, Property(16, 32)); + } + bit_width = ci->params[id_BIT_WIDTH_1].as_int64(); + if (bit_width == 32 || bit_width == 36) { + log_error("Bit width %d is not supported\n", bit_width); + } + bsram_rename_ports(ci, bit_width, "DIB[%d]", "DIB%d"); + bsram_rename_ports(ci, bit_width, "DOB[%d]", "DOB%d"); + } + + void pack_SP(CellInfo *ci) + { + if (ci->type == id_SP) { + 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(); + for (int i = 0; i < 3; ++i) { + ci->renamePort(ctx->idf("BLKSEL[%d]", i), ctx->idf("BLKSEL%d", i)); + ci->copyPortTo(ctx->idf("BLKSEL%d", i), ci, ctx->idf("BLKSELB%d", i)); + } + + 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(); 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("AD[%d]", i), ctx->idf("AD%d", i)); + if (bit_width == 32 || bit_width == 36) { + ci->copyPortTo(ctx->idf("AD%d", i), ci, ctx->idf("ADB%d", i)); } - ci->renamePort(ctx->idf("DO[%d]", i), ctx->idf("DO%d", j % 36)); } + if (bit_width == 32 || bit_width == 36) { + ci->copyPortTo(id_CLK, ci, id_CLKB); + ci->copyPortTo(id_OCE, ci, id_OCEB); + ci->copyPortTo(id_CE, ci, id_CEB); + ci->copyPortTo(id_RESET, ci, id_RESETB); + ci->copyPortTo(id_WRE, ci, id_WREB); + ci->disconnectPort(ctx->id("ADB4")); + ci->connectPort(ctx->id("ADB4"), vcc_net); + } + bsram_rename_ports(ci, bit_width, "DI[%d]", "DI%d"); + bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d"); } void pack_bsram(void) @@ -1336,11 +1489,26 @@ struct GowinPacker log_info(" pack %s\n", ci->type.c_str(ctx)); } switch (ci->type.hash()) { - case ID_pROM: /* fallthrough */ - case ID_pROMX9: + case ID_pROMX9: /* fallthrough */ + case ID_pROM: pack_ROM(ci); ci->type = id_ROM; break; + case ID_SDPX9B: /* fallthrough */ + case ID_SDPB: + pack_SDPB(ci); + ci->type = id_SDP; + break; + case ID_DPX9B: /* fallthrough */ + case ID_DPB: + pack_DPB(ci); + ci->type = id_DP; + break; + case ID_SPX9: /* fallthrough */ + case ID_SP: + pack_SP(ci); + ci->type = id_SP; + break; default: log_error("Unsupported BSRAM type '%s'\n", ci->type.c_str(ctx)); } @@ -1463,7 +1631,8 @@ struct GowinPacker pack_alus(); ctx->check(); - constrain_lutffs(); + // XXX Leads to the impossibility of placement on lower models. + // constrain_lutffs(); ctx->check(); pack_pll();