Merge pull request #995 from pepijndevos/shadowram

Gowin: WIP shadowram
This commit is contained in:
myrtle 2022-07-05 09:29:04 +02:00 committed by GitHub
commit 86396c41d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 187 additions and 0 deletions

View File

@ -1274,6 +1274,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++;

View File

@ -491,6 +491,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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -692,6 +692,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") ||
@ -1010,6 +1099,7 @@ bool Arch::pack()
try {
log_break();
pack_constants(ctx);
pack_sram(ctx);
pack_gsr(ctx);
pack_io(ctx);
pack_diff_io(ctx);