Skip to content

Commit

Permalink
Gowin. Fix BSRAM block selection.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
yrabbit committed Jun 27, 2024
1 parent 2e8280a commit 69df7f7
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 2 deletions.
1 change: 1 addition & 0 deletions himbaechel/uarch/gowin/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ X(DID)
X(WRE)

// BSRAM
X(BLK_SEL)
X(BSRAM_SUBTYPE)
X(WRITE_MODE)
X(READ_MODE)
Expand Down
1 change: 1 addition & 0 deletions himbaechel/uarch/gowin/gowin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions himbaechel/uarch/gowin/gowin_arch_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions himbaechel/uarch/gowin/gowin_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::NEED_BLKSEL_FIX;
}

std::unique_ptr<CellInfo> GowinUtils::create_cell(IdString name, IdString type)
{
NPNR_ASSERT(!ctx->cells.count(name));
Expand Down
1 change: 1 addition & 0 deletions himbaechel/uarch/gowin/gowin_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
69 changes: 69 additions & 0 deletions himbaechel/uarch/gowin/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::unique_ptr<CellInfo>> &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<std::pair<IdString, int>> 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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 69df7f7

Please sign in to comment.