aboutsummaryrefslogtreecommitdiffstats
path: root/passes/memory/memory_map.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/memory/memory_map.cc')
-rw-r--r--passes/memory/memory_map.cc149
1 files changed, 92 insertions, 57 deletions
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index ca1ca483d..fd5b1f1ad 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -30,6 +30,8 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMapWorker
{
bool attr_icase = false;
+ bool rom_only = false;
+ bool keepdc = false;
dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
RTLIL::Design *design;
@@ -107,11 +109,8 @@ struct MemoryMapWorker
SigSpec init_data = mem.get_init_data();
- // delete unused memory cell
- if (mem.rd_ports.empty()) {
- mem.remove();
+ if (!mem.wr_ports.empty() && rom_only)
return;
- }
// check if attributes allow us to infer FFRAM for this memory
for (const auto &attr : attributes) {
@@ -143,6 +142,12 @@ struct MemoryMapWorker
}
}
+ // delete unused memory cell
+ if (mem.rd_ports.empty()) {
+ mem.remove();
+ return;
+ }
+
// all write ports must share the same clock
RTLIL::SigSpec refclock;
bool refclock_pol = false;
@@ -186,11 +191,16 @@ struct MemoryMapWorker
{
int addr = i + mem.start_offset;
int idx = addr & ((1 << abits) - 1);
+ SigSpec w_init = init_data.extract(i*mem.width, mem.width);
if (static_cells_map.count(addr) > 0)
{
data_reg_out[idx] = static_cells_map[addr];
count_static++;
}
+ else if (mem.wr_ports.empty() && (!keepdc || w_init.is_fully_def()))
+ {
+ data_reg_out[idx] = w_init;
+ }
else
{
RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff));
@@ -212,13 +222,15 @@ struct MemoryMapWorker
w_out_name = genid(mem.memid, "", addr, "$q");
RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width);
- SigSpec w_init = init_data.extract(i*mem.width, mem.width);
if (!w_init.is_fully_undef())
w_out->attributes[ID::init] = w_init.as_const();
data_reg_out[idx] = w_out;
c->setPort(ID::Q, w_out);
+
+ if (mem.wr_ports.empty())
+ module->connect(RTLIL::SigSig(w_in, w_out));
}
}
@@ -266,69 +278,72 @@ struct MemoryMapWorker
log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
- for (int i = 0; i < mem.size; i++)
+ if (!mem.wr_ports.empty())
{
- int addr = i + mem.start_offset;
- int idx = addr & ((1 << abits) - 1);
- if (static_cells_map.count(addr) > 0)
- continue;
-
- RTLIL::SigSpec sig = data_reg_out[idx];
-
- for (int j = 0; j < GetSize(mem.wr_ports); j++)
+ for (int i = 0; i < mem.size; i++)
{
- auto &port = mem.wr_ports[j];
- RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2);
- RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr)));
+ int addr = i + mem.start_offset;
+ int idx = addr & ((1 << abits) - 1);
+ if (static_cells_map.count(addr) > 0)
+ continue;
- int sub = addr & ((1 << port.wide_log2) - 1);
+ RTLIL::SigSpec sig = data_reg_out[idx];
- int wr_offset = 0;
- while (wr_offset < mem.width)
+ for (int j = 0; j < GetSize(mem.wr_ports); j++)
{
- int wr_width = 1;
- RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1);
-
- while (wr_offset + wr_width < mem.width) {
- RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1);
- if (next_wr_bit != wr_bit)
- break;
- wr_width++;
- }
+ auto &port = mem.wr_ports[j];
+ RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2);
+ RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr)));
- RTLIL::Wire *w = w_seladdr;
+ int sub = addr & ((1 << port.wide_log2) - 1);
- if (wr_bit != State::S1)
+ int wr_offset = 0;
+ while (wr_offset < mem.width)
{
- RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and));
- c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
- c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
- c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
- c->parameters[ID::B_WIDTH] = RTLIL::Const(1);
- c->parameters[ID::Y_WIDTH] = RTLIL::Const(1);
- c->setPort(ID::A, w);
- c->setPort(ID::B, wr_bit);
-
- w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y"));
- c->setPort(ID::Y, RTLIL::SigSpec(w));
+ int wr_width = 1;
+ RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1);
+
+ while (wr_offset + wr_width < mem.width) {
+ RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1);
+ if (next_wr_bit != wr_bit)
+ break;
+ wr_width++;
+ }
+
+ RTLIL::Wire *w = w_seladdr;
+
+ if (wr_bit != State::S1)
+ {
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and));
+ c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
+ c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
+ c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
+ c->parameters[ID::B_WIDTH] = RTLIL::Const(1);
+ c->parameters[ID::Y_WIDTH] = RTLIL::Const(1);
+ c->setPort(ID::A, w);
+ c->setPort(ID::B, wr_bit);
+
+ w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y"));
+ c->setPort(ID::Y, RTLIL::SigSpec(w));
+ }
+
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux));
+ c->parameters[ID::WIDTH] = wr_width;
+ c->setPort(ID::A, sig.extract(wr_offset, wr_width));
+ c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
+ c->setPort(ID::S, RTLIL::SigSpec(w));
+
+ w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width);
+ c->setPort(ID::Y, w);
+
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ count_wrmux++;
}
-
- RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux));
- c->parameters[ID::WIDTH] = wr_width;
- c->setPort(ID::A, sig.extract(wr_offset, wr_width));
- c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
- c->setPort(ID::S, RTLIL::SigSpec(w));
-
- w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width);
- c->setPort(ID::Y, w);
-
- sig.replace(wr_offset, w);
- wr_offset += wr_width;
- count_wrmux++;
}
- }
- module->connect(RTLIL::SigSig(data_reg_in[idx], sig));
+ module->connect(RTLIL::SigSig(data_reg_in[idx], sig));
+ }
}
log(" write interface: %d write mux blocks.\n", count_wrmux);
@@ -366,10 +381,18 @@ struct MemoryMapPass : public Pass {
log(" -iattr\n");
log(" for -attr, ignore case of <value>.\n");
log("\n");
+ log(" -rom-only\n");
+ log(" only perform conversion for ROMs (memories with no write ports).\n");
+ log("\n");
+ log(" -keepdc\n");
+ log(" when mapping ROMs, keep x-bits shared across read ports.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool attr_icase = false;
+ bool rom_only = false;
+ bool keepdc = false;
dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n");
@@ -406,6 +429,16 @@ struct MemoryMapPass : public Pass {
attr_icase = true;
continue;
}
+ if (args[argidx] == "-rom-only")
+ {
+ rom_only = true;
+ continue;
+ }
+ if (args[argidx] == "-keepdc")
+ {
+ keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -414,6 +447,8 @@ struct MemoryMapPass : public Pass {
MemoryMapWorker worker(design, mod);
worker.attr_icase = attr_icase;
worker.attributes = attributes;
+ worker.rom_only = rom_only;
+ worker.keepdc = keepdc;
worker.run();
}
}