diff options
| author | Clifford Wolf <clifford@clifford.at> | 2016-05-29 12:17:36 +0200 | 
|---|---|---|
| committer | Clifford Wolf <clifford@clifford.at> | 2016-05-29 12:17:36 +0200 | 
| commit | 11f7b8a2a1dd6e5c47e8081e4485127331fd80be (patch) | |
| tree | 63343bbce2a0c7a6f1598301b13d375e0a3ff7e9 | |
| parent | 766032c5f85e33c8aabb69d1868c3493f254695f (diff) | |
| download | yosys-11f7b8a2a1dd6e5c47e8081e4485127331fd80be.tar.gz yosys-11f7b8a2a1dd6e5c47e8081e4485127331fd80be.tar.bz2 yosys-11f7b8a2a1dd6e5c47e8081e4485127331fd80be.zip | |
Added opt_expr support for div/mod by power-of-two
| -rw-r--r-- | passes/opt/opt_expr.cc | 69 | ||||
| -rw-r--r-- | tests/simple/constmuldivmod.v | 27 | 
2 files changed, 96 insertions, 0 deletions
| diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index a18ebb901..b62eae285 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1098,6 +1098,75 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons  			}  		} +		if (!keepdc && cell->type.in("$div", "$mod")) +		{ +			bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); +			SigSpec sig_b = assign_map(cell->getPort("\\B")); +			SigSpec sig_y = assign_map(cell->getPort("\\Y")); + +			if (sig_b.is_fully_def() && sig_b.size() <= 32) +			{ +				int b_val = sig_b.as_int(); + +				if (b_val == 0) +				{ +					cover("opt.opt_expr.divmod_zero"); + +					log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", +							cell->name.c_str(), module->name.c_str()); + +					module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); +					module->remove(cell); + +					did_something = true; +					goto next_cell; +				} + +				for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++) +					if (b_val == (1 << i)) +					{ +						if (cell->type == "$div") +						{ +							cover("opt.opt_expr.div_shift"); + +							log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", +									b_val, cell->name.c_str(), module->name.c_str(), i); + +							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); + +							while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) +								new_b.pop_back(); + +							cell->type = "$shr"; +							cell->parameters["\\B_WIDTH"] = GetSize(new_b); +							cell->parameters["\\B_SIGNED"] = false; +							cell->setPort("\\B", new_b); +							cell->check(); +						} +						else +						{ +							cover("opt.opt_expr.mod_mask"); + +							log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", +									b_val, cell->name.c_str(), module->name.c_str()); + +							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); + +							if (b_signed) +								new_b.push_back(State::S0); + +							cell->type = "$and"; +							cell->parameters["\\B_WIDTH"] = GetSize(new_b); +							cell->setPort("\\B", new_b); +							cell->check(); +						} + +						did_something = true; +						goto next_cell; +					} +			} +		} +  	next_cell:;  #undef ACTION_DO  #undef ACTION_DO_Y diff --git a/tests/simple/constmuldivmod.v b/tests/simple/constmuldivmod.v new file mode 100644 index 000000000..d1d8be862 --- /dev/null +++ b/tests/simple/constmuldivmod.v @@ -0,0 +1,27 @@ +module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y); +	always @* begin +		case (mode) +			0: Y = A / 8'd0; +			1: Y = A % 8'd0; +			2: Y = A * 8'd0; + +			3: Y = A / 8'd1; +			4: Y = A % 8'd1; +			5: Y = A * 8'd1; + +			6: Y = A / 8'd2; +			7: Y = A % 8'd2; +			8: Y = A * 8'd2; + +			9: Y = A / 8'd4; +			10: Y = A % 8'd4; +			11: Y = A * 8'd4; + +			12: Y = A / 8'd8; +			13: Y = A % 8'd8; +			14: Y = A * 8'd8; + +			default: Y = 8'd16 * A; +		endcase +	end +endmodule | 
