diff options
Diffstat (limited to 'passes')
-rw-r--r-- | passes/memory/memory_collect.cc | 4 | ||||
-rw-r--r-- | passes/memory/memory_map.cc | 88 | ||||
-rw-r--r-- | passes/memory/memory_unpack.cc | 2 | ||||
-rw-r--r-- | passes/opt/opt_reduce.cc | 80 |
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); } } |