WIP shadowram
This commit is contained in:
parent
997af6d720
commit
490dddf636
@ -791,6 +791,39 @@ void Arch::read_cst(std::istream &in)
|
|||||||
settings[id_cst] = 1;
|
settings[id_cst] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arch::addShadowRamBels(const DatabasePOD *db, int row, int col)
|
||||||
|
{
|
||||||
|
IdString belname, bel_id;
|
||||||
|
char buf[32];
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add all MUXes for the cell
|
// Add all MUXes for the cell
|
||||||
void Arch::addMuxBels(const DatabasePOD *db, int row, int col)
|
void Arch::addMuxBels(const DatabasePOD *db, int row, int col)
|
||||||
{
|
{
|
||||||
@ -1112,6 +1145,9 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
if (z == 0) {
|
if (z == 0) {
|
||||||
addMuxBels(db, row, col);
|
addMuxBels(db, row, col);
|
||||||
}
|
}
|
||||||
|
if (z == 4) {
|
||||||
|
addShadowRamBels(db, row, col);
|
||||||
|
}
|
||||||
if (z % 2 == 0) {
|
if (z % 2 == 0) {
|
||||||
snprintf(buf, 32, "R%dC%d_LUT_GRP%d", row + 1, col + 1, z);
|
snprintf(buf, 32, "R%dC%d_LUT_GRP%d", row + 1, col + 1, z);
|
||||||
grpname = id(buf);
|
grpname = id(buf);
|
||||||
|
@ -344,6 +344,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
DelayQuad getWireTypeDelay(IdString wire);
|
DelayQuad getWireTypeDelay(IdString wire);
|
||||||
void read_cst(std::istream &in);
|
void read_cst(std::istream &in);
|
||||||
void addMuxBels(const DatabasePOD *db, int row, int col);
|
void addMuxBels(const DatabasePOD *db, int row, int col);
|
||||||
|
void addShadowRamBels(const DatabasePOD *db, int row, int col);
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// Common Arch API. Every arch must provide the following methods.
|
// Common Arch API. Every arch must provide the following methods.
|
||||||
@ -485,6 +486,7 @@ enum
|
|||||||
{
|
{
|
||||||
mux_0_z = 10, // start Z for the MUX2LUT5 bels
|
mux_0_z = 10, // start Z for the MUX2LUT5 bels
|
||||||
iologic_0_z = 20, // start Z for the IOLOGIC 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
|
vcc_0_z = 277, // virtual VCC bel Z
|
||||||
gnd_0_z = 278, // virtual VSS bel Z
|
gnd_0_z = 278, // virtual VSS bel Z
|
||||||
osc_z = 280 // Z for the oscillator bels
|
osc_z = 280 // Z for the oscillator bels
|
||||||
|
@ -166,4 +166,37 @@ 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, "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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -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_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
|
// 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
|
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||||
// can be reconnected
|
// 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
|
// Convert a Gowin IO buffer to a IOB bel
|
||||||
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -748,6 +748,19 @@ X(DFFNPE)
|
|||||||
X(DFFNC)
|
X(DFFNC)
|
||||||
X(DFFNCE)
|
X(DFFNCE)
|
||||||
|
|
||||||
|
// Shadow RAM
|
||||||
|
X(RAMW)
|
||||||
|
X(RAM16SDP4)
|
||||||
|
X(WADA)
|
||||||
|
X(WADB)
|
||||||
|
X(WADC)
|
||||||
|
X(WADD)
|
||||||
|
X(DIA)
|
||||||
|
X(DIB)
|
||||||
|
X(DIC)
|
||||||
|
X(DID)
|
||||||
|
X(WRE)
|
||||||
|
|
||||||
// IOB types
|
// IOB types
|
||||||
X(IBUF)
|
X(IBUF)
|
||||||
X(OBUF)
|
X(OBUF)
|
||||||
|
@ -692,6 +692,89 @@ static void pack_gsr(Context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pack shadow RAM
|
||||||
|
void pack_sram(Context *ctx)
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
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));
|
||||||
|
ramw_block[i]->params[id_FF_TYPE] = std::string("RAMW_BLOCK");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = 4;
|
||||||
|
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)
|
static bool is_nextpnr_iob(const Context *ctx, CellInfo *cell)
|
||||||
{
|
{
|
||||||
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
|
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
|
||||||
|
Loading…
Reference in New Issue
Block a user