diff --git a/common/design_utils.cc b/common/design_utils.cc index 7ad7f749..e3051d20 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -76,6 +76,8 @@ void print_utilisation(const Context *ctx) // Connect a net to a port void connect_port(const Context *ctx, NetInfo *net, CellInfo *cell, IdString port_name) { + if (net == nullptr) + return; PortInfo &port = cell->ports.at(port_name); NPNR_ASSERT(port.net == nullptr); port.net = net; diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 7e101ab2..048db1d7 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -238,4 +238,49 @@ void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) replace_port(ccu, ctx->id("COUT"), lc, ctx->id("FCO")); } +void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc) +{ + lc->params[ctx->id("MODE")] = "RAMW"; + replace_port(ram, ctx->id("WAD[0]"), lc, ctx->id("D0")); + replace_port(ram, ctx->id("WAD[1]"), lc, ctx->id("B0")); + replace_port(ram, ctx->id("WAD[2]"), lc, ctx->id("C0")); + replace_port(ram, ctx->id("WAD[3]"), lc, ctx->id("A0")); + + replace_port(ram, ctx->id("DI[0]"), lc, ctx->id("C1")); + replace_port(ram, ctx->id("DI[1]"), lc, ctx->id("A1")); + replace_port(ram, ctx->id("DI[2]"), lc, ctx->id("D1")); + replace_port(ram, ctx->id("DI[3]"), lc, ctx->id("B1")); +} + +void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw, int index) +{ + lc->params[ctx->id("MODE")] = "DPRAM"; + lc->params[ctx->id("WREMUX")] = str_or_default(ram->params, ctx->id("WREMUX"), "WRE"); + lc->params[ctx->id("WCKMUX")] = str_or_default(ram->params, ctx->id("WCKMUX"), "WCK"); + + // TODO: INIT + + if (ram->ports.count(ctx->id("RAD[0]"))) { + connect_port(ctx, ram->ports.at(ctx->id("RAD[0]")).net, lc, ctx->id("D0")); + connect_port(ctx, ram->ports.at(ctx->id("RAD[0]")).net, lc, ctx->id("D1")); + } + if (ram->ports.count(ctx->id("RAD[1]"))) { + connect_port(ctx, ram->ports.at(ctx->id("RAD[1]")).net, lc, ctx->id("B0")); + connect_port(ctx, ram->ports.at(ctx->id("RAD[1]")).net, lc, ctx->id("B1")); + } + if (ram->ports.count(ctx->id("RAD[2]"))) { + connect_port(ctx, ram->ports.at(ctx->id("RAD[2]")).net, lc, ctx->id("C0")); + connect_port(ctx, ram->ports.at(ctx->id("RAD[2]")).net, lc, ctx->id("C1")); + } + if (ram->ports.count(ctx->id("RAD[3]"))) { + connect_port(ctx, ram->ports.at(ctx->id("RAD[3]")).net, lc, ctx->id("A0")); + connect_port(ctx, ram->ports.at(ctx->id("RAD[3]")).net, lc, ctx->id("A1")); + } + + if (ram->ports.count(ctx->id("WRE"))) + connect_port(ctx, ram->ports.at(ctx->id("WRE")).net, lc, ctx->id("WRE")); + if (ram->ports.count(ctx->id("WCK"))) + connect_port(ctx, ram->ports.at(ctx->id("WCK")).net, lc, ctx->id("WCK")); +} + NEXTPNR_NAMESPACE_END diff --git a/ecp5/cells.h b/ecp5/cells.h index d2ea5490..c68d1dd3 100644 --- a/ecp5/cells.h +++ b/ecp5/cells.h @@ -49,6 +49,8 @@ inline bool is_l6mux(const BaseCtx *ctx, const CellInfo *cell) { return cell->ty void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut); void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index); void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc); +void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc); +void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, int index); NEXTPNR_NAMESPACE_END diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 14b387d5..2c7ce020 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -555,6 +555,23 @@ class Ecp5Packer flush_cells(); } + // Pack distributed RAM + void pack_dram() + { + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_dpram(ctx, ci)) { + std::unique_ptr ramw_slice = + create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "$RAMW_SLICE"); + dram_to_ramw(ctx, ci, ramw_slice.get()); + + new_cells.push_back(std::move(ramw_slice)); + packed_cells.insert(ci->name); + } + } + flush_cells(); + } + // Pack LUTs that have been paired together void pack_lut_pairs() {