From 69df7f76920d8523ec0107d50ada804148ee74be Mon Sep 17 00:00:00 2001 From: YRabbit Date: Fri, 28 Jun 2024 08:15:50 +1000 Subject: [PATCH] Gowin. Fix BSRAM block selection. In the images generated by Gowin IDE, the signals for dynamic BSRAM block selection (BLKSEL[2:0]) are not always connected directly to the ports - some chips add LUT2, LUT3 or LUT4 to turn these signals into Clock Enable. Apparently there are chips with an error in the operation of these ports. Here we make such a decoder instead of using ports directly. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/constids.inc | 1 + himbaechel/uarch/gowin/gowin.h | 1 + himbaechel/uarch/gowin/gowin_arch_gen.py | 7 ++- himbaechel/uarch/gowin/gowin_utils.cc | 6 +++ himbaechel/uarch/gowin/gowin_utils.h | 1 + himbaechel/uarch/gowin/pack.cc | 69 ++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 1add903340..032de7ac65 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -889,6 +889,7 @@ X(DID) X(WRE) // BSRAM +X(BLK_SEL) X(BSRAM_SUBTYPE) X(WRITE_MODE) X(READ_MODE) diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 728d6df21c..c815fe0a2c 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -98,6 +98,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { static constexpr int32_t HAS_SP32 = 1; static constexpr int32_t NEED_SP_FIX = 2; static constexpr int32_t NEED_BSRAM_OUTREG_FIX = 4; + static constexpr int32_t NEED_BLKSEL_FIX = 8; }); } // namespace diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 73a5ade1cb..cc19e3c09c 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -15,9 +15,10 @@ BEL_FLAG_SIMPLE_IO = 0x100 # Chip flags -CHIP_HAS_SP32 = 0x1 -CHIP_NEED_SP_FIX = 0x2 +CHIP_HAS_SP32 = 0x1 +CHIP_NEED_SP_FIX = 0x2 CHIP_NEED_BSRAM_OUTREG_FIX = 0x4 +CHIP_NEED_BLKSEL_FIX = 0x8 # Z of the bels # sync with C++ part! @@ -1021,6 +1022,8 @@ def main(): chip_flags |= CHIP_NEED_SP_FIX; if "NEED_BSRAM_OUTREG_FIX" in db.chip_flags: chip_flags |= CHIP_NEED_BSRAM_OUTREG_FIX; + if "NEED_BLKSEL_FIX" in db.chip_flags: + chip_flags |= CHIP_NEED_BLKSEL_FIX; X = db.cols; Y = db.rows; diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index ac6153af1f..603b6fc5b5 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -130,6 +130,12 @@ bool GowinUtils::need_BSRAM_OUTREG_fix(void) return extra->chip_flags & Extra_chip_data_POD::NEED_BSRAM_OUTREG_FIX; } +bool GowinUtils::need_BLKSEL_fix(void) +{ + const Extra_chip_data_POD *extra = reinterpret_cast(ctx->chip_info->extra_data.get()); + return extra->chip_flags & Extra_chip_data_POD::NEED_BLKSEL_FIX; +} + std::unique_ptr GowinUtils::create_cell(IdString name, IdString type) { NPNR_ASSERT(!ctx->cells.count(name)); diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index c4d3e628dd..65ae632e99 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -38,6 +38,7 @@ struct GowinUtils bool have_SP32(void); bool need_SP_fix(void); bool need_BSRAM_OUTREG_fix(void); + bool need_BLKSEL_fix(void); // DSP inline int get_dsp_18_z(int z) const { return z & (~3); } diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index ee1ce9f200..b0975b3a3f 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1331,6 +1331,70 @@ struct GowinPacker } } + // We solve the BLKSEL problems that are observed on some chips by + // connecting the BLKSEL ports to constant networks so that this BSRAM will + // be selected, the actual selection is made by manipulating the Clock + // Enable pin using a LUT-based decoder. + void bsram_fix_blksel(CellInfo *ci, std::vector> &new_cells) + { + // is BSRAM enabled + NetInfo *ce_net = ci->getPort(id_CE); + if (ce_net == nullptr || ce_net->name == ctx->id("$PACKER_GND")) { + return; + } + + // port name, BLK_SEL parameter for this port + std::vector> dyn_blksel; + + int blk_sel_parameter = ci->params.at(id_BLK_SEL).as_int64(); + for (int i = 0; i < 3; ++i) { + IdString pin_name = ctx->idf("BLKSEL[%d]", i); + NetInfo *net = ci->getPort(pin_name); + if (net == nullptr || net->name == ctx->id("$PACKER_GND") || net->name == ctx->id("$PACKER_VCC")) { + continue; + } + dyn_blksel.push_back(std::make_pair(pin_name, (blk_sel_parameter >> i) & 1)); + } + + if (dyn_blksel.empty()) { + return; + } + + if (ctx->verbose) { + log_info(" apply the BSRAM BLKSEL fix\n"); + } + + // Make a decoder + auto lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_blksel_lut$"), id_LUT4); + CellInfo *lut = lut_cell.get(); + lut->addInput(id_I3); + ci->movePortTo(id_CE, lut, id_I3); + lut->addOutput(id_F); + ci->connectPorts(id_CE, lut, id_F); + + NetInfo *vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC")).get(); + NetInfo *vss_net = ctx->nets.at(ctx->id("$PACKER_GND")).get(); + + // Connected CE to I3 to make it easy to calculate the decoder + int init = 0x100; // CE == 0 --> F = 0 + // CE == 1 --> F = decoder result + int idx = 0; + for (auto &port : dyn_blksel) { + IdString lut_input_name = ctx->idf("I%d", idx); + ci->movePortTo(port.first, lut, lut_input_name); + if (port.second) { + init <<= (1 << idx); + ci->connectPort(port.first, vcc_net); + } else { + ci->connectPort(port.first, vss_net); + } + ++idx; + } + lut->setParam(id_INIT, init); + + new_cells.push_back(std::move(lut_cell)); + } + // Some chips cannot, for some reason, use internal BSRAM registers to // implement READ_MODE=1'b1 (pipeline) with a word width other than 32 or // 36 bits. @@ -1729,6 +1793,11 @@ struct GowinPacker bsram_fix_outreg(ci, new_cells); } + // Some chips have problems with BLKSEL ports + if (gwu.need_BLKSEL_fix()) { + bsram_fix_blksel(ci, new_cells); + } + // XXX UG285-1.3.6_E Gowin BSRAM & SSRAM User Guide: // For GW1N-9/GW1NR-9/GW1NS-4 series, 32/36-bit SP/SPX9 is divided into two // SP/SPX9s, which occupy two BSRAMs.