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 + + + | 
