aboutsummaryrefslogtreecommitdiffstats
path: root/gowin
diff options
context:
space:
mode:
authorYRabbit <rabbit@yrabbit.cyou>2022-07-05 19:43:24 +1000
committerYRabbit <rabbit@yrabbit.cyou>2022-07-05 19:43:24 +1000
commit3364a3b6746c6df62a36e1dd319afaa97259d6ad (patch)
treefe7e96804ecee6f46ffef4522a1a3bba290fd86a /gowin
parent5d915a550ba8a825fa29a2cab3851adea20f40fb (diff)
parent86396c41d64d2583ec1dffca4298e83d927f0762 (diff)
downloadnextpnr-3364a3b6746c6df62a36e1dd319afaa97259d6ad.tar.gz
nextpnr-3364a3b6746c6df62a36e1dd319afaa97259d6ad.tar.bz2
nextpnr-3364a3b6746c6df62a36e1dd319afaa97259d6ad.zip
Merge branch 'master' into clock-wip
Diffstat (limited to 'gowin')
-rw-r--r--gowin/arch.cc30
-rw-r--r--gowin/arch.h1
-rw-r--r--gowin/cells.cc44
-rw-r--r--gowin/cells.h8
-rw-r--r--gowin/constids.inc14
-rw-r--r--gowin/pack.cc90
6 files changed, 187 insertions, 0 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index cdb932a6..82b44f91 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -1307,6 +1307,36 @@ Arch::Arch(ArchArgs args) : args(args)
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
addBelInput(belname, id_OSCEN, id(buf));
break;
+ case ID_RAM16:
+ snprintf(buf, 32, "R%dC%d_RAMW", row + 1, col + 1);
+ belname = id(buf);
+ addBel(belname, id_RAMW, Loc(col, row, BelZ::lutram_0_z), false);
+
+ snprintf(buf, 32, "R%dC%d_A%d", row + 1, col + 1, 4);
+ addBelInput(belname, id_A4, id(buf));
+ snprintf(buf, 32, "R%dC%d_B%d", row + 1, col + 1, 4);
+ addBelInput(belname, id_B4, id(buf));
+ snprintf(buf, 32, "R%dC%d_C%d", row + 1, col + 1, 4);
+ addBelInput(belname, id_C4, id(buf));
+ snprintf(buf, 32, "R%dC%d_D%d", row + 1, col + 1, 4);
+ addBelInput(belname, id_D4, id(buf));
+
+ snprintf(buf, 32, "R%dC%d_A%d", row + 1, col + 1, 5);
+ addBelInput(belname, id_A5, id(buf));
+ snprintf(buf, 32, "R%dC%d_B%d", row + 1, col + 1, 5);
+ addBelInput(belname, id_B5, id(buf));
+ snprintf(buf, 32, "R%dC%d_C%d", row + 1, col + 1, 5);
+ addBelInput(belname, id_C5, id(buf));
+ snprintf(buf, 32, "R%dC%d_D%d", row + 1, col + 1, 5);
+ addBelInput(belname, id_D5, id(buf));
+
+ snprintf(buf, 32, "R%dC%d_CLK%d", row + 1, col + 1, 2);
+ addBelInput(belname, id_CLK, id(buf));
+ snprintf(buf, 32, "R%dC%d_LSR%d", row + 1, col + 1, 2);
+ addBelInput(belname, id_LSR, id(buf));
+ snprintf(buf, 32, "R%dC%d_CE%d", row + 1, col + 1, 2);
+ addBelInput(belname, id_CE, id(buf));
+ break;
// fall through the ++
case ID_LUT7:
z++;
diff --git a/gowin/arch.h b/gowin/arch.h
index cd43aa7a..d02a2488 100644
--- a/gowin/arch.h
+++ b/gowin/arch.h
@@ -506,6 +506,7 @@ enum
{
mux_0_z = 10, // start Z for the MUX2LUT5 bels
iologic_0_z = 20, // start Z for the IOLOGIC bels
+ lutram_0_z = 30, // start Z for the IOLOGIC bels
vcc_0_z = 277, // virtual VCC bel Z
gnd_0_z = 278, // virtual VSS bel Z
osc_z = 280, // Z for the oscillator bels
diff --git a/gowin/cells.cc b/gowin/cells.cc
index 6010164a..d83b07c8 100644
--- a/gowin/cells.cc
+++ b/gowin/cells.cc
@@ -48,6 +48,14 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::
new_cell->addOutput(id_Q);
new_cell->addInput(id_CE);
new_cell->addInput(id_LSR);
+ } else if (type == id_RAMW) {
+ IdString names[8] = {id_A4, id_B4, id_C4, id_D4, id_A5, id_B5, id_C5, id_D5};
+ for (int i = 0; i < 8; i++) {
+ new_cell->addInput(names[i]);
+ }
+ new_cell->addInput(id_CLK);
+ new_cell->addInput(id_CE);
+ new_cell->addInput(id_LSR);
} else if (type == id_GW_MUX2_LUT5 || type == id_GW_MUX2_LUT6 || type == id_GW_MUX2_LUT7 ||
type == id_GW_MUX2_LUT7 || type == id_GW_MUX2_LUT8) {
new_cell->addInput(id_I0);
@@ -169,4 +177,40 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &to
}
}
+void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw)
+{
+ if (ramw->hierpath == IdString())
+ ramw->hierpath = ramw->hierpath;
+ ram->movePortTo(ctx->id("WAD[0]"), ramw, id_A4);
+ ram->movePortTo(ctx->id("WAD[1]"), ramw, id_B4);
+ ram->movePortTo(ctx->id("WAD[2]"), ramw, id_C4);
+ ram->movePortTo(ctx->id("WAD[3]"), ramw, id_D4);
+
+ ram->movePortTo(ctx->id("DI[0]"), ramw, id_A5);
+ ram->movePortTo(ctx->id("DI[1]"), ramw, id_B5);
+ ram->movePortTo(ctx->id("DI[2]"), ramw, id_C5);
+ ram->movePortTo(ctx->id("DI[3]"), ramw, id_D5);
+
+ ram->movePortTo(ctx->id("CLK"), ramw, id_CLK);
+ ram->movePortTo(ctx->id("WRE"), ramw, id_LSR);
+}
+
+void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index)
+{
+ char buf1[32];
+ if (slice->hierpath == IdString())
+ slice->hierpath = slice->hierpath;
+
+ snprintf(buf1, 32, "INIT_%d", index);
+ slice->params[id_INIT] = ram->params[ctx->id(buf1)];
+
+ snprintf(buf1, 32, "DO[%d]", index);
+ ram->movePortTo(ctx->id(buf1), slice, id_F);
+
+ ram->copyPortTo(ctx->id("RAD[0]"), slice, id_A);
+ ram->copyPortTo(ctx->id("RAD[1]"), slice, id_B);
+ ram->copyPortTo(ctx->id("RAD[2]"), slice, id_C);
+ ram->copyPortTo(ctx->id("RAD[3]"), slice, id_D);
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/gowin/cells.h b/gowin/cells.h
index 8f0636b8..b6d86497 100644
--- a/gowin/cells.h
+++ b/gowin/cells.h
@@ -111,6 +111,8 @@ inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell)
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_SLICE; }
+inline bool is_sram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_RAM16SDP4; }
+
// Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports
// as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected
@@ -125,6 +127,12 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
// Convert a Gowin IO buffer to a IOB bel
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
+// Convert RAM16 to write port
+void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw);
+
+// Convert RAM16 to slice
+void sram_to_slice(Context *ctx, CellInfo *ram, CellInfo *slice, int index);
+
NEXTPNR_NAMESPACE_END
#endif
diff --git a/gowin/constids.inc b/gowin/constids.inc
index 99c791f8..8916f093 100644
--- a/gowin/constids.inc
+++ b/gowin/constids.inc
@@ -823,6 +823,20 @@ X(DFFNPE)
X(DFFNC)
X(DFFNCE)
+// Shadow RAM
+X(RAM16)
+X(RAMW)
+X(RAM16SDP4)
+X(WADA)
+X(WADB)
+X(WADC)
+X(WADD)
+X(DIA)
+X(DIB)
+X(DIC)
+X(DID)
+X(WRE)
+
// IOB types
X(IBUF)
X(OBUF)
diff --git a/gowin/pack.cc b/gowin/pack.cc
index 5b304f10..dbf949d4 100644
--- a/gowin/pack.cc
+++ b/gowin/pack.cc
@@ -694,6 +694,95 @@ static void pack_gsr(Context *ctx)
}
}
+// Pack shadow RAM
+void pack_sram(Context *ctx)
+{
+ log_info("Packing Shadow RAM..\n");
+
+ pool<IdString> packed_cells;
+ std::vector<std::unique_ptr<CellInfo>> new_cells;
+
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ if (is_sram(ctx, ci)) {
+
+ // Create RAMW slice
+ std::unique_ptr<CellInfo> ramw_slice =
+ create_generic_cell(ctx, id_RAMW, ci->name.str(ctx) + "$RAMW_SLICE");
+ sram_to_ramw_split(ctx, ci, ramw_slice.get());
+ ramw_slice->connectPort(id_CE, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
+
+ // Create actual RAM slices
+ std::unique_ptr<CellInfo> ram_comb[4];
+ for (int i = 0; i < 4; i++) {
+ ram_comb[i] = create_generic_cell(ctx, id_SLICE,
+ ci->name.str(ctx) + "$SRAM_SLICE" + std::to_string(i));
+ ram_comb[i]->params[id_FF_USED] = 1;
+ ram_comb[i]->params[id_FF_TYPE] = std::string("RAM");
+ sram_to_slice(ctx, ci, ram_comb[i].get(), i);
+ }
+ // Create 'block' SLICEs as a placement hint that these cells are mutually exclusive with the RAMW
+ std::unique_ptr<CellInfo> ramw_block[2];
+ for (int i = 0; i < 2; i++) {
+ ramw_block[i] = create_generic_cell(ctx, id_SLICE,
+ ci->name.str(ctx) + "$RAMW_BLOCK" + std::to_string(i));
+ ram_comb[i]->params[id_FF_USED] = 1;
+ ramw_block[i]->params[id_FF_TYPE] = std::string("RAM");
+ }
+
+ // Disconnect ports of original cell after packing
+ // ci->disconnectPort(id_WCK);
+ // ci->disconnectPort(id_WRE);
+
+ for (int i = 0; i < 4; i++)
+ ci->disconnectPort(ctx->id(stringf("RAD[%d]", i)));
+
+ // Setup placement constraints
+ // Use the 0th bit as an anchor
+ ram_comb[0]->constr_abs_z = true;
+ ram_comb[0]->constr_z = 0;
+ ram_comb[0]->cluster = ram_comb[0]->name;
+ for (int i = 1; i < 4; i++) {
+ ram_comb[i]->cluster = ram_comb[0]->name;
+ ram_comb[i]->constr_abs_z = true;
+ ram_comb[i]->constr_x = 0;
+ ram_comb[i]->constr_y = 0;
+ ram_comb[i]->constr_z = i;
+ ram_comb[0]->constr_children.push_back(ram_comb[i].get());
+ }
+ for (int i = 0; i < 2; i++) {
+ ramw_block[i]->cluster = ram_comb[0]->name;
+ ramw_block[i]->constr_abs_z = true;
+ ramw_block[i]->constr_x = 0;
+ ramw_block[i]->constr_y = 0;
+ ramw_block[i]->constr_z = i + 4;
+ ram_comb[0]->constr_children.push_back(ramw_block[i].get());
+ }
+
+ ramw_slice->cluster = ram_comb[0]->name;
+ ramw_slice->constr_abs_z = true;
+ ramw_slice->constr_x = 0;
+ ramw_slice->constr_y = 0;
+ ramw_slice->constr_z = BelZ::lutram_0_z;
+ ram_comb[0]->constr_children.push_back(ramw_slice.get());
+
+ for (int i = 0; i < 4; i++)
+ new_cells.push_back(std::move(ram_comb[i]));
+ for (int i = 0; i < 2; i++)
+ new_cells.push_back(std::move(ramw_block[i]));
+ new_cells.push_back(std::move(ramw_slice));
+ packed_cells.insert(ci->name);
+ }
+ }
+ for (auto pcell : packed_cells) {
+ ctx->cells.erase(pcell);
+ }
+ for (auto &ncell : new_cells) {
+ ctx->cells[ncell->name] = std::move(ncell);
+ }
+}
+
+
static bool is_nextpnr_iob(const Context *ctx, CellInfo *cell)
{
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
@@ -1013,6 +1102,7 @@ bool Arch::pack()
log_break();
pre_pack(ctx);
pack_constants(ctx);
+ pack_sram(ctx);
pack_gsr(ctx);
pack_io(ctx);
pack_diff_io(ctx);