memory: declare blackbox ports for generated RAM cells

This commit is contained in:
Emil J. Tywoniak
2026-09-18 17:29:46 +02:00
parent b24fcf8566
commit df2ea7d788
2 changed files with 69 additions and 23 deletions
+44 -21
View File
@@ -130,6 +130,29 @@ struct MemConfig {
typedef std::vector<MemConfig> MemConfigs;
static void set_ram_port(RTLIL::Cell *cell, const std::string &port_name,
const RTLIL::SigSpec &sig, bool is_output = false)
{
RTLIL::Design *design = cell->module->design;
RTLIL::IdString port(port_name);
static const IdString generated = RTLIL::escape_id("memory_libmap_blackbox");
RTLIL::Module *mod = design->module(cell->type);
if (mod == nullptr) {
mod = design->addModule(cell->type);
mod->set_bool_attribute(ID::blackbox);
mod->set_bool_attribute(generated);
}
if (mod->get_bool_attribute(generated) && mod->wire(port) == nullptr) {
RTLIL::Wire *wire = mod->addWire(port, GetSize(sig));
(is_output ? wire->port_output : wire->port_input) = true;
mod->fixup_ports();
}
cell->setPort(port, sig);
}
struct MapWorker {
Module *module;
ModWalker modwalker;
@@ -1755,9 +1778,9 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
cell->setParam(stringf("\\PORT_%s_CLK_POL", name), clk_pol);
}
for (auto cell: cells) {
cell->setPort(stringf("\\PORT_%s_CLK", name), clk);
set_ram_port(cell, stringf("\\PORT_%s_CLK", name), clk);
if (pdef.clk_en)
cell->setPort(stringf("\\PORT_%s_CLK_EN", name), clk_en);
set_ram_port(cell, stringf("\\PORT_%s_CLK_EN", name), clk_en);
}
}
@@ -1819,7 +1842,7 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
for (int i = 0; i < hw_wr_wide_log2 && i < hw_rd_wide_log2; i++)
hw_addr[i] = State::S0;
for (auto cell: cells)
cell->setPort(stringf("\\PORT_%s_ADDR", name), hw_addr);
set_ram_port(cell, stringf("\\PORT_%s_ADDR", name), hw_addr);
// Write part.
if (pdef.kind != PortKind::Ar && pdef.kind != PortKind::Sr) {
@@ -1850,31 +1873,31 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
hw_wren.append(big_wren[bit.mux_idx][bit.bit]);
}
}
cell->setPort(stringf("\\PORT_%s_WR_DATA", name), hw_wdata);
set_ram_port(cell, stringf("\\PORT_%s_WR_DATA", name), hw_wdata);
if (pdef.wrbe_separate) {
// TODO make some use of it
SigSpec en = mem.module->ReduceOr(NEW_ID, hw_wren);
cell->setPort(stringf("\\PORT_%s_WR_EN", name), en);
cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren);
set_ram_port(cell, stringf("\\PORT_%s_WR_EN", name), en);
set_ram_port(cell, stringf("\\PORT_%s_WR_BE", name), hw_wren);
if (cfg.def->width_mode != WidthMode::Single)
cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
} else {
cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren);
set_ram_port(cell, stringf("\\PORT_%s_WR_EN", name), hw_wren);
if (cfg.def->byte != 0 && (cfg.def->width_mode != WidthMode::Single || opts.force_params))
cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren));
}
}
} else {
for (auto cell: cells) {
cell->setPort(stringf("\\PORT_%s_WR_DATA", name), Const(State::Sx, width));
set_ram_port(cell, stringf("\\PORT_%s_WR_DATA", name), Const(State::Sx, width));
SigSpec hw_wren = Const(State::S0, width / effective_byte);
if (pdef.wrbe_separate) {
cell->setPort(stringf("\\PORT_%s_WR_EN", name), State::S0);
cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren);
set_ram_port(cell, stringf("\\PORT_%s_WR_EN", name), State::S0);
set_ram_port(cell, stringf("\\PORT_%s_WR_BE", name), hw_wren);
if (cfg.def->width_mode != WidthMode::Single)
cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
} else {
cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren);
set_ram_port(cell, stringf("\\PORT_%s_WR_EN", name), hw_wren);
if (cfg.def->byte != 0 && cfg.def->width_mode != WidthMode::Single)
cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren));
}
@@ -1894,11 +1917,11 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
auto cell = cells[rd];
if (pdef.kind == PortKind::Sr || pdef.kind == PortKind::Srsw) {
if (pdef.rd_en)
cell->setPort(stringf("\\PORT_%s_RD_EN", name), rpcfg.rd_en_to_clk_en ? State::S1 : rport.en);
set_ram_port(cell, stringf("\\PORT_%s_RD_EN", name), rpcfg.rd_en_to_clk_en ? State::S1 : rport.en);
if (pdef.rdarstval != ResetValKind::None)
cell->setPort(stringf("\\PORT_%s_RD_ARST", name), rport.arst);
set_ram_port(cell, stringf("\\PORT_%s_RD_ARST", name), rport.arst);
if (pdef.rdsrstval != ResetValKind::None)
cell->setPort(stringf("\\PORT_%s_RD_SRST", name), rport.srst);
set_ram_port(cell, stringf("\\PORT_%s_RD_SRST", name), rport.srst);
if (pdef.rdinitval == ResetValKind::Any || pdef.rdinitval == ResetValKind::NoUndef) {
Const val = rport.init_value;
if (pdef.rdarstval == ResetValKind::Init && rport.arst != State::S0) {
@@ -1949,7 +1972,7 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
}
}
SigSpec hw_rdata = mem.module->addWire(NEW_ID, width);
cell->setPort(stringf("\\PORT_%s_RD_DATA", name), hw_rdata);
set_ram_port(cell, stringf("\\PORT_%s_RD_DATA", name), hw_rdata, true);
SigSpec lhs;
SigSpec rhs;
for (int i = 0; i < GetSize(hw_rdata); i++) {
@@ -1965,11 +1988,11 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
for (auto cell: cells) {
if (pdef.kind == PortKind::Sr || pdef.kind == PortKind::Srsw) {
if (pdef.rd_en)
cell->setPort(stringf("\\PORT_%s_RD_EN", name), State::S0);
set_ram_port(cell, stringf("\\PORT_%s_RD_EN", name), State::S0);
if (pdef.rdarstval != ResetValKind::None)
cell->setPort(stringf("\\PORT_%s_RD_ARST", name), State::S0);
set_ram_port(cell, stringf("\\PORT_%s_RD_ARST", name), State::S0);
if (pdef.rdsrstval != ResetValKind::None)
cell->setPort(stringf("\\PORT_%s_RD_SRST", name), State::S0);
set_ram_port(cell, stringf("\\PORT_%s_RD_SRST", name), State::S0);
if (pdef.rdinitval == ResetValKind::Any)
cell->setParam(stringf("\\PORT_%s_RD_INIT_VALUE", name), Const(State::Sx, width));
else if (pdef.rdinitval == ResetValKind::NoUndef)
@@ -1984,7 +2007,7 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
cell->setParam(stringf("\\PORT_%s_RD_SRST_VALUE", name), Const(State::S0, width));
}
SigSpec hw_rdata = mem.module->addWire(NEW_ID, width);
cell->setPort(stringf("\\PORT_%s_RD_DATA", name), hw_rdata);
set_ram_port(cell, stringf("\\PORT_%s_RD_DATA", name), hw_rdata, true);
}
}
}
@@ -2086,12 +2109,12 @@ void MemMapping::emit(const MemConfig &cfg) {
auto &ccfg = cfg.shared_clocks[i];
if (cdef.anyedge) {
cell->setParam(stringf("\\CLK_%s_POL", cdef.name), ccfg.used ? ccfg.polarity : true);
cell->setPort(stringf("\\CLK_%s", cdef.name), ccfg.used ? ccfg.clk : State::S0);
set_ram_port(cell, stringf("\\CLK_%s", cdef.name), ccfg.used ? ccfg.clk : State::S0);
} else {
SigSpec sig = ccfg.used ? ccfg.clk : State::S0;
if (ccfg.used && ccfg.invert)
sig = mem.module->Not(NEW_ID, sig);
cell->setPort(stringf("\\CLK_%s", cdef.name), sig);
set_ram_port(cell, stringf("\\CLK_%s", cdef.name), sig);
}
}
if (cfg.def->init == MemoryInitKind::Any || cfg.def->init == MemoryInitKind::NoUndef) {
+25 -2
View File
@@ -122,6 +122,29 @@ struct QlBramMergeWorker {
return bram1_map;
}
void set_bb_instance_port(RTLIL::Cell *merged, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
static const IdString generated = RTLIL::escape_id("ql_bram_merge_blackbox");
RTLIL::Design *design = module->design;
RTLIL::Module *mod = design->module(merged->type);
if (mod == nullptr) {
mod = design->addModule(merged->type);
mod->set_bool_attribute(ID::blackbox);
mod->set_bool_attribute(generated);
}
if (mod->get_bool_attribute(generated) && mod->wire(port) == nullptr) {
const std::string &name = port.str();
RTLIL::Wire *wire = mod->addWire(port, GetSize(sig));
bool is_output = name.size() >= 8 && name.compare(name.size() - 8, 8, "_RD_DATA") == 0;
(is_output ? wire->port_output : wire->port_input) = true;
mod->fixup_ports();
}
merged->setPort(port, sig);
}
void merge_brams(RTLIL::Cell* bram1, RTLIL::Cell* bram2)
{
const RTLIL::IdString merged_cell_type = ID($__QLF_TDP36K_MERGED);
@@ -144,14 +167,14 @@ struct QlBramMergeWorker {
for (auto &it : port_map(false))
{
if (bram1->hasPort(it.first))
merged->setPort(it.second, bram1->getPort(it.first));
set_bb_instance_port(merged, it.second, bram1->getPort(it.first));
else
log_error("Can't find port %s on cell %s!\n", it.first.unescape(), bram1->name.unescape());
}
for (auto &it : port_map(true))
{
if (bram2->hasPort(it.first))
merged->setPort(it.second, bram2->getPort(it.first));
set_bb_instance_port(merged, it.second, bram2->getPort(it.first));
else
log_error("Can't find port %s on cell %s!\n", it.first.unescape(), bram2->name.unescape());
}