mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	muxadd and muldiv_c peepopt
This commit is contained in:
		
							parent
							
								
									8dabfbe429
								
							
						
					
					
						commit
						31a5197a1c
					
				
					 9 changed files with 902 additions and 38 deletions
				
			
		
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -918,6 +918,7 @@ SH_TEST_DIRS += tests/memlib
 | 
			
		|||
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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,8 @@ PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftadd.pmg
 | 
			
		|||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv_c.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muxadd.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv_c.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muxadd.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_formal_clockgateff.pmg
 | 
			
		||||
 | 
			
		||||
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,9 @@ bool did_something;
 | 
			
		|||
// scratchpad configurations for pmgen
 | 
			
		||||
int shiftadd_max_ratio;
 | 
			
		||||
 | 
			
		||||
// Helper function, removes LSB 0s
 | 
			
		||||
SigSpec remove_bottom_padding(SigSpec sig);
 | 
			
		||||
 | 
			
		||||
#include "passes/pmgen/peepopt_pm.h"
 | 
			
		||||
 | 
			
		||||
struct PeepoptPass : public Pass {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,8 +45,6 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("This pass employs the following rules by default:\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * muxadd - Replace S?(A+B):A with A+(S?B:0)\n");
 | 
			
		||||
		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");
 | 
			
		||||
| 
						 | 
				
			
			@ -67,13 +68,17 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
		log("                   based pattern to prevent combinational paths from the\n");
 | 
			
		||||
		log("                   output to the enable input after running clk2fflogic.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("If -withmuxadd is specified it adds the following rule:\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * muxadd - Replace S?(A+B):A with A+(S?B:0)\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | 
			
		||||
	{
 | 
			
		||||
		log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
 | 
			
		||||
 | 
			
		||||
		bool formalclk = false;
 | 
			
		||||
 | 
			
		||||
		bool withmuxadd = false;
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +86,10 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
				formalclk = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-withmuxadd") {
 | 
			
		||||
				withmuxadd = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(args, argidx, design);
 | 
			
		||||
| 
						 | 
				
			
			@ -110,11 +119,21 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
					pm.run_shiftmul_left();
 | 
			
		||||
					pm.run_muldiv();
 | 
			
		||||
					pm.run_muldiv_c();
 | 
			
		||||
					pm.run_muxadd();
 | 
			
		||||
					if (withmuxadd)
 | 
			
		||||
						pm.run_muxadd();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
} PeepoptPass;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE_NAMESPACE_END
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
pattern muldiv_c
 | 
			
		||||
//
 | 
			
		||||
// Transforms mul->div into div->mul when b and c are divisible constants:
 | 
			
		||||
// y = (a * b_const) / c_const   ===>   a * (b_const / c_const)
 | 
			
		||||
// 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
 | 
			
		||||
| 
						 | 
				
			
			@ -18,9 +19,8 @@ code a b_const mul_y
 | 
			
		|||
	mul_y = port(mul, \Y);
 | 
			
		||||
 | 
			
		||||
	// Fanout of each multiplier Y bit should be 1 (no bit-split)
 | 
			
		||||
	for (auto bit : mul_y)
 | 
			
		||||
		if (nusers(bit) != 2)
 | 
			
		||||
			reject;
 | 
			
		||||
	if (nusers(mul_y) != 2)
 | 
			
		||||
		reject;
 | 
			
		||||
 | 
			
		||||
	// A and B can be interchanged
 | 
			
		||||
	branch;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ match 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
 | 
			
		||||
| 
						 | 
				
			
			@ -46,13 +47,61 @@ code
 | 
			
		|||
	int offset = GetSize(div_a) - GetSize(mul_y);
 | 
			
		||||
 | 
			
		||||
	// Get properties and values of b_const and c_const
 | 
			
		||||
	int b_const_width = mul->getParam(ID::B_WIDTH).as_int();
 | 
			
		||||
	// 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +111,8 @@ code
 | 
			
		|||
		reject;
 | 
			
		||||
 | 
			
		||||
	// Rewire to only keep multiplier
 | 
			
		||||
	mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width));
 | 
			
		||||
	mul->setPort(\A, a);
 | 
			
		||||
	mul->setPort(\B, const_ratio);
 | 
			
		||||
	mul->setPort(\Y, div_y);
 | 
			
		||||
 | 
			
		||||
	// Remove divider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,59 +1,123 @@
 | 
			
		|||
pattern muxadd
 | 
			
		||||
//
 | 
			
		||||
// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license.
 | 
			
		||||
// Transforms add->mux into mux->add:
 | 
			
		||||
// y = s ? (a + b) : a   ===>   y = a + (s ? b : 0)
 | 
			
		||||
//
 | 
			
		||||
// or
 | 
			
		||||
// y = s ? a : (a + b)   ===>   y = a + (s ? 0 : b)
 | 
			
		||||
 | 
			
		||||
state <SigSpec> add_a add_b add_y
 | 
			
		||||
state <SigSpec> add_a add_b add_y add_a_ext mux_a mux_b mux_y
 | 
			
		||||
state <Const> add_a_signed
 | 
			
		||||
state <IdString> add_a_id add_b_id mux_a_id mux_b_id
 | 
			
		||||
 | 
			
		||||
match add
 | 
			
		||||
	// Select adder
 | 
			
		||||
	select add->type == $add
 | 
			
		||||
 | 
			
		||||
	// Set ports, allowing A and B to be swapped
 | 
			
		||||
	choice <IdString> A {\A, \B}
 | 
			
		||||
	define <IdString> B (A == \A ? \B : \A)
 | 
			
		||||
	set add_a port(add, A)
 | 
			
		||||
	set add_b port(add, B)
 | 
			
		||||
	set add_y port(add, \Y)
 | 
			
		||||
 | 
			
		||||
	// Get signedness
 | 
			
		||||
	set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED)
 | 
			
		||||
 | 
			
		||||
	// Choice ids
 | 
			
		||||
	set add_a_id A
 | 
			
		||||
	set add_b_id B
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
code add_y add_a add_b
 | 
			
		||||
code add_y add_a add_b add_a_ext
 | 
			
		||||
	// Get adder signals
 | 
			
		||||
	add_a = port(add, \A);
 | 
			
		||||
	add_b = port(add, \B);
 | 
			
		||||
	add_y = port(add, \Y);
 | 
			
		||||
	add_a_ext = SigSpec(port(add, add_a_id));
 | 
			
		||||
	add_a_ext.extend_u0(GetSize(add_y), add_a_signed.as_bool());
 | 
			
		||||
 | 
			
		||||
	// Fanout of each adder Y bit should be 1 (no bit-split)
 | 
			
		||||
	for (auto bit : add_y)
 | 
			
		||||
		if (nusers(bit) != 2)
 | 
			
		||||
			reject;
 | 
			
		||||
 | 
			
		||||
	// A and B can be interchanged
 | 
			
		||||
	branch;
 | 
			
		||||
	std::swap(add_a, add_b);
 | 
			
		||||
	if (nusers(add_y) != 2)
 | 
			
		||||
		reject;
 | 
			
		||||
endcode
 | 
			
		||||
 | 
			
		||||
match mux
 | 
			
		||||
	// Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH
 | 
			
		||||
match mux 
 | 
			
		||||
	// Select mux of form: s ? (a + b) : a
 | 
			
		||||
	// Allow leading 0s when A_WIDTH != Y_WIDTH or s ? a : (a + b)
 | 
			
		||||
	select mux->type == $mux
 | 
			
		||||
	index <SigSpec> port(mux, \A) === SigSpec({Const(State::S0, GetSize(add_y)-GetSize(add_a)), add_a})
 | 
			
		||||
	index <SigSpec> port(mux, \B) === add_y
 | 
			
		||||
	choice <IdString> AB {\A, \B}
 | 
			
		||||
	define <IdString> BA (AB == \A ? \B : \A)
 | 
			
		||||
	set mux_y port(mux, \Y)
 | 
			
		||||
	set mux_a port(mux, AB)
 | 
			
		||||
	set mux_b port(mux, BA)
 | 
			
		||||
	set mux_a_id AB
 | 
			
		||||
	set mux_b_id BA
 | 
			
		||||
	index <SigSpec> port(mux, AB) === add_a_ext
 | 
			
		||||
	index <SigSpec> port(mux, BA) === add_y
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
code
 | 
			
		||||
code add_y add_a add_b add_a_ext add_a_id add_b_id  mux_y mux_a mux_b mux_a_id mux_b_id
 | 
			
		||||
	// Get mux signal
 | 
			
		||||
	SigSpec mux_y = port(mux, \Y);
 | 
			
		||||
	SigSpec mid; 
 | 
			
		||||
	std::string adder_y_name;
 | 
			
		||||
	if (add_y.is_wire()) 
 | 
			
		||||
		adder_y_name = add_y.as_wire()->name.c_str();
 | 
			
		||||
	else
 | 
			
		||||
		adder_y_name = add_y.as_string();
 | 
			
		||||
 | 
			
		||||
	// SILIMATE: Alias cell to mux for mid wire
 | 
			
		||||
	Cell *cell = mux;
 | 
			
		||||
	// Start by renaming the LHS of an eventual assign statement
 | 
			
		||||
	// where the RHS is the adder output (that is getting rewired).
 | 
			
		||||
	// Renaming the signal allows equiv_opt to function as it would
 | 
			
		||||
	// otherwise try to match the functionality which would fail
 | 
			
		||||
	// as the LHS signal has indeed changed function.
 | 
			
		||||
 | 
			
		||||
	// Adder output could be assigned
 | 
			
		||||
	for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
 | 
			
		||||
		RTLIL::SigSpec rhs = it->second;
 | 
			
		||||
		if (rhs.is_wire()) {
 | 
			
		||||
			const std::string& rhs_name = rhs.as_wire()->name.c_str();
 | 
			
		||||
			if (rhs_name == adder_y_name) {
 | 
			
		||||
				RTLIL::SigSpec lhs = it->first;
 | 
			
		||||
				if (lhs.is_wire()) {
 | 
			
		||||
					const std::string& lhs_name =  lhs.as_wire()->name.c_str();
 | 
			
		||||
					module->rename(lhs_name, module->uniquify("$" + lhs_name));
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Alternatively, the port name could be a wire name
 | 
			
		||||
	if (add_y.is_wire()) {
 | 
			
		||||
		if (GetSize(adder_y_name)) {
 | 
			
		||||
			if (adder_y_name[0] != '$') {
 | 
			
		||||
				module->rename(adder_y_name, module->uniquify("$" + adder_y_name));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (auto chunk : add_y.chunks()) {
 | 
			
		||||
			if (chunk.is_wire()) {
 | 
			
		||||
				const std::string& name = chunk.wire->name.c_str();
 | 
			
		||||
				if (name[0] != '$') {
 | 
			
		||||
					module->rename(name, module->uniquify("$" + name));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create new mid wire
 | 
			
		||||
	SigSpec mid = module->addWire(NEW_ID2_SUFFIX("mid"), GetSize(add_b)); // SILIMATE: Improve the naming
 | 
			
		||||
	mid = module->addWire(NEW_ID, GetSize(add_b));
 | 
			
		||||
 | 
			
		||||
	// Rewire
 | 
			
		||||
	mux->setPort(\A, Const(State::S0, GetSize(add_b)));
 | 
			
		||||
	mux->setPort(\B, add_b);
 | 
			
		||||
	// Connect ports
 | 
			
		||||
	add->setPort(add_b_id, mid);
 | 
			
		||||
	add->setPort(add_a_id, add_a);
 | 
			
		||||
	add->setPort(\Y, add_y);
 | 
			
		||||
	mux->setPort(mux_a_id, Const(State::S0, GetSize(add_b)));
 | 
			
		||||
	mux->setPort(mux_b_id, add_b);
 | 
			
		||||
	mux->setPort(\Y, mid);
 | 
			
		||||
	add->setPort(\B, mid);
 | 
			
		||||
	add->setPort(\Y, mux_y);
 | 
			
		||||
	module->connect(mux_y, add_y);
 | 
			
		||||
 | 
			
		||||
	// Log, fixup, accept
 | 
			
		||||
	log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add));
 | 
			
		||||
	add->fixup_parameters();
 | 
			
		||||
	mux->fixup_parameters();
 | 
			
		||||
	did_something = true;
 | 
			
		||||
	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
 | 
			
		||||
							
								
								
									
										378
									
								
								tests/peepopt/muxadd.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								tests/peepopt/muxadd.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,378 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
        assign y = s ? (a + b) : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern with intermediate var gets transformed (a,b module inputs)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern gets transformed (a is driven by a cell)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a_, b, s, y);
 | 
			
		||||
	input wire [3:0] a_;
 | 
			
		||||
	wire [3:0] a = ~a_;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test basic s?(a+b):a pattern gets transformed (b is driven by a cell, output consumed by a cell)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b_, f, s, y_);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b_;
 | 
			
		||||
	input wire [3:0] f;
 | 
			
		||||
	wire [3:0] b = b_ ^ f;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [3:0] y;
 | 
			
		||||
	output wire [3:0] y_;
 | 
			
		||||
	assign y_ = ~y;
 | 
			
		||||
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test no transform when a+b has more fanouts (module output)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, ab, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [2:0] b;
 | 
			
		||||
	output wire [2:0] ab;
 | 
			
		||||
	output wire [2:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	assign ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
log -pop
 | 
			
		||||
 | 
			
		||||
log -header "Test no transform when a+b has more fanouts (single bit, cell)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y, z);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [2:0] b;
 | 
			
		||||
	output wire [2:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [2:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
	output wire [2:0] z = !ab[1];
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test no transform when a+b width smaller than a's width"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [2:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test no transform when (a+b) wider than a, adder’s a input is unsigned, a is not padded with zeros on the muxes input"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : {a[2], a};
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test no transform when (a+b) wider than a, adder’s a input is signed, a is not sign-extended on the muxes input"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [3:0] ab = $signed(a) + $signed(b);
 | 
			
		||||
	assign y = s ? ab : {1'b0, a};
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test no transform when adder and mux not connected together but otherwise fitting transform. criteria"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	wire [3:0] ab_ = !a;
 | 
			
		||||
	assign y = s ? ab_ : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-none t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when (a+b) wider than a, adder’s a input is unsigned, a padded with zeros on the muxes input"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : {1'b0, a};
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when (a+b) wider than a, adder’s a input is signed, a sign-extended on the muxes input"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [3:0] ab = $signed(a) + $signed(b);
 | 
			
		||||
	assign y = s ? ab : {a[2], a};
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when pattern is s?a:(a+b)"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? a : ab;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when pattern is a?(b+a):a"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [3:0] ab = b + a;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when widths b > (a+b) > a"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [4:0] b;
 | 
			
		||||
	output wire [3:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [3:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when widths (a+b) > a > b"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [2:0] a;
 | 
			
		||||
	input wire [3:0] b;
 | 
			
		||||
	output wire [4:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [4:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
 | 
			
		||||
log -pop
 | 
			
		||||
log -header "Test transform when widths (a+b) > b > a"
 | 
			
		||||
log -push
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module top(a, b, s, y);
 | 
			
		||||
	input wire [3:0] a;
 | 
			
		||||
	input wire [2:0] b;
 | 
			
		||||
	output wire [4:0] y;
 | 
			
		||||
	input wire s;
 | 
			
		||||
	wire signed [4:0] ab = a + b;
 | 
			
		||||
	assign y = s ? ab : a;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
check -assert
 | 
			
		||||
wreduce
 | 
			
		||||
opt_clean
 | 
			
		||||
equiv_opt -assert peepopt -withmuxadd
 | 
			
		||||
design -load postopt
 | 
			
		||||
select -assert-any t:$add %co1 %a w:y %i # assert adder rewired
 | 
			
		||||
							
								
								
									
										6
									
								
								tests/peepopt/run-test.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								tests/peepopt/run-test.sh
									
										
									
									
									
										Executable 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