gowin: Himbaechel. Add GW1NZ-1 BSRAM.

The following primitives are implemented for the GW1NZ-1 chip:

* pROM     - read only memory - (bitwidth: 1, 2, 4, 8, 16, 32).
* pROMX9   - read only memory - (bitwidth: 9, 18, 36).
* SDPB     - semidual port    - (bitwidth: 1, 2, 4, 8, 16, 32).
* SDPX9B   - semidual port    - (bitwidth: 9, 18, 36).
* DPB      - dual port        - (bitwidth: 16).
* DPX9B    - dual port        - (bitwidth: 18).
* SP       - single port      - (bitwidth: 1, 2, 4, 8, 16, 32).
* SPX9     - single port      - (bitwidth: 9, 18, 36).

Also:
 - The creation of databases for GW1NS-2 has been removed - this was not
   planned to be supported in Himbaechel from the very beginning and
   even examples were not created in apicula for this chip due to the
   lack of boards with it on sale.
 - It is temporarily prohibited to connect DFFs and LUTs into clusters
   because for some reason this prevents the creation of images on lower
   chips (placer cannot find the placement), although without these
   clusters the images are quite working. Requires further research.
 - Added creation of ALU with mode 0 - addition. Such an element is not
   generated by Yosys, but it is a favorite vendor element and its
   support here greatly simplifies the compilation of vendor netlists.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2023-11-20 12:27:56 +10:00 committed by myrtle
parent f2c280feda
commit 90d4863dd4
6 changed files with 205 additions and 20 deletions

View File

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5)
project(himbaechel-gowin-chipdb NONE)
find_package(Python3 3.5 REQUIRED COMPONENTS Interpreter)
set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1NS-2 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C)
set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C)
set(HIMBAECHEL_GOWIN_DEVICES "" CACHE STRING
"Include support for these Gowin devices (available: ${ALL_HIMBAECHEL_GOWIN_DEVICES})")
if(HIMBAECHEL_GOWIN_DEVICES STREQUAL "all")

View File

@ -685,6 +685,7 @@ X(IOBIS)
X(IOBJS)
// long wires
X(LONGWIRE)
X(BUFS)
X(BUFS0)
X(BUFS1)
@ -888,9 +889,17 @@ X(WRE)
// BSRAM
X(BSRAM_SUBTYPE)
X(BIT_WIDTH)
X(BIT_WIDTH_0)
X(BIT_WIDTH_1)
X(ROM)
X(DP)
X(DPB)
X(DPX9B)
X(SP)
X(SPX9)
X(SDP)
X(SDPB)
X(SDPX9B)
X(pROM)
X(pROMX9)
X(BSRAM)

View File

@ -40,7 +40,11 @@ inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1
inline bool is_ssram(const CellInfo *cell) { return type_is_ssram(cell->type); }
// Return true if a cell is a SSRAM
inline bool type_is_bsram(IdString cell_type) { return cell_type.in(id_SP, id_SPX9, id_pROM, id_pROMX9, id_ROM); }
inline bool type_is_bsram(IdString cell_type)
{
return cell_type.in(id_SP, id_SPX9, id_pROM, id_pROMX9, id_ROM, id_SDP, id_SDPB, id_SDPX9B, id_DP, id_DPB,
id_DPX9B);
}
inline bool is_bsram(const CellInfo *cell) { return type_is_bsram(cell->type); }
// ==========================================

View File

@ -728,7 +728,7 @@ def main():
io_tiletypes = db.tile_types['I']
ssram_tiletypes = db.tile_types['M']
pll_tiletypes = db.tile_types['P']
bsram_tiletypes = db.tile_types['B']
bsram_tiletypes = db.tile_types.get('B', set())
# Setup tile grid
for x in range(X):

View File

@ -35,6 +35,9 @@ struct GowinUtils
bool have_bottom_io_cnds(void);
IdString get_bottom_io_wire_a_net(int8_t condition);
IdString get_bottom_io_wire_b_net(int8_t condition);
// wires
inline bool is_wire_type_default(IdString wire_type) { return wire_type == IdString(); }
};
NEXTPNR_NAMESPACE_END

View File

@ -1023,6 +1023,8 @@ struct GowinPacker
return cin_ci;
}
// CIN from logic
cin_ci->addInput(id_I0);
cin_ci->connectPort(id_I0, ctx->nets.at(ctx->id("$PACKER_GND")).get());
cin_ci->addInput(id_I1);
cin_ci->addInput(id_I3);
cin_ci->connectPort(id_I1, cin_net);
@ -1113,6 +1115,12 @@ struct GowinPacker
ci->constr_x = alu_chain_len / 6;
ci->constr_y = 0;
ci->constr_z = alu_chain_len % 6;
// XXX mode 0 - ADD
if (ci->params[id_ALU_MODE].as_int64() == 0) {
ci->renamePort(id_I3, id_I2);
ci->renamePort(id_I0, id_I3);
ci->renamePort(id_I2, id_I0);
}
// XXX I2 is pin C which must be set to 1 for all ALU modes except MUL
// we use only mode 2 ADDSUB so create and connect this pin
ci->addInput(id_I2);
@ -1184,7 +1192,7 @@ struct GowinPacker
{id_DFFP, id_D}, {id_DFFPE, id_D}, {id_DFFNP, id_D}, {id_DFFNPE, id_D},
{id_DFFC, id_D}, {id_DFFCE, id_D}, {id_DFFNC, id_D}, {id_DFFNCE, id_D}};
int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 1);
int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 0);
log_info("Constrained %d LUTFF pairs.\n", lutffs);
}
@ -1275,9 +1283,20 @@ struct GowinPacker
// ===================================
// Block RAM
// ===================================
void bsram_rename_ports(CellInfo *ci, int bit_width, char const *from, char const *to, int offset = 0)
{
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)) {
++j;
}
ci->renamePort(ctx->idf(from, i), ctx->idf(to, offset ? j % 36 : j));
}
}
void pack_ROM(CellInfo *ci)
{
// use block 111
// XXX use block 111
ci->setParam(ctx->id("BLK_SEL"), Property(7, 32));
if (ci->type == id_pROM) {
ci->setAttr(id_BSRAM_SUBTYPE, Property(""));
@ -1295,11 +1314,7 @@ struct GowinPacker
ci->addInput(port);
ci->connectPort(port, vcc_net);
}
// use port B
ci->renamePort(id_CLK, id_CLKB);
ci->renamePort(id_OCE, id_OCEB);
ci->renamePort(id_CE, id_CEB);
ci->renamePort(id_RESET, id_RESETB);
ci->addInput(id_WRE);
ci->connectPort(id_WRE, vss_net);
ci->addInput(id_WREB);
@ -1308,20 +1323,158 @@ struct GowinPacker
if (!ci->params.count(id_BIT_WIDTH)) {
ci->setParam(id_BIT_WIDTH, Property(32, 32));
}
int bit_width = ci->params[id_BIT_WIDTH].as_int64();
if (bit_width == 32 || bit_width == 36) {
ci->copyPortTo(id_CLK, ci, id_CLKB);
ci->copyPortTo(id_CE, ci, id_CEB);
ci->copyPortTo(id_OCE, ci, id_OCEB);
ci->copyPortTo(id_RESET, ci, id_RESETB);
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));
}
bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d");
} else {
// use port B
ci->renamePort(id_CLK, id_CLKB);
ci->renamePort(id_OCE, id_OCEB);
ci->renamePort(id_CE, id_CEB);
ci->renamePort(id_RESET, id_RESETB);
ci->addInput(id_CEA);
ci->connectPort(id_CEA, vss_net);
for (int i = 0; i < 14; ++i) {
ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADB%d", i));
}
bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d", 18);
}
}
void pack_SDPB(CellInfo *ci)
{
if (ci->type == id_SDPB) {
ci->setAttr(id_BSRAM_SUBTYPE, Property(""));
} else {
ci->setAttr(id_BSRAM_SUBTYPE, Property("X9"));
}
NetInfo *vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC")).get();
NetInfo *vss_net = ctx->nets.at(ctx->id("$PACKER_GND")).get();
for (int i = 0; i < 14; ++i) {
ci->renamePort(ctx->idf("ADA[%d]", i), ctx->idf("ADA%d", i));
ci->renamePort(ctx->idf("ADB[%d]", i), ctx->idf("ADB%d", i));
}
for (int i = 0; i < 3; ++i) {
ci->renamePort(ctx->idf("BLKSELA[%d]", i), ctx->idf("BLKSELA%d", i));
ci->renamePort(ctx->idf("BLKSELB[%d]", i), ctx->idf("BLKSELB%d", i));
}
ci->copyPortTo(id_OCE, ci, id_OCEB);
// Port A
ci->addInput(id_WRE);
ci->connectPort(id_WRE, vcc_net);
if (!ci->params.count(id_BIT_WIDTH_0)) {
ci->setParam(id_BIT_WIDTH_0, Property(32, 32));
}
int bit_width = ci->params[id_BIT_WIDTH_0].as_int64();
bsram_rename_ports(ci, bit_width, "DI[%d]", "DI%d");
// Port B
ci->addInput(id_WREB);
if (!ci->params.count(id_BIT_WIDTH_1)) {
ci->setParam(id_BIT_WIDTH_1, Property(32, 32));
}
bit_width = ci->params[id_BIT_WIDTH_1].as_int64();
if (bit_width == 32 || bit_width == 36) {
ci->connectPort(id_WREB, vcc_net);
bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d");
} else {
ci->connectPort(id_WREB, vss_net);
bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d", 18);
}
}
void pack_DPB(CellInfo *ci)
{
if (ci->type == id_DPB) {
ci->setAttr(id_BSRAM_SUBTYPE, Property(""));
} else {
ci->setAttr(id_BSRAM_SUBTYPE, Property("X9"));
}
for (int i = 0; i < 14; ++i) {
ci->renamePort(ctx->idf("ADA[%d]", i), ctx->idf("ADA%d", i));
ci->renamePort(ctx->idf("ADB[%d]", i), ctx->idf("ADB%d", i));
}
for (int i = 0; i < 3; ++i) {
ci->renamePort(ctx->idf("BLKSELA[%d]", i), ctx->idf("BLKSELA%d", i));
ci->renamePort(ctx->idf("BLKSELB[%d]", i), ctx->idf("BLKSELB%d", i));
}
if (!ci->params.count(id_BIT_WIDTH_0)) {
ci->setParam(id_BIT_WIDTH_0, Property(16, 32));
}
int bit_width = ci->params[id_BIT_WIDTH_0].as_int64();
if (bit_width == 32 || bit_width == 36) {
log_error("Bit width %d is not supported\n", bit_width);
}
bsram_rename_ports(ci, bit_width, "DIA[%d]", "DIA%d");
bsram_rename_ports(ci, bit_width, "DOA[%d]", "DOA%d");
if (!ci->params.count(id_BIT_WIDTH_1)) {
ci->setParam(id_BIT_WIDTH_1, Property(16, 32));
}
bit_width = ci->params[id_BIT_WIDTH_1].as_int64();
if (bit_width == 32 || bit_width == 36) {
log_error("Bit width %d is not supported\n", bit_width);
}
bsram_rename_ports(ci, bit_width, "DIB[%d]", "DIB%d");
bsram_rename_ports(ci, bit_width, "DOB[%d]", "DOB%d");
}
void pack_SP(CellInfo *ci)
{
if (ci->type == id_SP) {
ci->setAttr(id_BSRAM_SUBTYPE, Property(""));
} else {
ci->setAttr(id_BSRAM_SUBTYPE, Property("X9"));
}
NetInfo *vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC")).get();
for (int i = 0; i < 3; ++i) {
ci->renamePort(ctx->idf("BLKSEL[%d]", i), ctx->idf("BLKSEL%d", i));
ci->copyPortTo(ctx->idf("BLKSEL%d", i), ci, ctx->idf("BLKSELB%d", i));
}
if (!ci->params.count(id_BIT_WIDTH)) {
ci->setParam(id_BIT_WIDTH, Property(32, 32));
}
int bit_width = ci->params[id_BIT_WIDTH].as_int64();
for (int i = 0; i < 14; ++i) {
ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("ADB%d", i));
}
int out_num = (bit_width == 9 || bit_width == 18) ? 36 : 32;
for (int i = 0, j = 18; i < out_num; ++i, ++j) {
if (((i + 1) % 9) == 0 && bit_width == 16) {
++j;
ci->renamePort(ctx->idf("AD[%d]", i), ctx->idf("AD%d", i));
if (bit_width == 32 || bit_width == 36) {
ci->copyPortTo(ctx->idf("AD%d", i), ci, ctx->idf("ADB%d", i));
}
ci->renamePort(ctx->idf("DO[%d]", i), ctx->idf("DO%d", j % 36));
}
if (bit_width == 32 || bit_width == 36) {
ci->copyPortTo(id_CLK, ci, id_CLKB);
ci->copyPortTo(id_OCE, ci, id_OCEB);
ci->copyPortTo(id_CE, ci, id_CEB);
ci->copyPortTo(id_RESET, ci, id_RESETB);
ci->copyPortTo(id_WRE, ci, id_WREB);
ci->disconnectPort(ctx->id("ADB4"));
ci->connectPort(ctx->id("ADB4"), vcc_net);
}
bsram_rename_ports(ci, bit_width, "DI[%d]", "DI%d");
bsram_rename_ports(ci, bit_width, "DO[%d]", "DO%d");
}
void pack_bsram(void)
@ -1336,11 +1489,26 @@ struct GowinPacker
log_info(" pack %s\n", ci->type.c_str(ctx));
}
switch (ci->type.hash()) {
case ID_pROM: /* fallthrough */
case ID_pROMX9:
case ID_pROMX9: /* fallthrough */
case ID_pROM:
pack_ROM(ci);
ci->type = id_ROM;
break;
case ID_SDPX9B: /* fallthrough */
case ID_SDPB:
pack_SDPB(ci);
ci->type = id_SDP;
break;
case ID_DPX9B: /* fallthrough */
case ID_DPB:
pack_DPB(ci);
ci->type = id_DP;
break;
case ID_SPX9: /* fallthrough */
case ID_SP:
pack_SP(ci);
ci->type = id_SP;
break;
default:
log_error("Unsupported BSRAM type '%s'\n", ci->type.c_str(ctx));
}
@ -1463,7 +1631,8 @@ struct GowinPacker
pack_alus();
ctx->check();
constrain_lutffs();
// XXX Leads to the impossibility of placement on lower models.
// constrain_lutffs();
ctx->check();
pack_pll();