mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	Merge pull request #5080 from akashlevy/muldiv_c
Add `muldiv_c` peepopt
This commit is contained in:
		
						commit
						3823157c25
					
				
					 7 changed files with 488 additions and 0 deletions
				
			
		
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -894,6 +894,7 @@ SH_TEST_DIRS += tests/bram
 | 
			
		|||
SH_TEST_DIRS += tests/svinterfaces
 | 
			
		||||
SH_TEST_DIRS += tests/xprop
 | 
			
		||||
SH_TEST_DIRS += tests/select
 | 
			
		||||
SH_TEST_DIRS += tests/peepopt
 | 
			
		||||
SH_TEST_DIRS += tests/proc
 | 
			
		||||
SH_TEST_DIRS += tests/blif
 | 
			
		||||
SH_TEST_DIRS += tests/arch
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@ PEEPOPT_PATTERN  = passes/opt/peepopt_shiftmul_right.pmg
 | 
			
		|||
PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg
 | 
			
		||||
 | 
			
		||||
passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,14 @@ bool did_something;
 | 
			
		|||
// scratchpad configurations for pmgen
 | 
			
		||||
int shiftadd_max_ratio;
 | 
			
		||||
 | 
			
		||||
// Helper function, removes LSB 0s
 | 
			
		||||
SigSpec remove_bottom_padding(SigSpec sig)
 | 
			
		||||
{
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	for (; i < sig.size() - 1 && sig[i] == State::S0; i++);
 | 
			
		||||
	return sig.extract(i, sig.size() - i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "passes/opt/peepopt_pm.h"
 | 
			
		||||
 | 
			
		||||
struct PeepoptPass : public Pass {
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +53,8 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("   * muldiv - Replace (A*B)/B with A\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n");
 | 
			
		||||
		log("                and A' is derived from A by appropriately inserting padding\n");
 | 
			
		||||
		log("                into the signal. (right variant)\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +116,7 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
					pm.run_shiftmul_right();
 | 
			
		||||
					pm.run_shiftmul_left();
 | 
			
		||||
					pm.run_muldiv();
 | 
			
		||||
					pm.run_muldiv_c();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										125
									
								
								passes/opt/peepopt_muldiv_c.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								passes/opt/peepopt_muldiv_c.pmg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
pattern muldiv_c
 | 
			
		||||
//
 | 
			
		||||
// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license.
 | 
			
		||||
// Transforms mul->div into const->mul when b and c are divisible constants:
 | 
			
		||||
// y = (a * b_const) / c_const   ===>   a * eval(b_const / c_const)
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
state <SigSpec> a b_const mul_y
 | 
			
		||||
 | 
			
		||||
match mul
 | 
			
		||||
	// Select multiplier
 | 
			
		||||
	select mul->type == $mul
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
code a b_const mul_y
 | 
			
		||||
	// Get multiplier signals
 | 
			
		||||
	a = port(mul, \A);
 | 
			
		||||
	b_const = port(mul, \B);
 | 
			
		||||
	mul_y = port(mul, \Y);
 | 
			
		||||
 | 
			
		||||
	// Fanout of each multiplier Y bit should be 1 (no bit-split)
 | 
			
		||||
	if (nusers(mul_y) != 2)
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// A and B can be interchanged
 | 
			
		||||
	branch;
 | 
			
		||||
	std::swap(a, b_const);
 | 
			
		||||
endcode
 | 
			
		||||
 | 
			
		||||
match div
 | 
			
		||||
	// Select div of form (a * b_const) / c_const
 | 
			
		||||
	select div->type == $div
 | 
			
		||||
 | 
			
		||||
	// Check that b_const and c_const is constant
 | 
			
		||||
	filter b_const.is_fully_const()
 | 
			
		||||
	filter port(div, \B).is_fully_const()
 | 
			
		||||
	index <SigSpec> remove_bottom_padding(port(div, \A)) === mul_y
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
code
 | 
			
		||||
	// Get div signals
 | 
			
		||||
	SigSpec div_a = port(div, \A);
 | 
			
		||||
	SigSpec c_const = port(div, \B);
 | 
			
		||||
	SigSpec div_y = port(div, \Y);
 | 
			
		||||
 | 
			
		||||
	// Get offset of multiplier result chunk in divider
 | 
			
		||||
	int offset = GetSize(div_a) - GetSize(mul_y);
 | 
			
		||||
 | 
			
		||||
	// Get properties and values of b_const and c_const
 | 
			
		||||
	// b_const may be coming from the A port
 | 
			
		||||
	// But it is an RTLIL invariant that A_SIGNED equals B_SIGNED
 | 
			
		||||
	bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool();
 | 
			
		||||
	bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool();
 | 
			
		||||
	int b_const_int = b_const.as_int(b_const_signed);
 | 
			
		||||
	int c_const_int = c_const.as_int(c_const_signed);
 | 
			
		||||
	int b_const_int_shifted = b_const_int << offset;
 | 
			
		||||
 | 
			
		||||
	// Helper lambdas for two's complement math	
 | 
			
		||||
	auto sign2sComplement = [](auto value, int numBits) {
 | 
			
		||||
  		if (value & (1 << (numBits - 1))) {
 | 
			
		||||
   			return -1; 
 | 
			
		||||
  		} else {
 | 
			
		||||
   		    return 1; 
 | 
			
		||||
  		}
 | 
			
		||||
	};
 | 
			
		||||
	auto twosComplement = [](auto value, int numBits) {
 | 
			
		||||
  		if (value & (1 << (numBits - 1))) {
 | 
			
		||||
   			return (~value) + 1; // invert bits before adding 1
 | 
			
		||||
  		} else {
 | 
			
		||||
   		    return value; 
 | 
			
		||||
  		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Two's complement conversion
 | 
			
		||||
	if (b_const_signed)
 | 
			
		||||
		b_const_int = sign2sComplement(b_const_int, GetSize(b_const)) * twosComplement(b_const_int, GetSize(b_const));
 | 
			
		||||
	if (c_const_signed)
 | 
			
		||||
		c_const_int = sign2sComplement(c_const_int, GetSize(c_const)) * twosComplement(c_const_int, GetSize(c_const));
 | 
			
		||||
	// Calculate the constant and compress the width to fit the value
 | 
			
		||||
	Const const_ratio;
 | 
			
		||||
	Const b_const_actual;
 | 
			
		||||
	// Avoid division by zero
 | 
			
		||||
	if (c_const_int == 0)
 | 
			
		||||
		reject;
 | 
			
		||||
	b_const_actual = b_const_int_shifted;
 | 
			
		||||
	b_const_actual.compress(b_const_signed);
 | 
			
		||||
 | 
			
		||||
	const_ratio = b_const_int_shifted / c_const_int;
 | 
			
		||||
	const_ratio.compress(b_const_signed | c_const_signed);
 | 
			
		||||
 | 
			
		||||
	// Integer values should be lesser than 32 bits
 | 
			
		||||
	// This is because we are using C++ types, and int is 32 bits
 | 
			
		||||
	// FIXME: use long long or BigInteger to make pass work with >32 bits
 | 
			
		||||
	if (GetSize(mul->getParam(ID::B_WIDTH)) > 32)
 | 
			
		||||
		reject;
 | 
			
		||||
	if (GetSize(b_const) > 32)
 | 
			
		||||
		reject;
 | 
			
		||||
	if (GetSize(c_const) + offset > 32)
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// Check for potential multiplier overflow
 | 
			
		||||
	if (GetSize(b_const_actual) + GetSize(a) > GetSize(mul_y))
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// Check that there are only zeros before offset
 | 
			
		||||
	if (offset < 0 || !div_a.extract(0, offset).is_fully_zero())
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// Check that b is divisible by c
 | 
			
		||||
	if (b_const_int_shifted % c_const_int != 0)
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// Rewire to only keep multiplier
 | 
			
		||||
	mul->setPort(\A, a);
 | 
			
		||||
	mul->setPort(\B, const_ratio);
 | 
			
		||||
	mul->setPort(\Y, div_y);
 | 
			
		||||
 | 
			
		||||
	// Remove divider
 | 
			
		||||
	autoremove(div);
 | 
			
		||||
 | 
			
		||||
	// Log, fixup, accept
 | 
			
		||||
	log("muldiv_const pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
 | 
			
		||||
	mul->fixup_parameters();
 | 
			
		||||
	accept;
 | 
			
		||||
endcode
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/peepopt/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/peepopt/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
/*.log
 | 
			
		||||
							
								
								
									
										343
									
								
								tests/peepopt/muldiv_c.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								tests/peepopt/muldiv_c.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,343 @@
 | 
			
		|||
log -header "Test simple positive case"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top (
 | 
			
		||||
  input wire  [11:0] a,
 | 
			
		||||
  output wire  [11:0] y
 | 
			
		||||
);
 | 
			
		||||
  assign y = (a * 16'd5140) / (257 * 2);
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test negative case where div is kept"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top (
 | 
			
		||||
  input wire signed [11:0] a,
 | 
			
		||||
  output wire signed [31:0] y,
 | 
			
		||||
  output wire probe
 | 
			
		||||
);
 | 
			
		||||
   wire [28:0] tmp = (a * 16'd5140);
 | 
			
		||||
   assign probe = tmp[28];
 | 
			
		||||
 | 
			
		||||
  assign y = tmp[27:0] / (257 * 2);
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Basic pattern transformed: (a * b) / c"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Transformed on symmetry in multiplication"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = 4'sd6 * a;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Transformed on b == c"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd6;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "b negative, c positive"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * -4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "b positive, c negative"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / -8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when b not divisible by c"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd3;
 | 
			
		||||
	assign y = mul / 8'sd2;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when product has a second fanout"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
	output signed [7:0] z,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
	assign z = mul;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when divisor is 0"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd4;
 | 
			
		||||
	assign y = mul / 8'sd0;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when (a*b) output can overflow (divider’s A input signed)"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [5:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when (a*b) output can overflow (divider’s A input signed)"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [6:0] mul;
 | 
			
		||||
	assign mul = a * 4'sd6;
 | 
			
		||||
	assign y = mul / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when (a*b) output can overflow (divider’s A input unsigned)"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input [3:0] a,
 | 
			
		||||
	output [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire [4:0] mul;
 | 
			
		||||
	assign mul = a * 4'd4;
 | 
			
		||||
	assign y = mul / 8'd2;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when (a*b) output can overflow (divider’s A input unsigned)"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input [3:0] a,
 | 
			
		||||
	output [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire [6:0] mul;
 | 
			
		||||
	assign mul = a * 4'd8;
 | 
			
		||||
	assign y = mul / 8'd2;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when (a*b) and x/c fitting criteria but not connected (x != a*b)"
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	input signed [7:0] b,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
	output signed [7:0] z,
 | 
			
		||||
);
 | 
			
		||||
	assign y = a * 4'sd6;
 | 
			
		||||
	assign z = b / 8'sd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "No transform when b only divisible by c if b misinterpreted as unsigned"
 | 
			
		||||
# b 1001 is -7 but 9 misinterpreted
 | 
			
		||||
# c 11 is 3
 | 
			
		||||
log -push
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input signed [3:0] a,
 | 
			
		||||
	output signed [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire signed [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'sb1001;
 | 
			
		||||
	assign y = mul / 8'sb11;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 1 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Transform even if (a*b) result would overflow if divider’s A input signedness is confused & (A input is unsigned)"
 | 
			
		||||
log -push
 | 
			
		||||
# Transform even if:
 | 
			
		||||
# (a*b) result would overflow if divider’s A input signedness is confused
 | 
			
		||||
# (A input is unsigned)
 | 
			
		||||
read_verilog <<EOT
 | 
			
		||||
module top(
 | 
			
		||||
	input [3:0] a,
 | 
			
		||||
	output [7:0] y,
 | 
			
		||||
);
 | 
			
		||||
    wire [7:0] mul;
 | 
			
		||||
	assign mul = a * 4'd6;
 | 
			
		||||
	assign y = mul / 8'd3;
 | 
			
		||||
endmodule
 | 
			
		||||
EOT
 | 
			
		||||
equiv_opt -assert peepopt
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-count 1 t:$mul
 | 
			
		||||
select -assert-count 0 t:$div
 | 
			
		||||
design -reset
 | 
			
		||||
							
								
								
									
										6
									
								
								tests/peepopt/run-test.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/peepopt/run-test.sh
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
#!/usr/bin/env bash
 | 
			
		||||
set -e
 | 
			
		||||
for x in *.ys; do
 | 
			
		||||
  echo "Running $x.."
 | 
			
		||||
  ../../yosys -ql ${x%.ys}.log $x
 | 
			
		||||
done
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue