Skip to content

Commit

Permalink
Gowin. Fix pipeline mode in BSRAM.
Browse files Browse the repository at this point in the history
It seems that the internal registers on the BSRAM output pins in
READ_MODE=1'b1 (pipeline) mode do not function properly because in the
images generated by Gowin IDE an external register is added to each pin,
and the BSRAM itself switches to READ_MODE=1'b0 (bypass) mode .

This is observed on Tangnano9k and Tangnano20k boards.

Here we repeat this fix.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit authored and gatecat committed Jun 25, 2024
1 parent 8f87918 commit 2e8280a
Show file tree
Hide file tree
Showing 6 changed files with 89 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 @@ -892,6 +892,7 @@ X(WRE)
X(BSRAM_SUBTYPE)
X(WRITE_MODE)
X(READ_MODE)
X(RESET_MODE)
X(BIT_WIDTH)
X(BIT_WIDTH_0)
X(BIT_WIDTH_1)
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 @@ -97,6 +97,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
// chip flags
static constexpr int32_t HAS_SP32 = 1;
static constexpr int32_t NEED_SP_FIX = 2;
static constexpr int32_t NEED_BSRAM_OUTREG_FIX = 4;
});

} // 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,8 +15,9 @@
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

# Z of the bels
# sync with C++ part!
Expand Down Expand Up @@ -1018,6 +1019,8 @@ def main():
chip_flags |= CHIP_HAS_SP32;
if "NEED_SP_FIX" in db.chip_flags:
chip_flags |= CHIP_NEED_SP_FIX;
if "NEED_BSRAM_OUTREG_FIX" in db.chip_flags:
chip_flags |= CHIP_NEED_BSRAM_OUTREG_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 @@ -124,6 +124,12 @@ bool GowinUtils::need_SP_fix(void)
return extra->chip_flags & Extra_chip_data_POD::NEED_SP_FIX;
}

bool GowinUtils::need_BSRAM_OUTREG_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_BSRAM_OUTREG_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 @@ -37,6 +37,7 @@ struct GowinUtils
// BSRAM
bool have_SP32(void);
bool need_SP_fix(void);
bool need_BSRAM_OUTREG_fix(void);

// DSP
inline int get_dsp_18_z(int z) const { return z & (~3); }
Expand Down
75 changes: 75 additions & 0 deletions himbaechel/uarch/gowin/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,73 @@ struct GowinPacker
}
}

// 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.
// We work around this by adding an external DFF and using BSRAM
// as READ_MODE=1'b0 (bypass).
void bsram_fix_outreg(CellInfo *ci, std::vector<std::unique_ptr<CellInfo>> &new_cells)
{
int bit_width = ci->params.at(id_BIT_WIDTH).as_int64();
if (bit_width == 32 || bit_width == 36) {
return;
}
int read_mode = ci->params.at(id_READ_MODE).as_int64();
if (read_mode == 0) {
return;
}
NetInfo *ce_net = ci->getPort(id_CE);
NetInfo *oce_net = ci->getPort(id_OCE);
if (ce_net == nullptr || oce_net == nullptr) {
return;
}
if (ce_net->name == ctx->id("$PACKER_GND") || oce_net->name == ctx->id("$PACKER_GND")) {
return;
}

if (ctx->verbose) {
log_info(" apply the BSRAM OUTREG fix\n");
}
ci->setParam(id_READ_MODE, 0);
ci->disconnectPort(id_OCE);
ci->connectPort(id_OCE, ce_net);

NetInfo *reset_net = ci->getPort(id_RESET);
bool sync_reset = ci->params.at(id_RESET_MODE).as_string() == std::string("SYNC");
IdString dff_type = sync_reset ? id_DFFRE : id_DFFCE;
IdString reset_port = sync_reset ? id_RESET : id_CLEAR;

for (int i = 0; i < bit_width; ++i) {
IdString do_name = ctx->idf("DO[%d]", i);
const NetInfo *net = ci->getPort(do_name);
if (net != nullptr) {
if (net->users.empty()) {
ci->disconnectPort(do_name);
continue;
}

// create DFF
auto cache_dff_cell = gwu.create_cell(create_aux_name(ci->name, i, "_cache_dff$"), dff_type);
CellInfo *cache_dff = cache_dff_cell.get();
cache_dff->addInput(id_CE);
cache_dff->connectPort(id_CE, oce_net);

cache_dff->addInput(reset_port);
cache_dff->connectPort(reset_port, reset_net);

ci->copyPortTo(id_CLK, cache_dff, id_CLK);

cache_dff->addOutput(id_Q);
ci->movePortTo(do_name, cache_dff, id_Q);

cache_dff->addInput(id_D);
ci->connectPorts(do_name, cache_dff, id_D);

new_cells.push_back(std::move(cache_dff_cell));
}
}
}

// Analysis of the images generated by the IDE showed that some components
// are being added at the input and output of the BSRAM. Two LUTs are
// added on the WRE and CE inputs (strangely, OCE is not affected), a pair
Expand All @@ -1342,6 +1409,9 @@ struct GowinPacker
{
int bit_width = ci->params.at(id_BIT_WIDTH).as_int64();

if (ctx->verbose) {
log_info(" apply the SP fix\n");
}
// create WRE LUT
auto wre_lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_wre_lut$"), id_LUT4);
CellInfo *wre_lut = wre_lut_cell.get();
Expand Down Expand Up @@ -1654,6 +1724,11 @@ struct GowinPacker
bsram_fix_sp(ci, new_cells);
}

// Some chips have faulty output registers
if (gwu.need_BSRAM_OUTREG_fix()) {
bsram_fix_outreg(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 2e8280a

Please sign in to comment.