From 1871afe9b9970af8adc410b2715746c0bdeade50 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 4 Jul 2024 19:10:07 +1000 Subject: [PATCH 1/2] Gowin. Taking into account the features of ROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For pROM(X9) primitives in images generated by Gowin IDE, there is an interesting recommunication of inputs depending on the data bit depth. For example, in some cases, a high logical level may be applied to the Write Enable input, which, let’s say, is not entirely usual for Read Only memory. Here we will do similar manipulations. In addition, several minor bug fixes are included: - Fixed bit numbering for non-X9 series primitives. - Fixed decoder generation for BLKSEL - do not assume unused inputs are connected to GND. - Use default values for BSRAM parameters - don't assume their mandatory presence. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/pack.cc | 56 +++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 7fedad6e..bc8f70fd 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1,6 +1,7 @@ #include "design_utils.h" #include "log.h" #include "nextpnr.h" +#include "util.h" #define HIMBAECHEL_CONSTIDS "uarch/gowin/constids.inc" #include "himbaechel_constids.h" @@ -1324,7 +1325,7 @@ struct GowinPacker { 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)) { + if (((j + 1) % 9) == 0 && (bit_width == 16 || bit_width == 32)) { ++j; } ci->renamePort(ctx->idf(from, i), ctx->idf(to, offset ? j % 36 : j)); @@ -1390,6 +1391,15 @@ struct GowinPacker } ++idx; } + switch (idx) { + case 1: + init |= init << 2; /* fallthrough */ + case 2: + init |= init << 4; + break; + default: + break; + } lut->setParam(id_INIT, init); new_cells.push_back(std::move(lut_cell)); @@ -1406,7 +1416,7 @@ struct GowinPacker if (bit_width == 32 || bit_width == 36) { return; } - int read_mode = ci->params.at(id_READ_MODE).as_int64(); + int read_mode = int_or_default(ci->params, id_READ_MODE, 0); if (read_mode == 0) { return; } @@ -1511,7 +1521,7 @@ struct GowinPacker CellInfo *new_ce_net_src = ce_pre_dff; // add delay register in pipeline mode - int read_mode = ci->params.at(id_READ_MODE).as_int64(); + int read_mode = int_or_default(ci->params, id_READ_MODE, 0); if (read_mode) { auto ce_pipe_dff_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_ce_pipe_dff$"), id_DFF); new_cells.push_back(std::move(ce_pipe_dff_cell)); @@ -1587,10 +1597,7 @@ struct GowinPacker ci->connectPort(port, vcc_net); } - ci->addInput(id_WRE); - ci->connectPort(id_WRE, vss_net); ci->addInput(id_WREB); - ci->connectPort(id_WREB, vss_net); if (!ci->params.count(id_BIT_WIDTH)) { ci->setParam(id_BIT_WIDTH, Property(default_bw, 32)); @@ -1602,10 +1609,19 @@ struct GowinPacker ci->copyPortTo(id_CE, ci, id_CEB); ci->copyPortTo(id_OCE, ci, id_OCEB); ci->copyPortTo(id_RESET, ci, id_RESETB); + ci->connectPort(id_WREB, vcc_net); - 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)); + // disconnect lower address bits for ROM + static int rom_ignore_bits[] = {2, 4, 8, 16, 32}; + static int romx9_ignore_bits[] = {9, 9, 9, 18, 36}; + for (unsigned int i = 0; i < 14; ++i) { + if (i < sizeof(rom_ignore_bits) && ((ci->type == id_pROM && bit_width >= rom_ignore_bits[i]) || + (ci->type == id_pROMX9 && bit_width >= romx9_ignore_bits[i]))) { + ci->disconnectPort(ctx->idf("AD[%d]", i)); + } else { + 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 { @@ -1614,9 +1630,18 @@ struct GowinPacker ci->renamePort(id_OCE, id_OCEB); ci->renamePort(id_CE, id_CEB); ci->renamePort(id_RESET, id_RESETB); + ci->connectPort(id_WREB, vss_net); - ci->addInput(id_CEA); - ci->connectPort(id_CEA, vss_net); + ci->addInput(id_CE); + ci->connectPort(id_CE, vcc_net); + ci->disconnectPort(id_OCEB); + + int read_mode = int_or_default(ci->params, id_READ_MODE, 0); + if (read_mode) { + ci->connectPort(id_OCEB, vcc_net); + } else { + ci->copyPortTo(id_CEB, ci, id_OCEB); + } for (int i = 0; i < 14; ++i) { ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADB%d", i)); } @@ -1798,6 +1823,15 @@ struct GowinPacker bsram_fix_blksel(ci, new_cells); } + // XXX + NetInfo *oce_net = ci->getPort(id_OCE); + if (oce_net == nullptr || oce_net->name == ctx->id("$PACKER_VCC") || oce_net->name == ctx->id("$PACKER_GND")) { + if (oce_net != nullptr) { + ci->disconnectPort(id_OCE); + ci->copyPortTo(id_CE, ci, id_OCE); + } + } + // 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. From eb099a9244857219ee33d627540dc5e2316893ae Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 9 Jul 2024 09:42:35 +1000 Subject: [PATCH 2/2] Gowin. Bugfix. The statement in the Gowin documentation that in the reading mode "READ_MODE=0" the output register is not used and the OCE signal is ignored is not confirmed by practice - if the OCE was left unconnected or connected to the constant network, then a change in output data was observed even with CE=0, as well as the absence of such at CE=1. Synchronizing CE and OCE helps and the memory works properly in complex systems such as RISC-V emulation and i8080 emulation (with 32K RAM and 16K BSRAM based ROM), but there is no theoretical basis for this fix, so it is a hack. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/pack.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index bc8f70fd..2faf1df0 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -1612,11 +1612,11 @@ struct GowinPacker ci->connectPort(id_WREB, vcc_net); // disconnect lower address bits for ROM - static int rom_ignore_bits[] = {2, 4, 8, 16, 32}; - static int romx9_ignore_bits[] = {9, 9, 9, 18, 36}; + std::array rom_ignore_bits = {2, 4, 8, 16, 32}; + std::array romx9_ignore_bits = {9, 9, 9, 18, 36}; for (unsigned int i = 0; i < 14; ++i) { - if (i < sizeof(rom_ignore_bits) && ((ci->type == id_pROM && bit_width >= rom_ignore_bits[i]) || - (ci->type == id_pROMX9 && bit_width >= romx9_ignore_bits[i]))) { + if (i < size(rom_ignore_bits) && ((ci->type == id_pROM && bit_width >= rom_ignore_bits[i]) || + (ci->type == id_pROMX9 && bit_width >= romx9_ignore_bits[i]))) { ci->disconnectPort(ctx->idf("AD[%d]", i)); } else { ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADA%d", i)); @@ -1823,13 +1823,19 @@ struct GowinPacker bsram_fix_blksel(ci, new_cells); } - // XXX + // The statement in the Gowin documentation that in the reading mode + // "READ_MODE=0" the output register is not used and the OCE signal is + // ignored is not confirmed by practice - if the OCE was left + // unconnected or connected to the constant network, then a change in + // output data was observed even with CE=0, as well as the absence of + // such at CE=1. + // Synchronizing CE and OCE helps but it's definitely a hack. NetInfo *oce_net = ci->getPort(id_OCE); if (oce_net == nullptr || oce_net->name == ctx->id("$PACKER_VCC") || oce_net->name == ctx->id("$PACKER_GND")) { if (oce_net != nullptr) { ci->disconnectPort(id_OCE); - ci->copyPortTo(id_CE, ci, id_OCE); } + ci->copyPortTo(id_CE, ci, id_OCE); } // XXX UG285-1.3.6_E Gowin BSRAM & SSRAM User Guide: