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