From cbf99d5e5390d8439722e0172067b687be5ac060 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 19 Oct 2020 13:31:21 +0100 Subject: nexus: LUTRAM support Signed-off-by: David Shah --- common/design_utils.cc | 7 +++ nexus/arch_place.cc | 10 +++++ nexus/constids.inc | 5 ++- nexus/fasm.cc | 13 ++++++ nexus/pack.cc | 119 +++++++++++++++++++++++++++++++++++++++++++++++-- nexus/pins.cc | 8 +++- 6 files changed, 157 insertions(+), 5 deletions(-) diff --git a/common/design_utils.cc b/common/design_utils.cc index dd866758..9478afb2 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -30,6 +30,13 @@ void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdS if (!old_cell->ports.count(old_name)) return; PortInfo &old = old_cell->ports.at(old_name); + + // Create port on the replacement cell if it doesn't already exist + if (!rep_cell->ports.count(rep_name)) { + rep_cell->ports[rep_name].name = rep_name; + rep_cell->ports[rep_name].type = old.type; + } + PortInfo &rep = rep_cell->ports.at(rep_name); NPNR_ASSERT(old.type == rep.type); diff --git a/nexus/arch_place.cc b/nexus/arch_place.cc index 7e50de29..feec75ad 100644 --- a/nexus/arch_place.cc +++ b/nexus/arch_place.cc @@ -33,6 +33,16 @@ bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const CellInfo *lut1 = lts.cells[(s << 3) | BEL_LUT1]; CellInfo *ff0 = lts.cells[(s << 3) | BEL_FF0]; CellInfo *ff1 = lts.cells[(s << 3) | BEL_FF1]; + + if (s == 2) { + CellInfo *ramw = lts.cells[(s << 3) | BEL_RAMW]; + // Nothing else in SLICEC can be used if the RAMW is used + if (ramw != nullptr) { + if (lut0 != nullptr || lut1 != nullptr || ff0 != nullptr || ff1 != nullptr) + return false; + } + } + if (lut0 != nullptr) { // Check for overuse of M signal if (lut0->lutInfo.mux2_used && ff0 != nullptr && ff0->ffInfo.m != nullptr) diff --git a/nexus/constids.inc b/nexus/constids.inc index c89c1ec8..625931f2 100644 --- a/nexus/constids.inc +++ b/nexus/constids.inc @@ -23,7 +23,7 @@ X(WAD0) X(WAD1) X(WAD2) X(WAD3) -X(WD) +X(WDI) X(WCK) X(WRE) @@ -167,3 +167,6 @@ X(ACC54_CORE) X(DCC) X(CLKI) X(CLKO) + +X(DPR16X4) +X(INITVAL) diff --git a/nexus/fasm.cc b/nexus/fasm.cc index 66747461..031cd9b3 100644 --- a/nexus/fasm.cc +++ b/nexus/fasm.cc @@ -298,6 +298,17 @@ struct NexusFasmWriter pop(2); } + // Write out config for an OXIDE_RAMW cell + void write_ramw(const CellInfo *cell) + { + BelId bel = cell->bel; + push_tile(bel.tile, id_PLC); + push("SLICEC"); + write_bit("MODE.RAMW"); + write_cell_muxes(cell); + pop(2); + } + std::unordered_set used_io; // Write config for an SEIO33_CORE cell @@ -442,6 +453,8 @@ struct NexusFasmWriter write_comb(ci); else if (ci->type == id_OXIDE_FF) write_ff(ci); + else if (ci->type == id_RAMW) + write_ramw(ci); else if (ci->type == id_SEIO33_CORE) write_io33(ci); else if (ci->type == id_SEIO18_CORE) diff --git a/nexus/pack.cc b/nexus/pack.cc index 33e0a11f..7dbef99b 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -878,11 +878,124 @@ struct NexusPacker } } + // Get a bus port name + IdString bus(const std::string &base, int i) { return ctx->id(stringf("%s[%d]", base.c_str(), i)); } + + IdString bus_flat(const std::string &base, int i) { return ctx->id(stringf("%s%d", base.c_str(), i)); } + + // Pack a LUTRAM into COMB and RAMW cells + void pack_lutram() + { + // Do this so we don't have an iterate-and-modfiy situation + std::vector lutrams; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type != id_DPR16X4) + continue; + lutrams.push_back(ci); + } + + // Port permutation vectors + IdString ramw_wdo[4] = {id_D1, id_C1, id_A1, id_B1}; + IdString ramw_wado[4] = {id_D0, id_B0, id_C0, id_A0}; + IdString comb0_rad[4] = {id_D, id_B, id_C, id_A}; + IdString comb1_rad[4] = {id_C, id_B, id_D, id_A}; + + for (CellInfo *ci : lutrams) { + // Create constituent cells + CellInfo *ramw = ctx->createCell(ctx->id(stringf("%s$lutram_ramw$", ctx->nameOf(ci))), id_RAMW); + std::vector combs; + for (int i = 0; i < 4; i++) + combs.push_back( + ctx->createCell(ctx->id(stringf("%s$lutram_comb[%d]$", ctx->nameOf(ci), i)), id_OXIDE_COMB)); + // Rewiring - external WCK and WRE + replace_port(ci, id_WCK, ramw, id_CLK); + replace_port(ci, id_WRE, ramw, id_LSR); + + // Internal WCK and WRE signals + ramw->addOutput(id_WCKO); + ramw->addOutput(id_WREO); + NetInfo *int_wck = ctx->createNet(ctx->id(stringf("%s$lutram_wck$", ctx->nameOf(ci)))); + NetInfo *int_wre = ctx->createNet(ctx->id(stringf("%s$lutram_wre$", ctx->nameOf(ci)))); + connect_port(ctx, int_wck, ramw, id_WCKO); + connect_port(ctx, int_wre, ramw, id_WREO); + + uint64_t initval = ctx->parse_lattice_param(ci, id_INITVAL, 64, 0).as_int64(); + + // Rewiring - buses + for (int i = 0; i < 4; i++) { + // Write address - external + replace_port(ci, bus("WAD", i), ramw, ramw_wado[i]); + // Write data - external + replace_port(ci, bus("DI", i), ramw, ramw_wdo[i]); + // Read data + replace_port(ci, bus("DO", i), combs[i], id_F); + // Read address + NetInfo *rad = get_net_or_empty(ci, bus("RAD", i)); + if (rad != nullptr) { + for (int j = 0; j < 4; j++) { + IdString port = (j % 2) ? comb1_rad[i] : comb0_rad[i]; + combs[j]->addInput(port); + connect_port(ctx, rad, combs[j], port); + } + disconnect_port(ctx, ci, bus("RAD", i)); + } + // Write address - internal + NetInfo *int_wad = ctx->createNet(ctx->id(stringf("%s$lutram_wad[%d]$", ctx->nameOf(ci), i))); + ramw->addOutput(bus_flat("WADO", i)); + connect_port(ctx, int_wad, ramw, bus_flat("WADO", i)); + for (int j = 0; j < 4; j++) { + combs[j]->addInput(bus_flat("WAD", i)); + connect_port(ctx, int_wad, combs[j], bus_flat("WAD", i)); + } + // Write data - internal + NetInfo *int_wd = ctx->createNet(ctx->id(stringf("%s$lutram_wd[%d]$", ctx->nameOf(ci), i))); + ramw->addOutput(bus_flat("WDO", i)); + connect_port(ctx, int_wd, ramw, bus_flat("WDO", i)); + combs[i]->addInput(id_WDI); + connect_port(ctx, int_wd, combs[i], id_WDI); + // Write clock and enable - internal + combs[i]->addInput(id_WCK); + combs[i]->addInput(id_WRE); + connect_port(ctx, int_wck, combs[i], id_WCK); + connect_port(ctx, int_wre, combs[i], id_WRE); + // Remap init val + uint64_t split_init = 0; + for (int j = 0; j < 16; j++) + if (initval & (1ULL << (4 * j + i))) + split_init |= (1 << j); + combs[i]->params[id_INIT] = Property(split_init, 16); + } + + // Setup relative constraints + combs[0]->constr_z = 0; + combs[0]->constr_abs_z = true; + for (int i = 1; i < 4; i++) { + combs[i]->constr_x = 0; + combs[i]->constr_y = 0; + combs[i]->constr_z = ((i / 2) << 3) | (i % 2); + combs[i]->constr_abs_z = true; + combs[i]->constr_parent = combs[0]; + combs[0]->constr_children.push_back(combs[i]); + } + + ramw->constr_x = 0; + ramw->constr_y = 0; + ramw->constr_z = (2 << 3) | Arch::BEL_RAMW; + ramw->constr_abs_z = true; + ramw->constr_parent = combs[0]; + combs[0]->constr_children.push_back(ramw); + // Remove now-packed cell + ctx->cells.erase(ci->name); + } + } + explicit NexusPacker(Context *ctx) : ctx(ctx) {} void operator()() { pack_io(); + pack_lutram(); pack_ffs(); pack_constants(); pack_luts(); @@ -929,13 +1042,13 @@ void Arch::assignCellInfo(CellInfo *cell) cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR); cell->ffInfo.di = get_net_or_empty(cell, id_DI); cell->ffInfo.m = get_net_or_empty(cell, id_M); - } else if (cell->type == ID_RAMW) { - cell->ffInfo.ctrlset.async = false; + } else if (cell->type == id_RAMW) { + cell->ffInfo.ctrlset.async = true; cell->ffInfo.ctrlset.regddr_en = false; cell->ffInfo.ctrlset.gsr_en = false; cell->ffInfo.ctrlset.clkmux = id(str_or_default(cell->params, id_CLKMUX, "CLK")).index; cell->ffInfo.ctrlset.cemux = ID_CE; - cell->ffInfo.ctrlset.lsrmux = id(str_or_default(cell->params, id_LSRMUX, "LSR")).index; + cell->ffInfo.ctrlset.lsrmux = ID_INV; cell->ffInfo.ctrlset.clk = get_net_or_empty(cell, id_CLK); cell->ffInfo.ctrlset.ce = nullptr; cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR); diff --git a/nexus/pins.cc b/nexus/pins.cc index f9ddd5f5..1fa62b28 100644 --- a/nexus/pins.cc +++ b/nexus/pins.cc @@ -31,11 +31,12 @@ static const std::unordered_map base_cell_pin_data {id_WRE, PINSTYLE_DEDI}, {id_FCI, PINSTYLE_DEDI}, + {id_F1, PINSTYLE_DEDI}, {id_WAD0, PINSTYLE_DEDI}, {id_WAD1, PINSTYLE_DEDI}, {id_WAD2, PINSTYLE_DEDI}, {id_WAD3, PINSTYLE_DEDI}, - {id_WD, PINSTYLE_DEDI}, + {id_WDI, PINSTYLE_DEDI}, {{}, PINSTYLE_PU}, }}, @@ -46,6 +47,11 @@ static const std::unordered_map base_cell_pin_data {id_CE, PINSTYLE_CE}, {{}, PINSTYLE_DEDI}, }}, + {id_RAMW, + { + {id_CLK, PINSTYLE_CLK}, + {{}, PINSTYLE_DEDI}, + }}, {id_SEIO18_CORE, { {id_T, PINSTYLE_T}, -- cgit v1.2.3