Gowin. Fix pipeline mode in BSRAM.
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 <rabbit@yrabbit.cyou>
This commit is contained in:
parent
8f87918230
commit
2e8280a949
@ -892,6 +892,7 @@ X(WRE)
|
|||||||
X(BSRAM_SUBTYPE)
|
X(BSRAM_SUBTYPE)
|
||||||
X(WRITE_MODE)
|
X(WRITE_MODE)
|
||||||
X(READ_MODE)
|
X(READ_MODE)
|
||||||
|
X(RESET_MODE)
|
||||||
X(BIT_WIDTH)
|
X(BIT_WIDTH)
|
||||||
X(BIT_WIDTH_0)
|
X(BIT_WIDTH_0)
|
||||||
X(BIT_WIDTH_1)
|
X(BIT_WIDTH_1)
|
||||||
|
@ -97,6 +97,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
|
|||||||
// chip flags
|
// chip flags
|
||||||
static constexpr int32_t HAS_SP32 = 1;
|
static constexpr int32_t HAS_SP32 = 1;
|
||||||
static constexpr int32_t NEED_SP_FIX = 2;
|
static constexpr int32_t NEED_SP_FIX = 2;
|
||||||
|
static constexpr int32_t NEED_BSRAM_OUTREG_FIX = 4;
|
||||||
});
|
});
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -15,8 +15,9 @@ from apycula import chipdb
|
|||||||
BEL_FLAG_SIMPLE_IO = 0x100
|
BEL_FLAG_SIMPLE_IO = 0x100
|
||||||
|
|
||||||
# Chip flags
|
# Chip flags
|
||||||
CHIP_HAS_SP32 = 0x1
|
CHIP_HAS_SP32 = 0x1
|
||||||
CHIP_NEED_SP_FIX = 0x2
|
CHIP_NEED_SP_FIX = 0x2
|
||||||
|
CHIP_NEED_BSRAM_OUTREG_FIX = 0x4
|
||||||
|
|
||||||
# Z of the bels
|
# Z of the bels
|
||||||
# sync with C++ part!
|
# sync with C++ part!
|
||||||
@ -1018,6 +1019,8 @@ def main():
|
|||||||
chip_flags |= CHIP_HAS_SP32;
|
chip_flags |= CHIP_HAS_SP32;
|
||||||
if "NEED_SP_FIX" in db.chip_flags:
|
if "NEED_SP_FIX" in db.chip_flags:
|
||||||
chip_flags |= CHIP_NEED_SP_FIX;
|
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;
|
X = db.cols;
|
||||||
Y = db.rows;
|
Y = db.rows;
|
||||||
|
@ -124,6 +124,12 @@ bool GowinUtils::need_SP_fix(void)
|
|||||||
return extra->chip_flags & Extra_chip_data_POD::NEED_SP_FIX;
|
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)
|
std::unique_ptr<CellInfo> GowinUtils::create_cell(IdString name, IdString type)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(!ctx->cells.count(name));
|
NPNR_ASSERT(!ctx->cells.count(name));
|
||||||
|
@ -37,6 +37,7 @@ struct GowinUtils
|
|||||||
// BSRAM
|
// BSRAM
|
||||||
bool have_SP32(void);
|
bool have_SP32(void);
|
||||||
bool need_SP_fix(void);
|
bool need_SP_fix(void);
|
||||||
|
bool need_BSRAM_OUTREG_fix(void);
|
||||||
|
|
||||||
// DSP
|
// DSP
|
||||||
inline int get_dsp_18_z(int z) const { return z & (~3); }
|
inline int get_dsp_18_z(int z) const { return z & (~3); }
|
||||||
|
@ -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
|
// 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
|
// 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
|
// added on the WRE and CE inputs (strangely, OCE is not affected), a pair
|
||||||
@ -1342,6 +1409,9 @@ struct GowinPacker
|
|||||||
{
|
{
|
||||||
int bit_width = ci->params.at(id_BIT_WIDTH).as_int64();
|
int bit_width = ci->params.at(id_BIT_WIDTH).as_int64();
|
||||||
|
|
||||||
|
if (ctx->verbose) {
|
||||||
|
log_info(" apply the SP fix\n");
|
||||||
|
}
|
||||||
// create WRE LUT
|
// create WRE LUT
|
||||||
auto wre_lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_wre_lut$"), id_LUT4);
|
auto wre_lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_wre_lut$"), id_LUT4);
|
||||||
CellInfo *wre_lut = wre_lut_cell.get();
|
CellInfo *wre_lut = wre_lut_cell.get();
|
||||||
@ -1654,6 +1724,11 @@ struct GowinPacker
|
|||||||
bsram_fix_sp(ci, new_cells);
|
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:
|
// 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
|
// For GW1N-9/GW1NR-9/GW1NS-4 series, 32/36-bit SP/SPX9 is divided into two
|
||||||
// SP/SPX9s, which occupy two BSRAMs.
|
// SP/SPX9s, which occupy two BSRAMs.
|
||||||
|
Loading…
Reference in New Issue
Block a user