aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--passes/proc/proc_rom.cc55
-rw-r--r--tests/proc/proc_rom.ys146
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
+
+
+