summaryrefslogtreecommitdiff
path: root/passes/memory
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-09-25 12:23:11 +0200
committerClifford Wolf <clifford@clifford.at>2015-09-25 12:23:11 +0200
commit924d9d6e86a5e9a2294479345daac1c03d78008a (patch)
tree04d28a2068b32c44c0aca2b8b815f6fc51cec427 /passes/memory
parentec92c8965960fa814c3663e987bc2a7eb80965e5 (diff)
Added read-enable to memory model
Diffstat (limited to 'passes/memory')
-rw-r--r--passes/memory/memory_bram.cc20
-rw-r--r--passes/memory/memory_collect.cc37
-rw-r--r--passes/memory/memory_dff.cc52
-rw-r--r--passes/memory/memory_map.cc33
-rw-r--r--passes/memory/memory_unpack.cc1
5 files changed, 101 insertions, 42 deletions
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index f638b5bb..3e83a6d9 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -112,15 +112,15 @@ struct rules_t
if (ports[i] != other.ports[i])
log_error("Bram %s variants %d and %d have different number of %c-ports.\n", log_id(name), variant, other.variant, 'A'+i);
if (wrmode[i] != other.wrmode[i])
- variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[1];
+ variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[i];
if (enable[i] != other.enable[i])
- variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[1];
+ variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[i];
if (transp[i] != other.transp[i])
- variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[1];
+ variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[i];
if (clocks[i] != other.clocks[i])
- variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[1];
+ variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[i];
if (clkpol[i] != other.clkpol[i])
- variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[1];
+ variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[i];
}
}
};
@@ -429,6 +429,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
rd_clkpol.extend_u0(rd_ports);
rd_transp.extend_u0(rd_ports);
+ SigSpec rd_en = cell->getPort("\\RD_EN");
SigSpec rd_clk = cell->getPort("\\RD_CLK");
SigSpec rd_data = cell->getPort("\\RD_DATA");
SigSpec rd_addr = cell->getPort("\\RD_ADDR");
@@ -688,6 +689,10 @@ grow_read_ports:;
log(" Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
+ if (rd_en[cell_port_i] != State::S1 && pi.enable == 0) {
+ log(" Bram port %c%d.%d has no read enable input.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
skip_bram_rport_clkcheck:
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) {
@@ -713,6 +718,7 @@ grow_read_ports:;
clock_polarities[pi.clkpol] = clkdom.second;
read_transp[pi.transp] = transp;
pi.sig_clock = clkdom.first;
+ pi.sig_en = rd_en[cell_port_i];
pi.effective_clkpol = clkdom.second;
}
@@ -886,6 +892,8 @@ grow_read_ports:;
if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
+ if (!pi.sig_en.empty())
+ bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q;
}
@@ -1126,7 +1134,7 @@ struct MemoryBramPass : public Pass {
log(" groups 2 # number of port groups\n");
log(" ports 1 1 # number of ports in each group\n");
log(" wrmode 1 0 # set to '1' if this groups is write ports\n");
- log(" enable 4 0 # number of enable bits (for write ports)\n");
+ log(" enable 4 1 # number of enable bits\n");
log(" transp 0 2 # transparent (for read ports)\n");
log(" clocks 1 2 # clock configuration\n");
log(" clkpol 2 2 # clock polarity configuration\n");
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 91b5759e..abd4b124 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -57,6 +57,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
SigSpec sig_rd_transparent;
SigSpec sig_rd_addr;
SigSpec sig_rd_data;
+ SigSpec sig_rd_en;
std::vector<Cell*> memcells;
@@ -139,22 +140,27 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
SigSpec transparent = SigSpec(cell->parameters["\\TRANSPARENT"]);
SigSpec addr = sigmap(cell->getPort("\\ADDR"));
SigSpec data = sigmap(cell->getPort("\\DATA"));
+ SigSpec en = sigmap(cell->getPort("\\EN"));
- clk.extend_u0(1, false);
- clk_enable.extend_u0(1, false);
- clk_polarity.extend_u0(1, false);
- transparent.extend_u0(1, false);
- addr.extend_u0(addr_bits, false);
- data.extend_u0(memory->width, false);
-
- sig_rd_clk.append(clk);
- sig_rd_clk_enable.append(clk_enable);
- sig_rd_clk_polarity.append(clk_polarity);
- sig_rd_transparent.append(transparent);
- sig_rd_addr.append(addr);
- sig_rd_data.append(data);
-
- rd_ports++;
+ if (!en.is_fully_zero())
+ {
+ clk.extend_u0(1, false);
+ clk_enable.extend_u0(1, false);
+ clk_polarity.extend_u0(1, false);
+ transparent.extend_u0(1, false);
+ addr.extend_u0(addr_bits, false);
+ data.extend_u0(memory->width, false);
+
+ sig_rd_clk.append(clk);
+ sig_rd_clk_enable.append(clk_enable);
+ sig_rd_clk_polarity.append(clk_polarity);
+ sig_rd_transparent.append(transparent);
+ sig_rd_addr.append(addr);
+ sig_rd_data.append(data);
+ sig_rd_en.append(en);
+
+ rd_ports++;
+ }
continue;
}
}
@@ -203,6 +209,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
mem->setPort("\\RD_CLK", sig_rd_clk);
mem->setPort("\\RD_ADDR", sig_rd_addr);
mem->setPort("\\RD_DATA", sig_rd_data);
+ mem->setPort("\\RD_EN", sig_rd_en);
for (auto c : memcells)
module->remove(c);
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 5584f27c..3373369f 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -31,6 +31,7 @@ struct MemoryDffWorker
vector<Cell*> dff_cells;
dict<SigBit, SigBit> invbits;
dict<SigBit, int> sigbit_users_count;
+ dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
@@ -150,16 +151,44 @@ struct MemoryDffWorker
if (sigbit_users_count[bit] > 1)
goto skip_ff_after_read_merging;
- if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
+ if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
{
- disconnect_dff(sig_data);
- cell->setPort("\\CLK", clk_data);
- cell->setPort("\\DATA", sig_data);
- cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
- cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
- cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
- log("merged data $dff to cell.\n");
- return;
+ bool enable_invert = mux_cells_a.count(sig_data);
+ Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
+ SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
+
+ sig_data = sigmap(mux->getPort("\\Y"));
+ for (auto bit : sig_data)
+ if (sigbit_users_count[bit] > 1)
+ goto skip_ff_after_read_merging;
+
+ if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q)
+ {
+ disconnect_dff(sig_data);
+ cell->setPort("\\CLK", clk_data);
+ cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
+ cell->setPort("\\DATA", sig_data);
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+ cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
+ log("merged data $dff with rd enable to cell.\n");
+ return;
+ }
+ }
+ else
+ {
+ if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
+ {
+ disconnect_dff(sig_data);
+ cell->setPort("\\CLK", clk_data);
+ cell->setPort("\\EN", State::S1);
+ cell->setPort("\\DATA", sig_data);
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+ cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
+ log("merged data $dff to cell.\n");
+ return;
+ }
}
skip_ff_after_read_merging:;
@@ -169,6 +198,7 @@ struct MemoryDffWorker
clk_addr != RTLIL::SigSpec(RTLIL::State::Sx))
{
cell->setPort("\\CLK", clk_addr);
+ cell->setPort("\\EN", State::S1);
cell->setPort("\\ADDR", sig_addr);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
@@ -191,6 +221,10 @@ struct MemoryDffWorker
for (auto cell : module->cells()) {
if (cell->type == "$dff")
dff_cells.push_back(cell);
+ if (cell->type == "$mux") {
+ mux_cells_a[sigmap(cell->getPort("\\A"))] = cell;
+ mux_cells_b[sigmap(cell->getPort("\\B"))] = cell;
+ }
if (cell->type == "$not" || cell->type == "$_NOT_" || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) {
SigSpec sig_a = cell->getPort("\\A");
SigSpec sig_y = cell->getPort("\\Y");
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index 524fa8d2..0b8ccb36 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -200,34 +200,43 @@ struct MemoryMapWorker
if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
{
+ RTLIL::Cell *dff_cell = nullptr;
+
if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
{
- RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
- c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
- c->setPort("\\D", rd_addr);
+ dff_cell = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ dff_cell->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
+ dff_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ dff_cell->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ dff_cell->setPort("\\D", rd_addr);
count_dff++;
RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
- c->setPort("\\Q", RTLIL::SigSpec(w));
+ dff_cell->setPort("\\Q", RTLIL::SigSpec(w));
rd_addr = RTLIL::SigSpec(w);
}
else
{
- RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
- c->setPort("\\Q", rd_signals.back());
+ dff_cell = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ dff_cell->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+ dff_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ dff_cell->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ dff_cell->setPort("\\Q", rd_signals.back());
count_dff++;
RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
rd_signals.clear();
rd_signals.push_back(RTLIL::SigSpec(w));
- c->setPort("\\D", rd_signals.back());
+ dff_cell->setPort("\\D", rd_signals.back());
+ }
+
+ SigBit en_bit = cell->getPort("\\RD_EN").extract(i);
+ if (en_bit != State::S1) {
+ SigSpec new_d = module->Mux(genid(cell->name, "$rdenmux", i),
+ dff_cell->getPort("\\Q"), dff_cell->getPort("\\D"), en_bit);
+ dff_cell->setPort("\\D", new_d);
}
}
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index a497362b..60724da7 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -57,6 +57,7 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\TRANSPARENT"] = RTLIL::SigSpec(memory->parameters.at("\\RD_TRANSPARENT")).extract(i, 1).as_const();
cell->setPort("\\CLK", memory->getPort("\\RD_CLK").extract(i, 1));
+ cell->setPort("\\EN", memory->getPort("\\RD_EN").extract(i, 1));
cell->setPort("\\ADDR", memory->getPort("\\RD_ADDR").extract(i*abits, abits));
cell->setPort("\\DATA", memory->getPort("\\RD_DATA").extract(i*mem->width, mem->width));
}