summaryrefslogtreecommitdiff
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/memory/memory_collect.cc4
-rw-r--r--passes/memory/memory_map.cc88
-rw-r--r--passes/memory/memory_unpack.cc2
-rw-r--r--passes/opt/opt_reduce.cc80
4 files changed, 136 insertions, 38 deletions
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 6fe5e162..028841f6 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -88,7 +88,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
clk_polarity.extend(1, false);
addr.extend(addr_bits, false);
data.extend(memory->width, false);
- en.extend(1, false);
+ en.extend(memory->width, false);
sig_wr_clk.append(clk);
sig_wr_clk_enable.append(clk_enable);
@@ -147,7 +147,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
assert(sig_wr_addr.width == wr_ports * addr_bits);
assert(sig_wr_data.width == wr_ports * memory->width);
- assert(sig_wr_en.width == wr_ports);
+ assert(sig_wr_en.width == wr_ports * memory->width);
mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index e0e3802d..10ab6e2f 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -69,8 +69,8 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
RTLIL::SigSpec refclock;
RTLIL::State refclock_pol = RTLIL::State::Sx;
for (int i = 0; i < clocks.width; i++) {
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
- if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
+ RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i * mem_width, mem_width);
+ if (wr_en.is_fully_const() && !wr_en.as_bool()) {
static_ports.insert(i);
continue;
}
@@ -256,7 +256,7 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j, 1);
+ RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j*mem_width, mem_width);
RTLIL::Cell *c = new RTLIL::Cell;
c->name = genid(cell->name, "$wreq", i, "", j);
@@ -271,46 +271,64 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
module->cells[c->name] = c;
count_wrmux++;
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wreq", i, "", j, "$y");
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
+ RTLIL::Wire *w_seladdr = new RTLIL::Wire;
+ w_seladdr->name = genid(cell->name, "$wreq", i, "", j, "$y");
+ module->wires[w_seladdr->name] = w_seladdr;
+ c->connections["\\Y"] = w_seladdr;
- if (wr_en != RTLIL::SigSpec(1, 1))
+ int wr_offset = 0;
+ while (wr_offset < wr_en.width)
{
+ int wr_width = 1;
+ RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
+
+ while (wr_offset + wr_width < wr_en.width) {
+ RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
+ if (next_wr_bit != wr_bit)
+ break;
+ wr_width++;
+ }
+
+ RTLIL::Wire *w = w_seladdr;
+
+ if (wr_bit != RTLIL::SigSpec(1, 1))
+ {
+ c = new RTLIL::Cell;
+ c->name = genid(cell->name, "$wren", i, "", j, "", wr_offset);
+ c->type = "$and";
+ c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+ c->connections["\\A"] = w;
+ c->connections["\\B"] = wr_bit;
+ module->cells[c->name] = c;
+
+ w = new RTLIL::Wire;
+ w->name = genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y");
+ module->wires[w->name] = w;
+ c->connections["\\Y"] = RTLIL::SigSpec(w);
+ }
+
c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wren", i, "", j);
- c->type = "$and";
- c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- c->connections["\\A"] = RTLIL::SigSpec(w);
- c->connections["\\B"] = wr_en;
+ c->name = genid(cell->name, "$wrmux", i, "", j, "", wr_offset);
+ c->type = "$mux";
+ c->parameters["\\WIDTH"] = wr_width;
+ c->connections["\\A"] = sig.extract(wr_offset, wr_width);
+ c->connections["\\B"] = wr_data.extract(wr_offset, wr_width);
+ c->connections["\\S"] = RTLIL::SigSpec(w);
module->cells[c->name] = c;
w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wren", i, "", j, "$y");
+ w->name = genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y");
+ w->width = wr_width;
module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
- }
+ c->connections["\\Y"] = w;
- c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wrmux", i, "", j);
- c->type = "$mux";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->connections["\\A"] = sig;
- c->connections["\\B"] = wr_data;
- c->connections["\\S"] = RTLIL::SigSpec(w);
- module->cells[c->name] = c;
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wrmux", i, "", j, "$y");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
- sig = RTLIL::SigSpec(w);
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ }
}
module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 782c0cd7..bbd01583 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -74,7 +74,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\PRIORITY"] = i;
cell->connections["\\CLK"] = memory->connections.at("\\WR_CLK").extract(i, 1);
- cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i, 1);
+ cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i*mem->width, mem->width);
cell->connections["\\ADDR"] = memory->connections.at("\\WR_ADDR").extract(i*abits, abits);
cell->connections["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
module->add(cell);
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index dfe21441..d5bcb7f0 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -171,6 +171,66 @@ struct OptReduceWorker
}
}
+ void opt_mux_bits(RTLIL::Cell *cell)
+ {
+ std::vector<RTLIL::SigBit> sig_a = assign_map(cell->connections["\\A"]).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_b = assign_map(cell->connections["\\B"]).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_y = assign_map(cell->connections["\\Y"]).to_sigbit_vector();
+
+ std::vector<RTLIL::SigBit> new_sig_y;
+ RTLIL::SigSig old_sig_conn;
+
+ std::vector<std::vector<RTLIL::SigBit>> consolidated_in_tuples;
+ std::map<std::vector<RTLIL::SigBit>, RTLIL::SigBit> consolidated_in_tuples_map;
+
+ for (int i = 0; i < int(sig_y.size()); i++)
+ {
+ std::vector<RTLIL::SigBit> in_tuple;
+ in_tuple.push_back(sig_a.at(i));
+ for (int j = i; j < int(sig_b.size()); j += int(sig_a.size()))
+ in_tuple.push_back(sig_b.at(j));
+
+ if (consolidated_in_tuples_map.count(in_tuple))
+ {
+ old_sig_conn.first.append_bit(sig_y.at(i));
+ old_sig_conn.second.append_bit(consolidated_in_tuples_map.at(in_tuple));
+ }
+ else
+ {
+ consolidated_in_tuples_map[in_tuple] = sig_y.at(i);
+ consolidated_in_tuples.push_back(in_tuple);
+ new_sig_y.push_back(sig_y.at(i));
+ }
+ }
+
+ if (new_sig_y.size() != sig_y.size())
+ {
+ log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
+ log(" Old inputs: A=%s, B=%s\n", log_signal(cell->connections["\\A"]), log_signal(cell->connections["\\B"]));
+
+ cell->connections["\\A"] = RTLIL::SigSpec();
+ for (auto &in_tuple : consolidated_in_tuples)
+ cell->connections["\\A"].append(in_tuple.at(0));
+
+ cell->connections["\\B"] = RTLIL::SigSpec();
+ for (int i = 1; i <= cell->connections["\\S"].width; i++)
+ for (auto &in_tuple : consolidated_in_tuples)
+ cell->connections["\\B"].append(in_tuple.at(i));
+
+ log(" New inputs: A=%s, B=%s\n", log_signal(cell->connections["\\A"]), log_signal(cell->connections["\\B"]));
+
+ cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size());
+ cell->connections["\\Y"] = new_sig_y;
+
+ module->connections.push_back(old_sig_conn);
+ module->check();
+
+ did_something = true;
+ OPT_DID_SOMETHING = true;
+ total_count++;
+ }
+ }
+
OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module)
{
@@ -179,6 +239,20 @@ struct OptReduceWorker
total_count = 0;
did_something = true;
+ SigPool mem_wren_sigs;
+ for (auto &cell_it : module->cells) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$mem")
+ mem_wren_sigs.add(assign_map(cell->connections["\\WR_EN"]));
+ if (cell->type == "$memwr")
+ mem_wren_sigs.add(assign_map(cell->connections["\\EN"]));
+ }
+ for (auto &cell_it : module->cells) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->connections["\\Q"])))
+ mem_wren_sigs.add(assign_map(cell->connections["\\D"]));
+ }
+
while (did_something)
{
did_something = false;
@@ -213,6 +287,12 @@ struct OptReduceWorker
RTLIL::Cell *cell = cell_it.second;
if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
continue;
+
+ // this optimization is to aggressive for most coarse-grain applications.
+ // but we always want it for multiplexers driving write enable ports.
+ if (mem_wren_sigs.check_any(assign_map(cell->connections.at("\\Y"))))
+ opt_mux_bits(cell);
+
opt_mux(cell);
}
}