diff options
-rw-r--r-- | passes/proc/proc_rom.cc | 55 | ||||
-rw-r--r-- | tests/proc/proc_rom.ys | 146 |
2 files changed, 186 insertions, 15 deletions
diff --git a/passes/proc/proc_rom.cc b/passes/proc/proc_rom.cc index 4fd611518..b83466ce7 100644 --- a/passes/proc/proc_rom.cc +++ b/passes/proc/proc_rom.cc @@ -46,10 +46,6 @@ struct RomWorker log_debug("rejecting switch: no cases\n"); return; } - if (GetSize(sw->signal) > 30) { - log_debug("rejecting switch: address too wide\n"); - return; - } // A switch can be converted into ROM when: // @@ -70,9 +66,15 @@ struct RomWorker } } + int swsigbits = 0; + for (int i = 0; i < GetSize(sw->signal); i++) + if (sw->signal[i] != State::S0) + swsigbits = i + 1; + dict<int, Const> vals; Const default_val; bool got_default = false; + int maxaddr = 0; for (auto cs : sw->cases) { if (!cs->switches.empty()) { log_debug("rejecting switch: has nested switches\n"); @@ -105,10 +107,21 @@ struct RomWorker log_debug("rejecting switch: case value has undef bits\n"); return; } - int a = addr.as_int(); + Const c = addr.as_const(); + while (GetSize(c) && c.bits.back() == State::S0) + c.bits.pop_back(); + if (GetSize(c) > swsigbits) + continue; + if (GetSize(c) > 30) { + log_debug("rejecting switch: address too large\n"); + return; + } + int a = c.as_int(); if (vals.count(a)) continue; vals[a] = val; + if (a > maxaddr) + maxaddr = a; } if (cs->compare.empty()) { default_val = val; @@ -116,8 +129,8 @@ struct RomWorker break; } } - int total = 1 << GetSize(sw->signal); - if (!got_default && GetSize(vals) != total) { + int abits = ceil_log2(maxaddr + 1); + if (!got_default && (swsigbits > 30 || GetSize(vals) != (1 << swsigbits))) { log_debug("rejecting switch: not all values are covered\n"); return; } @@ -127,18 +140,18 @@ struct RomWorker log_debug("rejecting switch: not enough values\n"); return; } - if (total / GetSize(vals) > 4) { + if ((1 << abits) / GetSize(vals) > 4) { log_debug("rejecting switch: not enough density\n"); return; } // Ok, let's do it. SigSpec rdata = module->addWire(NEW_ID, GetSize(lhs)); - Mem mem(module, NEW_ID, GetSize(lhs), 0, total); + Mem mem(module, NEW_ID, GetSize(lhs), 0, 1 << abits); mem.attributes = sw->attributes; Const init_data; - for (int i = 0; i < total; i++) { + for (int i = 0; i < mem.size; i++) { auto it = vals.find(i); if (it == vals.end()) { log_assert(got_default); @@ -157,7 +170,7 @@ struct RomWorker mem.inits.push_back(std::move(init)); MemRd rd; - rd.addr = sw->signal; + rd.addr = sw->signal.extract(0, abits); rd.data = rdata; rd.init_value = Const(State::Sx, GetSize(lhs)); rd.arst_value = Const(State::Sx, GetSize(lhs)); @@ -168,10 +181,22 @@ struct RomWorker for (auto cs: sw->cases) delete cs; sw->cases.clear(); - sw->signal = SigSpec(); - RTLIL::CaseRule *cs = new RTLIL::CaseRule; - cs->actions.push_back(SigSig(lhs, rdata)); - sw->cases.push_back(cs); + sw->signal = sw->signal.extract(0, swsigbits); + if (abits == GetSize(sw->signal)) { + sw->signal = SigSpec(); + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->actions.push_back(SigSig(lhs, rdata)); + sw->cases.push_back(cs); + } else { + sw->signal = sw->signal.extract_end(abits); + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(Const(State::S0, GetSize(sw->signal))); + cs->actions.push_back(SigSig(lhs, rdata)); + sw->cases.push_back(cs); + RTLIL::CaseRule *cs2 = new RTLIL::CaseRule; + cs2->actions.push_back(SigSig(lhs, default_val)); + sw->cases.push_back(cs2); + } count += 1; } diff --git a/tests/proc/proc_rom.ys b/tests/proc/proc_rom.ys index c854e732f..0ef2e2c61 100644 --- a/tests/proc/proc_rom.ys +++ b/tests/proc/proc_rom.ys @@ -33,6 +33,7 @@ hierarchy -auto-top design -save orig proc +select -assert-count 1 t:$memrd_v2 memory opt_dff design -stash postopt @@ -41,3 +42,148 @@ proc -norom design -stash preopt equiv_opt -assert -run prepare: dummy + + + +design -reset + +read_verilog << EOT + +module top(input [3:0] a, input en, output [7:0] d); + +always @* + if (en) + case(a) + 4'h0: d <= 8'h12; + 4'h1: d <= 8'h34; + 4'h2: d <= 8'h56; + 4'h3: d <= 8'h78; + 4'h4: d <= 8'h9a; + 4'h5: d <= 8'hbc; + 4'h6: d <= 8'hde; + 4'h7: d <= 8'hff; + 4'h8: d <= 8'h61; + 4'h9: d <= 8'h49; + 4'ha: d <= 8'h36; + 4'hb: d <= 8'h81; + 4'hc: d <= 8'h8c; + default: d <= 8'h11; + endcase + else + d <= 0; + +endmodule + +EOT + +hierarchy -auto-top + +design -save orig +proc +select -assert-count 1 t:$memrd_v2 +memory +opt_dff +design -stash postopt +design -load orig +proc -norom +design -stash preopt + +equiv_opt -assert -run prepare: dummy + + + +design -reset + +read_verilog << EOT + +module top(input [31:0] a, input en, output [7:0] d); + +always @* + if (en) + case(a) + 0: d <= 8'h12; + 1: d <= 8'h34; + 2: d <= 8'h56; + 3: d <= 8'h78; + 4: d <= 8'h9a; + 5: d <= 8'hbc; + 6: d <= 8'hde; + 7: d <= 8'hff; + 8: d <= 8'h61; + 9: d <= 8'h49; + 10: d <= 8'h36; + 11: d <= 8'h81; + 12: d <= 8'h8c; + default: d <= 8'h11; + endcase + else + d <= 0; + +endmodule + +EOT + +hierarchy -auto-top + +design -save orig +proc +select -assert-count 1 t:$memrd_v2 +memory +opt_dff +design -stash postopt +design -load orig +proc -norom +design -stash preopt + +equiv_opt -assert -run prepare: dummy + + +design -reset + +read_verilog << EOT + +module top(input [3:0] a, input en, output [7:0] d); + +always @* + if (en) + case(a) + 'h0: d <= 8'h12; + 'h1: d <= 8'h34; + 'h2: d <= 8'h56; + 'h3: d <= 8'h78; + 'h4: d <= 8'h9a; + 'h5: d <= 8'hbc; + 'h6: d <= 8'hde; + 'h7: d <= 8'hff; + 'h8: d <= 8'h61; + 'h9: d <= 8'h49; + 'ha: d <= 8'h36; + 'hb: d <= 8'h81; + 'hc: d <= 8'h8c; + 'hd: d <= 8'ha9; + 'he: d <= 8'h99; + 'hf: d <= 8'h51; + endcase + else + d <= 0; + +endmodule + +EOT + +hierarchy -auto-top + +design -save orig +proc +select -assert-count 1 t:$memrd_v2 +memory +opt_dff +design -stash postopt +design -load orig +proc -norom +design -stash preopt + +equiv_opt -assert -run prepare: dummy + + + |