mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into eddie/cleanup
This commit is contained in:
		
						commit
						e6d5147214
					
				
					 19 changed files with 880 additions and 384 deletions
				
			
		|  | @ -17,6 +17,8 @@ Yosys 0.9 .. Yosys 0.9-dev | |||
|     - Added automatic gzip decompression for frontends | ||||
|     - Added $_NMUX_ cell type | ||||
|     - Added automatic gzip compression (based on filename extension) for backends | ||||
|     - Improve attribute and parameter encoding in JSON to avoid ambiguities between | ||||
|       bit vectors and strings containing [01xz]* | ||||
| 
 | ||||
| Yosys 0.8 .. Yosys 0.8-dev | ||||
| -------------------------- | ||||
|  |  | |||
|  | @ -381,10 +381,10 @@ struct FirrtlWorker | |||
| 
 | ||||
| 	// Given an expression for a shift amount, and a maximum width,
 | ||||
| 	//  generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
 | ||||
| 	std::string gen_dshl(const string b_expr, const int b_padded_width) | ||||
| 	std::string gen_dshl(const string b_expr, const int b_width) | ||||
| 	{ | ||||
| 		string result = b_expr; | ||||
| 		if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { | ||||
| 		if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { | ||||
| 			int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; | ||||
| 			string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1); | ||||
| 			// Deal with the difference in semantics between FIRRTL and verilog
 | ||||
|  | @ -422,22 +422,33 @@ struct FirrtlWorker | |||
| 
 | ||||
| 		for (auto cell : module->cells()) | ||||
| 		{ | ||||
| 			bool extract_y_bits = false;		// Assume no extraction of final bits will be required.
 | ||||
| 			static Const ndef(0, 0); | ||||
| 
 | ||||
| 		    // Is this cell is a module instance?
 | ||||
| 			if (cell->type[0] != '$') | ||||
| 			{ | ||||
| 				process_instance(cell, wire_exprs); | ||||
| 				continue; | ||||
| 			} | ||||
| 			// Not a module instance. Set up cell properties
 | ||||
| 			bool extract_y_bits = false;		// Assume no extraction of final bits will be required.
 | ||||
| 			int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int();	// The width of "A"
 | ||||
| 			int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int();	// The width of "A"
 | ||||
| 			const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int();	// The width of the result
 | ||||
| 			const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool(); | ||||
| 			const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool(); | ||||
| 			bool firrtl_is_signed = a_signed;	// The result is signed (subsequent code may change this).
 | ||||
| 			int firrtl_width = 0; | ||||
| 			string primop; | ||||
| 			bool always_uint = false; | ||||
| 			string y_id = make_id(cell->name); | ||||
| 
 | ||||
| 			if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor")) | ||||
| 			{ | ||||
| 				string y_id = make_id(cell->name); | ||||
| 				bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); | ||||
| 				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int(); | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width)); | ||||
| 
 | ||||
| 				if (cell->parameters.at("\\A_SIGNED").as_bool()) { | ||||
| 				if (a_signed) { | ||||
| 					a_expr = "asSInt(" + a_expr + ")"; | ||||
| 				} | ||||
| 
 | ||||
|  | @ -446,12 +457,13 @@ struct FirrtlWorker | |||
| 					a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); | ||||
| 				} | ||||
| 
 | ||||
| 				string primop; | ||||
| 				bool always_uint = false; | ||||
| 				// Assume the FIRRTL width is a single bit.
 | ||||
| 				firrtl_width = 1; | ||||
| 				if (cell->type == "$not") primop = "not"; | ||||
| 				else if (cell->type == "$neg") { | ||||
| 					primop = "neg"; | ||||
| 					is_signed = true;	// Result of "neg" is signed (an SInt).
 | ||||
| 					firrtl_is_signed = true;	// Result of "neg" is signed (an SInt).
 | ||||
| 					firrtl_width = a_width; | ||||
| 				} else if (cell->type == "$logic_not") { | ||||
|                                         primop = "eq"; | ||||
|                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str()); | ||||
|  | @ -466,14 +478,12 @@ struct FirrtlWorker | |||
| 				else if (cell->type == "$reduce_bool") { | ||||
| 					primop = "neq"; | ||||
| 					// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
 | ||||
| 					bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); | ||||
| 					int a_width =  cell->parameters.at("\\A_WIDTH").as_int(); | ||||
| 					a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); | ||||
| 				} | ||||
| 
 | ||||
| 				string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); | ||||
| 
 | ||||
| 				if ((is_signed && !always_uint)) | ||||
| 				if ((firrtl_is_signed && !always_uint)) | ||||
| 					expr = stringf("asUInt(%s)", expr.c_str()); | ||||
| 
 | ||||
| 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str())); | ||||
|  | @ -481,80 +491,120 @@ struct FirrtlWorker | |||
| 
 | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", | ||||
| 			if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx", | ||||
| 							  "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", | ||||
| 							  "$logic_and", "$logic_or")) | ||||
| 							  "$logic_and", "$logic_or", "$pow")) | ||||
| 			{ | ||||
| 				string y_id = make_id(cell->name); | ||||
| 				bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); | ||||
| 				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int(); | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				string b_expr = make_expr(cell->getPort("\\B")); | ||||
| 				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); | ||||
| 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width)); | ||||
| 
 | ||||
| 				if (cell->parameters.at("\\A_SIGNED").as_bool()) { | ||||
| 				if (a_signed) { | ||||
| 					a_expr = "asSInt(" + a_expr + ")"; | ||||
| 					// Expand the "A" operand to the result width
 | ||||
| 					if (a_width < y_width) { | ||||
| 						a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); | ||||
| 						a_width = y_width; | ||||
| 					} | ||||
| 				// Shift amount is always unsigned, and needn't be padded to result width.
 | ||||
| 				if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) { | ||||
| 					if (cell->parameters.at("\\B_SIGNED").as_bool()) { | ||||
| 				} | ||||
| 				// Shift amount is always unsigned, and needn't be padded to result width,
 | ||||
| 				//  otherwise, we need to cast the b_expr appropriately
 | ||||
| 				if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) { | ||||
| 					b_expr = "asSInt(" + b_expr + ")"; | ||||
| 					} | ||||
| 					if (b_padded_width < y_width) { | ||||
| 						auto b_sig = cell->getPort("\\B"); | ||||
| 						b_padded_width = y_width; | ||||
| 					// Expand the "B" operand to the result width
 | ||||
| 					if (b_width < y_width) { | ||||
| 						b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); | ||||
| 						b_width = y_width; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				// For the arithmetic ops, expand operand widths to result widths befor performing the operation.
 | ||||
| 				// This corresponds (according to iverilog) to what verilog compilers implement.
 | ||||
| 				if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or")) | ||||
| 				{ | ||||
| 					if (a_width < y_width) { | ||||
| 						a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); | ||||
| 						a_width = y_width; | ||||
| 					} | ||||
| 					if (b_width < y_width) { | ||||
| 						b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); | ||||
| 						b_width = y_width; | ||||
| 					} | ||||
| 				} | ||||
| 				// Assume the FIRRTL width is the width of "A"
 | ||||
| 				firrtl_width = a_width; | ||||
| 				auto a_sig = cell->getPort("\\A"); | ||||
| 
 | ||||
| 				if (cell->parameters.at("\\A_SIGNED").as_bool()  & (cell->type == "$shr")) { | ||||
| 					a_expr = "asUInt(" + a_expr + ")"; | ||||
| 				} | ||||
| 
 | ||||
| 				string primop; | ||||
| 				bool always_uint = false; | ||||
| 				if (cell->type == "$add") primop = "add"; | ||||
| 				else if (cell->type == "$sub") primop = "sub"; | ||||
| 				else if (cell->type == "$mul") primop = "mul"; | ||||
| 				else if (cell->type == "$div") primop = "div"; | ||||
| 				else if (cell->type == "$mod") primop = "rem"; | ||||
| 				else if (cell->type == "$and") { | ||||
| 				if (cell->type == "$add") { | ||||
| 					primop = "add"; | ||||
| 					firrtl_is_signed = a_signed | b_signed; | ||||
| 					firrtl_width = max(a_width, b_width); | ||||
| 				} else if (cell->type == "$sub") { | ||||
| 					primop = "sub"; | ||||
| 					firrtl_is_signed = true; | ||||
| 					int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0; | ||||
| 					int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0; | ||||
| 					firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc); | ||||
| 				} else if (cell->type == "$mul") { | ||||
| 					primop = "mul"; | ||||
| 					firrtl_is_signed = a_signed | b_signed; | ||||
| 					firrtl_width = a_width + b_width; | ||||
| 				} else if (cell->type == "$div") { | ||||
| 					primop = "div"; | ||||
| 					firrtl_is_signed = a_signed | b_signed; | ||||
| 					firrtl_width = a_width; | ||||
| 				} else if (cell->type == "$mod") { | ||||
| 					primop = "rem"; | ||||
| 					firrtl_width = min(a_width, b_width); | ||||
| 				} else if (cell->type == "$and") { | ||||
| 					primop = "and"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = max(a_width, b_width); | ||||
| 				} | ||||
| 				else if (cell->type == "$or" ) { | ||||
| 					primop =  "or"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = max(a_width, b_width); | ||||
| 				} | ||||
| 				else if (cell->type == "$xor") { | ||||
| 					primop = "xor"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = max(a_width, b_width); | ||||
| 				} | ||||
| 				else if (cell->type == "$xnor") { | ||||
| 					primop = "xnor"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = max(a_width, b_width); | ||||
| 				} | ||||
| 				else if ((cell->type == "$eq") | (cell->type == "$eqx")) { | ||||
| 					primop = "eq"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 			    } | ||||
| 				else if ((cell->type == "$ne") | (cell->type == "$nex")) { | ||||
| 					primop = "neq"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if (cell->type == "$gt") { | ||||
| 					primop = "gt"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if (cell->type == "$ge") { | ||||
| 					primop = "geq"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if (cell->type == "$lt") { | ||||
| 					primop = "lt"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if (cell->type == "$le") { | ||||
| 					primop = "leq"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if ((cell->type == "$shl") | (cell->type == "$sshl")) { | ||||
| 					// FIRRTL will widen the result (y) by the amount of the shift.
 | ||||
|  | @ -564,11 +614,14 @@ struct FirrtlWorker | |||
| 					auto b_sig = cell->getPort("\\B"); | ||||
| 					if (b_sig.is_fully_const()) { | ||||
| 						primop = "shl"; | ||||
| 						b_expr = std::to_string(b_sig.as_int()); | ||||
| 						int shift_amount = b_sig.as_int(); | ||||
| 						b_expr = std::to_string(shift_amount); | ||||
| 						firrtl_width = a_width + shift_amount; | ||||
| 					} else { | ||||
| 						primop = "dshl"; | ||||
| 						// Convert from FIRRTL left shift semantics.
 | ||||
| 						b_expr = gen_dshl(b_expr, b_padded_width); | ||||
| 						b_expr = gen_dshl(b_expr, b_width); | ||||
| 						firrtl_width = a_width + (1 << b_width) - 1; | ||||
| 					} | ||||
| 				} | ||||
| 				else if ((cell->type == "$shr") | (cell->type == "$sshr")) { | ||||
|  | @ -578,9 +631,19 @@ struct FirrtlWorker | |||
| 					auto b_sig = cell->getPort("\\B"); | ||||
| 					if (b_sig.is_fully_const()) { | ||||
| 						primop = "shr"; | ||||
| 						b_expr = std::to_string(b_sig.as_int()); | ||||
| 						int shift_amount = b_sig.as_int(); | ||||
| 						b_expr = std::to_string(shift_amount); | ||||
| 						firrtl_width = max(1, a_width - shift_amount); | ||||
| 					} else { | ||||
| 						primop = "dshr"; | ||||
| 						firrtl_width = a_width; | ||||
| 					} | ||||
| 					// We'll need to do some special fixups if the source (and thus result) is signed.
 | ||||
| 					if (firrtl_is_signed) { | ||||
| 						// If this is a "logical" shift right, pretend the source is unsigned.
 | ||||
| 						if (cell->type == "$shr") { | ||||
| 							a_expr = "asUInt(" + a_expr + ")"; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				else if ((cell->type == "$logic_and")) { | ||||
|  | @ -588,26 +651,66 @@ struct FirrtlWorker | |||
| 					a_expr = "neq(" + a_expr + ", UInt(0))"; | ||||
| 					b_expr = "neq(" + b_expr + ", UInt(0))"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if ((cell->type == "$logic_or")) { | ||||
| 					primop = "or"; | ||||
| 					a_expr = "neq(" + a_expr + ", UInt(0))"; | ||||
| 					b_expr = "neq(" + b_expr + ", UInt(0))"; | ||||
| 					always_uint = true; | ||||
| 					firrtl_width = 1; | ||||
| 				} | ||||
| 				else if ((cell->type == "$pow")) { | ||||
| 					if (a_sig.is_fully_const() && a_sig.as_int() == 2) { | ||||
| 						// We'll convert this to a shift. To simplify things, change the a_expr to "1"
 | ||||
| 						//	so we can use b_expr directly as a shift amount.
 | ||||
| 						// Only support 2 ** N (i.e., shift left)
 | ||||
| 						// FIRRTL will widen the result (y) by the amount of the shift.
 | ||||
| 						// We'll need to offset this by extracting the un-widened portion as Verilog would do.
 | ||||
| 						a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)"; | ||||
| 						extract_y_bits = true; | ||||
| 						// Is the shift amount constant?
 | ||||
| 						auto b_sig = cell->getPort("\\B"); | ||||
| 						if (b_sig.is_fully_const()) { | ||||
| 							primop = "shl"; | ||||
| 							int shiftAmount = b_sig.as_int(); | ||||
| 							if (shiftAmount < 0) { | ||||
| 								log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell)); | ||||
| 							} | ||||
| 							b_expr = std::to_string(shiftAmount); | ||||
| 							firrtl_width = a_width + shiftAmount; | ||||
| 						} else { | ||||
| 							primop = "dshl"; | ||||
| 							// Convert from FIRRTL left shift semantics.
 | ||||
| 							b_expr = gen_dshl(b_expr, b_width); | ||||
| 							firrtl_width = a_width + (1 << b_width) - 1; | ||||
| 						} | ||||
| 					} else { | ||||
| 						log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell)); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				if (!cell->parameters.at("\\B_SIGNED").as_bool()) { | ||||
| 					b_expr = "asUInt(" + b_expr + ")"; | ||||
| 				} | ||||
| 
 | ||||
| 				string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); | ||||
| 
 | ||||
| 				// Deal with FIRRTL's "shift widens" semantics
 | ||||
| 				if (extract_y_bits) { | ||||
| 					expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); | ||||
| 				string expr; | ||||
| 				// Deal with $xnor == ~^ (not xor)
 | ||||
| 				if (primop == "xnor") { | ||||
| 					expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); | ||||
| 				} else { | ||||
| 					expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); | ||||
| 				} | ||||
| 
 | ||||
| 				if ((is_signed && !always_uint) || cell->type.in("$sub")) | ||||
| 				// Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
 | ||||
| 				// If the operation is signed, the FIRRTL width will be 1 one bit larger.
 | ||||
| 				if (extract_y_bits) { | ||||
| 					expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); | ||||
| 				} else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { | ||||
| 					expr = stringf("pad(%s, %d)", expr.c_str(), y_width); | ||||
| 				} | ||||
| 
 | ||||
| 				if ((firrtl_is_signed && !always_uint)) | ||||
| 					expr = stringf("asUInt(%s)", expr.c_str()); | ||||
| 
 | ||||
| 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str())); | ||||
|  | @ -618,7 +721,6 @@ struct FirrtlWorker | |||
| 
 | ||||
| 			if (cell->type.in("$mux")) | ||||
| 			{ | ||||
| 				string y_id = make_id(cell->name); | ||||
| 				int width = cell->parameters.at("\\WIDTH").as_int(); | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				string b_expr = make_expr(cell->getPort("\\B")); | ||||
|  | @ -762,15 +864,14 @@ struct FirrtlWorker | |||
| 				if (clkpol == false) | ||||
| 					log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); | ||||
| 
 | ||||
| 				string q_id = make_id(cell->name); | ||||
| 				int width = cell->parameters.at("\\WIDTH").as_int(); | ||||
| 				string expr = make_expr(cell->getPort("\\D")); | ||||
| 				string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")"; | ||||
| 
 | ||||
| 				wire_decls.push_back(stringf("    reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str())); | ||||
| 				wire_decls.push_back(stringf("    reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str())); | ||||
| 
 | ||||
| 				cell_exprs.push_back(stringf("    %s <= %s\n", q_id.c_str(), expr.c_str())); | ||||
| 				register_reverse_wire_map(q_id, cell->getPort("\\Q")); | ||||
| 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str())); | ||||
| 				register_reverse_wire_map(y_id, cell->getPort("\\Q")); | ||||
| 
 | ||||
| 				continue; | ||||
| 			} | ||||
|  | @ -785,8 +886,6 @@ struct FirrtlWorker | |||
| 				// assign y = a[b +: y_width];
 | ||||
| 				// We'll extract the correct bits as part of the primop.
 | ||||
| 
 | ||||
| 				string y_id = make_id(cell->name); | ||||
| 				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int(); | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				// Get the initial bit selector
 | ||||
| 				string b_expr = make_expr(cell->getPort("\\B")); | ||||
|  | @ -808,18 +907,15 @@ struct FirrtlWorker | |||
| 				// assign y = a >> b;
 | ||||
| 				//  where b may be negative
 | ||||
| 
 | ||||
| 				string y_id = make_id(cell->name); | ||||
| 				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int(); | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				string b_expr = make_expr(cell->getPort("\\B")); | ||||
| 				auto b_string = b_expr.c_str(); | ||||
| 				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); | ||||
| 				string expr; | ||||
| 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width)); | ||||
| 
 | ||||
| 				if (cell->getParam("\\B_SIGNED").as_bool()) { | ||||
| 					// We generate a left or right shift based on the sign of b.
 | ||||
| 					std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width); | ||||
| 					std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width); | ||||
| 					std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); | ||||
| 					expr = stringf("mux(%s < 0, %s, %s)", | ||||
| 									 b_string, | ||||
|  | @ -833,6 +929,20 @@ struct FirrtlWorker | |||
| 				register_reverse_wire_map(y_id, cell->getPort("\\Y")); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (cell->type == "$pos") { | ||||
| 				// assign y = a;
 | ||||
| //				printCell(cell);
 | ||||
| 				string a_expr = make_expr(cell->getPort("\\A")); | ||||
| 				// Verilog appears to treat the result as signed, so if the result is wider than "A",
 | ||||
| 				//  we need to pad.
 | ||||
| 				if (a_width < y_width) { | ||||
| 					a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); | ||||
| 				} | ||||
| 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width)); | ||||
| 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), a_expr.c_str())); | ||||
| 				register_reverse_wire_map(y_id, cell->getPort("\\Y")); | ||||
| 				continue; | ||||
| 			} | ||||
| 			log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -83,20 +83,43 @@ struct JsonWriter | |||
| 		return str + " ]"; | ||||
| 	} | ||||
| 
 | ||||
| 	void write_parameter_value(const Const &value) | ||||
| 	{ | ||||
| 		if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { | ||||
| 			string str = value.decode_string(); | ||||
| 			int state = 0; | ||||
| 			for (char c : str) { | ||||
| 				if (state == 0) { | ||||
| 					if (c == '0' || c == '1' || c == 'x' || c == 'z') | ||||
| 						state = 0; | ||||
| 					else if (c == ' ') | ||||
| 						state = 1; | ||||
| 					else | ||||
| 						state = 2; | ||||
| 				} else if (state == 1 && c != ' ') | ||||
| 					state = 2; | ||||
| 			} | ||||
| 			if (state < 2) | ||||
| 				str += " "; | ||||
| 			f << get_string(str); | ||||
| 		} else | ||||
| 		if (GetSize(value) == 32 && value.is_fully_def()) { | ||||
| 			if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) | ||||
| 				f << stringf("%d", value.as_int()); | ||||
| 			else | ||||
| 				f << stringf("%u", value.as_int()); | ||||
| 		} else { | ||||
| 			f << get_string(value.as_string()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void write_parameters(const dict<IdString, Const> ¶meters, bool for_module=false) | ||||
| 	{ | ||||
| 		bool first = true; | ||||
| 		for (auto ¶m : parameters) { | ||||
| 			f << stringf("%s\n", first ? "" : ","); | ||||
| 			f << stringf("        %s%s: ", for_module ? "" : "    ", get_name(param.first).c_str()); | ||||
| 			if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) | ||||
| 				f << get_string(param.second.decode_string()); | ||||
| 			else if (GetSize(param.second.bits) > 32) | ||||
| 				f << get_string(param.second.as_string()); | ||||
| 			else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) | ||||
| 				f << stringf("%d", param.second.as_int()); | ||||
| 			else | ||||
| 				f << stringf("%u", param.second.as_int()); | ||||
| 			write_parameter_value(param.second); | ||||
| 			first = false; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -342,12 +365,13 @@ struct JsonBackend : public Backend { | |||
| 		log("Module and cell ports and nets can be single bit wide or vectors of multiple\n"); | ||||
| 		log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n"); | ||||
| 		log("values referenced above are vectors of this integers. Signal bits that are\n"); | ||||
| 		log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n"); | ||||
| 		log("a number.\n"); | ||||
| 		log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n"); | ||||
| 		log("\"z\" instead of a number.\n"); | ||||
| 		log("\n"); | ||||
| 		log("Numeric parameter and attribute values up to 32 bits are written as decimal\n"); | ||||
| 		log("values. Numbers larger than that are written as string holding the binary\n"); | ||||
| 		log("representation of the value.\n"); | ||||
| 		log("Numeric 32-bit parameter and attribute values are written as decimal values.\n"); | ||||
| 		log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n"); | ||||
| 		log("as string holding the binary representation of the value. Strings are written\n"); | ||||
| 		log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n"); | ||||
| 		log("\n"); | ||||
| 		log("For example the following Verilog code:\n"); | ||||
| 		log("\n"); | ||||
|  |  | |||
|  | @ -3439,19 +3439,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) | |||
| { | ||||
| 	std::map<std::string, AstNode*> backup_scope; | ||||
| 	std::map<std::string, AstNode::varinfo_t> variables; | ||||
| 	bool delete_temp_block = false; | ||||
| 	AstNode *block = NULL; | ||||
| 	AstNode *block = new AstNode(AST_BLOCK); | ||||
| 
 | ||||
| 	size_t argidx = 0; | ||||
| 	for (auto child : children) | ||||
| 	{ | ||||
| 		if (child->type == AST_BLOCK) | ||||
| 		{ | ||||
| 			log_assert(block == NULL); | ||||
| 			block = child; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (child->type == AST_WIRE) | ||||
| 		{ | ||||
| 			while (child->simplify(true, false, false, 1, -1, false, true)) { } | ||||
|  | @ -3468,13 +3460,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) | |||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		log_assert(block == NULL); | ||||
| 		delete_temp_block = true; | ||||
| 		block = new AstNode(AST_BLOCK); | ||||
| 		block->children.push_back(child->clone()); | ||||
| 	} | ||||
| 
 | ||||
| 	log_assert(block != NULL); | ||||
| 	log_assert(variables.count(str) != 0); | ||||
| 
 | ||||
| 	while (!block->children.empty()) | ||||
|  | @ -3642,7 +3630,6 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) | |||
| 		log_abort(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (delete_temp_block) | ||||
| 	delete block; | ||||
| 
 | ||||
| 	for (auto &it : backup_scope) | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ struct JsonNode | |||
| { | ||||
| 	char type; // S=String, N=Number, A=Array, D=Dict
 | ||||
| 	string data_string; | ||||
| 	int data_number; | ||||
| 	int64_t data_number; | ||||
| 	vector<JsonNode*> data_array; | ||||
| 	dict<string, JsonNode*> data_dict; | ||||
| 	vector<string> data_dict_keys; | ||||
|  | @ -206,6 +206,38 @@ struct JsonNode | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| Const json_parse_attr_param_value(JsonNode *node) | ||||
| { | ||||
| 	Const value; | ||||
| 
 | ||||
| 	if (node->type == 'S') { | ||||
| 		string &s = node->data_string; | ||||
| 		size_t cursor = s.find_first_not_of("01xz"); | ||||
| 		if (cursor == string::npos) { | ||||
| 			value = Const::from_string(s); | ||||
| 		} else if (s.find_first_not_of(' ', cursor) == string::npos) { | ||||
| 			value = Const(s.substr(0, GetSize(s)-1)); | ||||
| 		} else { | ||||
| 			value = Const(s); | ||||
| 		} | ||||
| 	} else | ||||
| 	if (node->type == 'N') { | ||||
| 		value = Const(node->data_number, 32); | ||||
| 		if (node->data_number < 0) | ||||
| 			value.flags |= RTLIL::CONST_FLAG_SIGNED; | ||||
| 	} else | ||||
| 	if (node->type == 'A') { | ||||
| 		log_error("JSON attribute or parameter value is an array.\n"); | ||||
| 	} else | ||||
| 	if (node->type == 'D') { | ||||
| 		log_error("JSON attribute or parameter value is a dict.\n"); | ||||
| 	} else { | ||||
| 		log_abort(); | ||||
| 	} | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
| void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node) | ||||
| { | ||||
| 	if (node->type != 'D') | ||||
|  | @ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node) | |||
| 	for (auto it : node->data_dict) | ||||
| 	{ | ||||
| 		IdString key = RTLIL::escape_id(it.first.c_str()); | ||||
| 		JsonNode *value_node = it.second; | ||||
| 		Const value; | ||||
| 
 | ||||
| 		if (value_node->type == 'S') { | ||||
| 			string &s = value_node->data_string; | ||||
| 			if (s.find_first_not_of("01xz") == string::npos) | ||||
| 				value = Const::from_string(s); | ||||
| 			else | ||||
| 				value = Const(s); | ||||
| 		} else | ||||
| 		if (value_node->type == 'N') { | ||||
| 			value = Const(value_node->data_number, 32); | ||||
| 		} else | ||||
| 		if (value_node->type == 'A') { | ||||
| 			log_error("JSON attribute or parameter value is an array.\n"); | ||||
| 		} else | ||||
| 		if (value_node->type == 'D') { | ||||
| 			log_error("JSON attribute or parameter value is a dict.\n"); | ||||
| 		} else { | ||||
| 			log_abort(); | ||||
| 		} | ||||
| 
 | ||||
| 		Const value = json_parse_attr_param_value(it.second); | ||||
| 		results[key] = value; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -24,12 +24,10 @@ | |||
| 
 | ||||
| YOSYS_NAMESPACE_BEGIN | ||||
| 
 | ||||
| int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false); | ||||
| 
 | ||||
| inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(), | ||||
| 		RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false) | ||||
| struct CellCosts | ||||
| { | ||||
| 	static dict<RTLIL::IdString, int> gate_cost = { | ||||
| 	static const dict<RTLIL::IdString, int>& default_gate_cost() { | ||||
| 		static const dict<RTLIL::IdString, int> db = { | ||||
| 			{ "$_BUF_",    1 }, | ||||
| 			{ "$_NOT_",    2 }, | ||||
| 			{ "$_AND_",    4 }, | ||||
|  | @ -38,18 +36,20 @@ inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL | |||
| 			{ "$_NOR_",    4 }, | ||||
| 			{ "$_ANDNOT_", 4 }, | ||||
| 			{ "$_ORNOT_",  4 }, | ||||
| 		{ "$_XOR_",    8 }, | ||||
| 		{ "$_XNOR_",   8 }, | ||||
| 			{ "$_XOR_",    5 }, | ||||
| 			{ "$_XNOR_",   5 }, | ||||
| 			{ "$_AOI3_",   6 }, | ||||
| 			{ "$_OAI3_",   6 }, | ||||
| 		{ "$_AOI4_",   8 }, | ||||
| 		{ "$_OAI4_",   8 }, | ||||
| 			{ "$_AOI4_",   7 }, | ||||
| 			{ "$_OAI4_",   7 }, | ||||
| 			{ "$_MUX_",    4 }, | ||||
| 			{ "$_NMUX_",   4 } | ||||
| 		}; | ||||
| 		return db; | ||||
| 	} | ||||
| 
 | ||||
| 	// match costs in "stat -tech cmos"
 | ||||
| 	static dict<RTLIL::IdString, int> cmos_gate_cost = { | ||||
| 	static const dict<RTLIL::IdString, int>& cmos_gate_cost() { | ||||
| 		static const dict<RTLIL::IdString, int> db = { | ||||
| 			{ "$_BUF_",     1 }, | ||||
| 			{ "$_NOT_",     2 }, | ||||
| 			{ "$_AND_",     6 }, | ||||
|  | @ -67,43 +67,49 @@ inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL | |||
| 			{ "$_MUX_",    12 }, | ||||
| 			{ "$_NMUX_",   10 } | ||||
| 		}; | ||||
| 		return db; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cmos_cost && cmos_gate_cost.count(type)) | ||||
| 		return cmos_gate_cost.at(type); | ||||
| 	dict<RTLIL::IdString, int> mod_cost_cache; | ||||
| 	const dict<RTLIL::IdString, int> *gate_cost = nullptr; | ||||
| 	Design *design = nullptr; | ||||
| 
 | ||||
| 	if (gate_cost.count(type)) | ||||
| 		return gate_cost.at(type); | ||||
| 
 | ||||
| 	if (parameters.empty() && design && design->module(type)) | ||||
| 	int get(RTLIL::IdString type) const | ||||
| 	{ | ||||
| 		RTLIL::Module *mod = design->module(type); | ||||
| 		if (gate_cost && gate_cost->count(type)) | ||||
| 			return gate_cost->at(type); | ||||
| 
 | ||||
| 		log_warning("Can't determine cost of %s cell.\n", log_id(type)); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	int get(RTLIL::Cell *cell) | ||||
| 	{ | ||||
| 		if (gate_cost && gate_cost->count(cell->type)) | ||||
| 			return gate_cost->at(cell->type); | ||||
| 
 | ||||
| 		if (design && design->module(cell->type) && cell->parameters.empty()) | ||||
| 		{ | ||||
| 			RTLIL::Module *mod = design->module(cell->type); | ||||
| 
 | ||||
| 			if (mod->attributes.count("\\cost")) | ||||
| 				return mod->attributes.at("\\cost").as_int(); | ||||
| 
 | ||||
| 		dict<RTLIL::IdString, int> local_mod_cost_cache; | ||||
| 		if (mod_cost_cache == nullptr) | ||||
| 			mod_cost_cache = &local_mod_cost_cache; | ||||
| 
 | ||||
| 		if (mod_cost_cache->count(mod->name)) | ||||
| 			return mod_cost_cache->at(mod->name); | ||||
| 			if (mod_cost_cache.count(mod->name)) | ||||
| 				return mod_cost_cache.at(mod->name); | ||||
| 
 | ||||
| 			int module_cost = 1; | ||||
| 			for (auto c : mod->cells()) | ||||
| 			module_cost += get_cell_cost(c, mod_cost_cache); | ||||
| 				module_cost += get(c); | ||||
| 
 | ||||
| 		(*mod_cost_cache)[mod->name] = module_cost; | ||||
| 			mod_cost_cache[mod->name] = module_cost; | ||||
| 			return module_cost; | ||||
| 		} | ||||
| 
 | ||||
| 	log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); | ||||
| 		log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters)); | ||||
| 		return 1; | ||||
| } | ||||
| 
 | ||||
| inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache, bool cmos_cost) | ||||
| { | ||||
| 	return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache, cmos_cost); | ||||
| } | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| YOSYS_NAMESPACE_END | ||||
| 
 | ||||
|  |  | |||
|  | @ -522,6 +522,12 @@ int main(int argc, char **argv) | |||
| 	if (!backend_command.empty()) | ||||
| 		run_backend(output_filename, backend_command); | ||||
| 
 | ||||
| 	yosys_design->check(); | ||||
| 	for (auto it : saved_designs) | ||||
| 		it.second->check(); | ||||
| 	for (auto it : pushed_designs) | ||||
| 		it->check(); | ||||
| 
 | ||||
| 	if (!depsfile.empty()) | ||||
| 	{ | ||||
| 		FILE *f = fopen(depsfile.c_str(), "wt"); | ||||
|  |  | |||
|  | @ -295,8 +295,6 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args) | |||
| 	pass_register[args[0]]->post_execute(state); | ||||
| 	while (design->selection_stack.size() > orig_sel_stack_pos) | ||||
| 		design->selection_stack.pop_back(); | ||||
| 
 | ||||
| 	design->check(); | ||||
| } | ||||
| 
 | ||||
| void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) | ||||
|  | @ -378,8 +376,10 @@ void ScriptPass::run(std::string command, std::string info) | |||
| 			log("        %s\n", command.c_str()); | ||||
| 		else | ||||
| 			log("        %s    %s\n", command.c_str(), info.c_str()); | ||||
| 	} else | ||||
| 	} else { | ||||
| 		Pass::call(active_design, command); | ||||
| 		active_design->check(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) | ||||
|  | @ -573,8 +573,6 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string | |||
| 			args.push_back(filename); | ||||
| 		frontend_register[args[0]]->execute(args, design); | ||||
| 	} | ||||
| 
 | ||||
| 	design->check(); | ||||
| } | ||||
| 
 | ||||
| Backend::Backend(std::string name, std::string short_help) : | ||||
|  | @ -698,8 +696,6 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f | |||
| 
 | ||||
| 	while (design->selection_stack.size() > orig_sel_stack_pos) | ||||
| 		design->selection_stack.pop_back(); | ||||
| 
 | ||||
| 	design->check(); | ||||
| } | ||||
| 
 | ||||
| static struct CellHelpMessages { | ||||
|  |  | |||
|  | @ -792,6 +792,7 @@ public: | |||
| 	RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; | ||||
| 	RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const; | ||||
| 	RTLIL::SigSpec extract(int offset, int length = 1) const; | ||||
| 	RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } | ||||
| 
 | ||||
| 	void append(const RTLIL::SigSpec &signal); | ||||
| 	void append_bit(const RTLIL::SigBit &bit); | ||||
|  | @ -838,6 +839,7 @@ public: | |||
| 
 | ||||
| 	operator std::vector<RTLIL::SigChunk>() const { return chunks(); } | ||||
| 	operator std::vector<RTLIL::SigBit>() const { return bits(); } | ||||
| 	RTLIL::SigBit at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } | ||||
| 
 | ||||
| 	unsigned int hash() const { if (!hash_) updhash(); return hash_; }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -964,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen | |||
| 					command += next_line; | ||||
| 				} | ||||
| 				handle_label(command, from_to_active, run_from, run_to); | ||||
| 				if (from_to_active) | ||||
| 				if (from_to_active) { | ||||
| 					Pass::call(design, command); | ||||
| 					design->check(); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (!command.empty()) { | ||||
| 				handle_label(command, from_to_active, run_from, run_to); | ||||
| 				if (from_to_active) | ||||
| 				if (from_to_active) { | ||||
| 					Pass::call(design, command); | ||||
| 					design->check(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		catch (...) { | ||||
|  | @ -1000,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen | |||
| 		Pass::call(design, vector<string>({command, filename})); | ||||
| 	else | ||||
| 		Frontend::frontend_call(design, NULL, filename, command); | ||||
| 	design->check(); | ||||
| } | ||||
| 
 | ||||
| void run_frontend(std::string filename, std::string command, RTLIL::Design *design) | ||||
|  | @ -1183,6 +1188,7 @@ void shell(RTLIL::Design *design) | |||
| 				design->selection_stack.pop_back(); | ||||
| 			log_reset_stack(); | ||||
| 		} | ||||
| 		design->check(); | ||||
| 	} | ||||
| 	if (command == NULL) | ||||
| 		printf("exit\n"); | ||||
|  |  | |||
|  | @ -17,11 +17,10 @@ | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/celltypes.h" | ||||
| #include "passes/techmap/libparse.h" | ||||
| 
 | ||||
| #include "kernel/log.h" | ||||
| #include "kernel/cost.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
|  | @ -228,25 +227,16 @@ struct statdata_t | |||
| 		{ | ||||
| 			int tran_cnt = 0; | ||||
| 			bool tran_cnt_exact = true; | ||||
| 			auto &gate_costs = CellCosts::cmos_gate_cost(); | ||||
| 
 | ||||
| 			for (auto it : num_cells_by_type) { | ||||
| 				auto ctype = it.first; | ||||
| 				auto cnum = it.second; | ||||
| 
 | ||||
| 				if (ctype == "$_NOT_") | ||||
| 					tran_cnt += 2*cnum; | ||||
| 				else if (ctype.in("$_NAND_", "$_NOR_")) | ||||
| 					tran_cnt += 4*cnum; | ||||
| 				else if (ctype.in("$_AOI3_", "$_OAI3_")) | ||||
| 					tran_cnt += 6*cnum; | ||||
| 				else if (ctype.in("$_AOI4_", "$_OAI4_")) | ||||
| 					tran_cnt += 8*cnum; | ||||
| 				else if (ctype.in("$_NMUX_")) | ||||
| 					tran_cnt += 10*cnum; | ||||
| 				else if (ctype.in("$_MUX_", "$_XOR_", "$_XNOR_")) | ||||
| 					tran_cnt += 12*cnum; | ||||
| 				if (gate_costs.count(ctype)) | ||||
| 					tran_cnt += cnum * gate_costs.at(ctype); | ||||
| 				else if (ctype.in("$_DFF_P_", "$_DFF_N_")) | ||||
| 					tran_cnt += 16*cnum; | ||||
| 					tran_cnt += cnum * 16; | ||||
| 				else | ||||
| 					tran_cnt_exact = false; | ||||
| 			} | ||||
|  |  | |||
|  | @ -640,6 +640,31 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 					did_something = true; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (cell->type.in("$add", "$sub")) { | ||||
| 				RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); | ||||
| 				RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); | ||||
| 				RTLIL::SigSpec sig_y = cell->getPort("\\Y"); | ||||
| 				bool sub = cell->type == "$sub"; | ||||
| 
 | ||||
| 				int i; | ||||
| 				for (i = 0; i < GetSize(sig_y); i++) { | ||||
| 					if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx) | ||||
| 						module->connect(sig_y[i], sig_a[i]); | ||||
| 					else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx) | ||||
| 						module->connect(sig_y[i], sig_b[i]); | ||||
| 					else | ||||
| 						break; | ||||
| 				} | ||||
| 				if (i > 0) { | ||||
| 					cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); | ||||
| 					cell->setPort("\\A", sig_a.extract_end(i)); | ||||
| 					cell->setPort("\\B", sig_b.extract_end(i)); | ||||
| 					cell->setPort("\\Y", sig_y.extract_end(i)); | ||||
| 					cell->fixup_parameters(); | ||||
| 					did_something = true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type.in("$reduce_xor", "$reduce_xnor", "$shift", "$shiftx", "$shl", "$shr", "$sshl", "$sshr", | ||||
|  |  | |||
|  | @ -342,9 +342,9 @@ struct WreduceWorker | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor")) | ||||
| 		if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor", "$sub")) | ||||
| 		{ | ||||
| 			bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); | ||||
| 			bool is_signed = cell->getParam("\\A_SIGNED").as_bool() || cell->type == "$sub"; | ||||
| 
 | ||||
| 			int a_size = 0, b_size = 0; | ||||
| 			if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A")); | ||||
|  | @ -352,7 +352,7 @@ struct WreduceWorker | |||
| 
 | ||||
| 			int max_y_size = max(a_size, b_size); | ||||
| 
 | ||||
| 			if (cell->type == "$add") | ||||
| 			if (cell->type.in("$add", "$sub")) | ||||
| 				max_y_size++; | ||||
| 
 | ||||
| 			if (cell->type == "$mul") | ||||
|  |  | |||
|  | @ -931,9 +931,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin | |||
| 	{ | ||||
| 		log_header(design, "Executing ABC.\n"); | ||||
| 
 | ||||
| 		auto cell_cost = [](IdString cell_type) { | ||||
| 			return get_cell_cost(cell_type, dict<RTLIL::IdString, RTLIL::Const>(), nullptr, nullptr, cmos_cost); | ||||
| 		}; | ||||
| 		auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost(); | ||||
| 
 | ||||
| 		buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str()); | ||||
| 		f = fopen(buffer.c_str(), "wt"); | ||||
|  | @ -941,42 +939,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin | |||
| 			log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); | ||||
| 		fprintf(f, "GATE ZERO    1 Y=CONST0;\n"); | ||||
| 		fprintf(f, "GATE ONE     1 Y=CONST1;\n"); | ||||
| 		fprintf(f, "GATE BUF    %d Y=A;                  PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_BUF_")); | ||||
| 		fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NOT_")); | ||||
| 		fprintf(f, "GATE BUF    %d Y=A;                  PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_BUF_")); | ||||
| 		fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_NOT_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("AND")) | ||||
| 			fprintf(f, "GATE AND    %d Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_AND_")); | ||||
| 			fprintf(f, "GATE AND    %d Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_AND_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("NAND")) | ||||
| 			fprintf(f, "GATE NAND   %d Y=!(A*B);             PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NAND_")); | ||||
| 			fprintf(f, "GATE NAND   %d Y=!(A*B);             PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_NAND_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("OR")) | ||||
| 			fprintf(f, "GATE OR     %d Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_OR_")); | ||||
| 			fprintf(f, "GATE OR     %d Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_OR_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("NOR")) | ||||
| 			fprintf(f, "GATE NOR    %d Y=!(A+B);             PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NOR_")); | ||||
| 			fprintf(f, "GATE NOR    %d Y=!(A+B);             PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_NOR_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("XOR")) | ||||
| 			fprintf(f, "GATE XOR    %d Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XOR_")); | ||||
| 			fprintf(f, "GATE XOR    %d Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XOR_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("XNOR")) | ||||
| 			fprintf(f, "GATE XNOR   %d Y=(A*B)+(!A*!B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XNOR_")); | ||||
| 			fprintf(f, "GATE XNOR   %d Y=(A*B)+(!A*!B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XNOR_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("ANDNOT")) | ||||
| 			fprintf(f, "GATE ANDNOT %d Y=A*!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ANDNOT_")); | ||||
| 			fprintf(f, "GATE ANDNOT %d Y=A*!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ANDNOT_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("ORNOT")) | ||||
| 			fprintf(f, "GATE ORNOT  %d Y=A+!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ORNOT_")); | ||||
| 			fprintf(f, "GATE ORNOT  %d Y=A+!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ORNOT_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("AOI3")) | ||||
| 			fprintf(f, "GATE AOI3   %d Y=!((A*B)+C);         PIN * INV     1 999 1 0 1 0\n", cell_cost("$_AOI3_")); | ||||
| 			fprintf(f, "GATE AOI3   %d Y=!((A*B)+C);         PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_AOI3_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("OAI3")) | ||||
| 			fprintf(f, "GATE OAI3   %d Y=!((A+B)*C);         PIN * INV     1 999 1 0 1 0\n", cell_cost("$_OAI3_")); | ||||
| 			fprintf(f, "GATE OAI3   %d Y=!((A+B)*C);         PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_OAI3_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("AOI4")) | ||||
| 			fprintf(f, "GATE AOI4   %d Y=!((A*B)+(C*D));     PIN * INV     1 999 1 0 1 0\n", cell_cost("$_AOI4_")); | ||||
| 			fprintf(f, "GATE AOI4   %d Y=!((A*B)+(C*D));     PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_AOI4_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("OAI4")) | ||||
| 			fprintf(f, "GATE OAI4   %d Y=!((A+B)*(C+D));     PIN * INV     1 999 1 0 1 0\n", cell_cost("$_OAI4_")); | ||||
| 			fprintf(f, "GATE OAI4   %d Y=!((A+B)*(C+D));     PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_OAI4_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("MUX")) | ||||
| 			fprintf(f, "GATE MUX    %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_MUX_")); | ||||
| 			fprintf(f, "GATE MUX    %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_MUX_")); | ||||
| 		if (enabled_gates.empty() || enabled_gates.count("NMUX")) | ||||
| 			fprintf(f, "GATE NMUX   %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_NMUX_")); | ||||
| 			fprintf(f, "GATE NMUX   %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_NMUX_")); | ||||
| 		if (map_mux4) | ||||
| 			fprintf(f, "GATE MUX4   %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost("$_MUX_")); | ||||
| 			fprintf(f, "GATE MUX4   %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at("$_MUX_")); | ||||
| 		if (map_mux8) | ||||
| 			fprintf(f, "GATE MUX8   %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost("$_MUX_")); | ||||
| 			fprintf(f, "GATE MUX8   %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at("$_MUX_")); | ||||
| 		if (map_mux16) | ||||
| 			fprintf(f, "GATE MUX16  %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost("$_MUX_")); | ||||
| 			fprintf(f, "GATE MUX16  %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at("$_MUX_")); | ||||
| 		fclose(f); | ||||
| 
 | ||||
| 		if (!lut_costs.empty()) { | ||||
|  |  | |||
|  | @ -42,10 +42,9 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
| 	wire [Y_WIDTH-1:0] AA = A_buf; | ||||
| 	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; | ||||
| 	wire [Y_WIDTH+1:0] COx; | ||||
| 	wire [Y_WIDTH+1:0] C = {COx, CI}; | ||||
| 	wire [Y_WIDTH+2:0] C = {COx, CI}; | ||||
| 
 | ||||
|     wire dummy; | ||||
| 	(* keep *) | ||||
|     AL_MAP_ADDER #( | ||||
|     	.ALUTYPE("ADD_CARRY")) | ||||
|     adder_cin  ( | ||||
|  | @ -55,19 +54,6 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
| 
 | ||||
| 	genvar i; | ||||
| 	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice | ||||
| 	  if(i==Y_WIDTH-1) begin | ||||
| 	  		(* keep *) | ||||
| 			AL_MAP_ADDER #( | ||||
| 				.ALUTYPE("ADD")) | ||||
| 			adder_cout  ( | ||||
| 				.c(C[Y_WIDTH]), | ||||
| 				.o(COx[Y_WIDTH]) | ||||
| 			);				 | ||||
|             assign CO = COx[Y_WIDTH]; | ||||
|           end | ||||
| 	  else | ||||
| 	  begin | ||||
| 	  	(* keep *) | ||||
| 	    AL_MAP_ADDER #( | ||||
|             .ALUTYPE("ADD") | ||||
|         ) adder_i ( | ||||
|  | @ -76,9 +62,15 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
|             .c(C[i+1]), | ||||
|             .o({COx[i+1],Y[i]}) | ||||
|         ); | ||||
| 		end		 | ||||
| 	  end: slice | ||||
| 	endgenerate | ||||
| 	/* End implementation */ | ||||
| 	AL_MAP_ADDER #( | ||||
| 		.ALUTYPE("ADD")) | ||||
| 	adder_cout  ( | ||||
| 		.c(C[Y_WIDTH+1]), | ||||
| 		.o(COx[Y_WIDTH+1]) | ||||
| 	);				 | ||||
| 	assign CO = COx[Y_WIDTH+1]; | ||||
| 	assign X = AA ^ BB; | ||||
| endmodule | ||||
|  | @ -333,6 +333,31 @@ module TRELLIS_SLICE( | |||
| 	parameter [127:0] CCU2_INJECT1_0 = "NO"; | ||||
| 	parameter [127:0] CCU2_INJECT1_1 = "NO"; | ||||
| 	parameter WREMUX = "WRE"; | ||||
| 	parameter WCKMUX = "WCK"; | ||||
| 
 | ||||
| 	parameter A0MUX = "A0"; | ||||
| 	parameter A1MUX = "A1"; | ||||
| 	parameter B0MUX = "B0"; | ||||
| 	parameter B1MUX = "B1"; | ||||
| 	parameter C0MUX = "C0"; | ||||
| 	parameter C1MUX = "C1"; | ||||
| 	parameter D0MUX = "D0"; | ||||
| 	parameter D1MUX = "D1"; | ||||
| 
 | ||||
| 	wire A0m, B0m, C0m, D0m; | ||||
| 	wire A1m, B1m, C1m, D1m; | ||||
| 
 | ||||
| 	generate | ||||
| 		if (A0MUX == "1") assign A0m = 1'b1; else assign A0m = A0; | ||||
| 		if (B0MUX == "1") assign B0m = 1'b1; else assign B0m = B0; | ||||
| 		if (C0MUX == "1") assign C0m = 1'b1; else assign C0m = C0; | ||||
| 		if (D0MUX == "1") assign D0m = 1'b1; else assign D0m = D0; | ||||
| 		if (A1MUX == "1") assign A1m = 1'b1; else assign A1m = A1; | ||||
| 		if (B1MUX == "1") assign B1m = 1'b1; else assign B1m = B1; | ||||
| 		if (C1MUX == "1") assign C1m = 1'b1; else assign C1m = C1; | ||||
| 		if (D1MUX == "1") assign D1m = 1'b1; else assign D1m = D1; | ||||
| 
 | ||||
| 	endgenerate | ||||
| 
 | ||||
| 	function [15:0] permute_initval; | ||||
| 		input [15:0] initval; | ||||
|  | @ -350,13 +375,13 @@ module TRELLIS_SLICE( | |||
| 			LUT4 #( | ||||
| 				.INIT(LUT0_INITVAL) | ||||
| 			) lut4_0 ( | ||||
| 				.A(A0), .B(B0), .C(C0), .D(D0), | ||||
| 				.A(A0m), .B(B0m), .C(C0m), .D(D0m), | ||||
| 				.Z(F0) | ||||
| 			); | ||||
| 			LUT4 #( | ||||
| 				.INIT(LUT1_INITVAL) | ||||
| 			) lut4_1 ( | ||||
| 				.A(A1), .B(B1), .C(C1), .D(D1), | ||||
| 				.A(A1m), .B(B1m), .C(C1m), .D(D1m), | ||||
| 				.Z(F1) | ||||
| 			); | ||||
| 			// LUT expansion muxes | ||||
|  | @ -370,20 +395,20 @@ module TRELLIS_SLICE( | |||
| 				.INJECT1_1(CCU2_INJECT1_1) | ||||
| 		  ) ccu2c_i ( | ||||
| 				.CIN(FCI), | ||||
| 				.A0(A0), .B0(B0), .C0(C0), .D0(D0), | ||||
| 				.A1(A1), .B1(B1), .C1(C1), .D1(D1), | ||||
| 				.A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m), | ||||
| 				.A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m), | ||||
| 				.S0(F0), .S1(F1), | ||||
| 				.COUT(FCO) | ||||
| 			); | ||||
| 		end else if (MODE == "RAMW") begin | ||||
| 			assign WDO0 = C1; | ||||
| 			assign WDO1 = A1; | ||||
| 			assign WDO2 = D1; | ||||
| 			assign WDO3 = B1; | ||||
| 			assign WADO0 = D0; | ||||
| 			assign WADO1 = B0; | ||||
| 			assign WADO2 = C0; | ||||
| 			assign WADO3 = A0; | ||||
| 			assign WDO0 = C1m; | ||||
| 			assign WDO1 = A1m; | ||||
| 			assign WDO2 = D1m; | ||||
| 			assign WDO3 = B1m; | ||||
| 			assign WADO0 = D0m; | ||||
| 			assign WADO1 = B0m; | ||||
| 			assign WADO2 = C0m; | ||||
| 			assign WADO3 = A0m; | ||||
| 		end else if (MODE == "DPRAM") begin | ||||
| 			TRELLIS_RAM16X2 #( | ||||
| 				.INITVAL_0(permute_initval(LUT0_INITVAL)), | ||||
|  | @ -393,17 +418,19 @@ module TRELLIS_SLICE( | |||
| 				.DI0(WD0), .DI1(WD1), | ||||
| 				.WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3), | ||||
| 				.WRE(WRE), .WCK(WCK), | ||||
| 				.RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0), | ||||
| 				.RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m), | ||||
| 				.DO0(F0), .DO1(F1) | ||||
| 			); | ||||
| 			// TODO: confirm RAD and INITVAL ordering | ||||
| 			// DPRAM mode contract? | ||||
| `ifdef FORMAL | ||||
| 			always @(*) begin | ||||
| 				assert(A0==A1); | ||||
| 				assert(B0==B1); | ||||
| 				assert(C0==C1); | ||||
| 				assert(D0==D1); | ||||
| 				assert(A0m==A1m); | ||||
| 				assert(B0m==B1m); | ||||
| 				assert(C0m==C1m); | ||||
| 				assert(D0m==D1m); | ||||
| 			end | ||||
| `endif | ||||
| 		end else begin | ||||
| 			ERROR_UNKNOWN_SLICE_MODE error(); | ||||
| 		end | ||||
|  | @ -470,8 +497,124 @@ module DP16KD( | |||
| 	parameter WRITEMODE_A = "NORMAL"; | ||||
| 	parameter WRITEMODE_B = "NORMAL"; | ||||
| 
 | ||||
| 	parameter DIA17MUX = "DIA17"; | ||||
| 	parameter DIA16MUX = "DIA16"; | ||||
| 	parameter DIA15MUX = "DIA15"; | ||||
| 	parameter DIA14MUX = "DIA14"; | ||||
| 	parameter DIA13MUX = "DIA13"; | ||||
| 	parameter DIA12MUX = "DIA12"; | ||||
| 	parameter DIA11MUX = "DIA11"; | ||||
| 	parameter DIA10MUX = "DIA10"; | ||||
| 	parameter DIA9MUX = "DIA9"; | ||||
| 	parameter DIA8MUX = "DIA8"; | ||||
| 	parameter DIA7MUX = "DIA7"; | ||||
| 	parameter DIA6MUX = "DIA6"; | ||||
| 	parameter DIA5MUX = "DIA5"; | ||||
| 	parameter DIA4MUX = "DIA4"; | ||||
| 	parameter DIA3MUX = "DIA3"; | ||||
| 	parameter DIA2MUX = "DIA2"; | ||||
| 	parameter DIA1MUX = "DIA1"; | ||||
| 	parameter DIA0MUX = "DIA0"; | ||||
| 	parameter ADA13MUX = "ADA13"; | ||||
| 	parameter ADA12MUX = "ADA12"; | ||||
| 	parameter ADA11MUX = "ADA11"; | ||||
| 	parameter ADA10MUX = "ADA10"; | ||||
| 	parameter ADA9MUX = "ADA9"; | ||||
| 	parameter ADA8MUX = "ADA8"; | ||||
| 	parameter ADA7MUX = "ADA7"; | ||||
| 	parameter ADA6MUX = "ADA6"; | ||||
| 	parameter ADA5MUX = "ADA5"; | ||||
| 	parameter ADA4MUX = "ADA4"; | ||||
| 	parameter ADA3MUX = "ADA3"; | ||||
| 	parameter ADA2MUX = "ADA2"; | ||||
| 	parameter ADA1MUX = "ADA1"; | ||||
| 	parameter ADA0MUX = "ADA0"; | ||||
| 	parameter CEAMUX = "CEA"; | ||||
| 	parameter OCEAMUX = "OCEA"; | ||||
| 	parameter CLKAMUX = "CLKA"; | ||||
| 	parameter WEAMUX = "WEA"; | ||||
| 	parameter RSTAMUX = "RSTA"; | ||||
| 	parameter CSA2MUX = "CSA2"; | ||||
| 	parameter CSA1MUX = "CSA1"; | ||||
| 	parameter CSA0MUX = "CSA0"; | ||||
| 	parameter DOA17MUX = "DOA17"; | ||||
| 	parameter DOA16MUX = "DOA16"; | ||||
| 	parameter DOA15MUX = "DOA15"; | ||||
| 	parameter DOA14MUX = "DOA14"; | ||||
| 	parameter DOA13MUX = "DOA13"; | ||||
| 	parameter DOA12MUX = "DOA12"; | ||||
| 	parameter DOA11MUX = "DOA11"; | ||||
| 	parameter DOA10MUX = "DOA10"; | ||||
| 	parameter DOA9MUX = "DOA9"; | ||||
| 	parameter DOA8MUX = "DOA8"; | ||||
| 	parameter DOA7MUX = "DOA7"; | ||||
| 	parameter DOA6MUX = "DOA6"; | ||||
| 	parameter DOA5MUX = "DOA5"; | ||||
| 	parameter DOA4MUX = "DOA4"; | ||||
| 	parameter DOA3MUX = "DOA3"; | ||||
| 	parameter DOA2MUX = "DOA2"; | ||||
| 	parameter DOA1MUX = "DOA1"; | ||||
| 	parameter DOA0MUX = "DOA0"; | ||||
| 	parameter DIB17MUX = "DIB17"; | ||||
| 	parameter DIB16MUX = "DIB16"; | ||||
| 	parameter DIB15MUX = "DIB15"; | ||||
| 	parameter DIB14MUX = "DIB14"; | ||||
| 	parameter DIB13MUX = "DIB13"; | ||||
| 	parameter DIB12MUX = "DIB12"; | ||||
| 	parameter DIB11MUX = "DIB11"; | ||||
| 	parameter DIB10MUX = "DIB10"; | ||||
| 	parameter DIB9MUX = "DIB9"; | ||||
| 	parameter DIB8MUX = "DIB8"; | ||||
| 	parameter DIB7MUX = "DIB7"; | ||||
| 	parameter DIB6MUX = "DIB6"; | ||||
| 	parameter DIB5MUX = "DIB5"; | ||||
| 	parameter DIB4MUX = "DIB4"; | ||||
| 	parameter DIB3MUX = "DIB3"; | ||||
| 	parameter DIB2MUX = "DIB2"; | ||||
| 	parameter DIB1MUX = "DIB1"; | ||||
| 	parameter DIB0MUX = "DIB0"; | ||||
| 	parameter ADB13MUX = "ADB13"; | ||||
| 	parameter ADB12MUX = "ADB12"; | ||||
| 	parameter ADB11MUX = "ADB11"; | ||||
| 	parameter ADB10MUX = "ADB10"; | ||||
| 	parameter ADB9MUX = "ADB9"; | ||||
| 	parameter ADB8MUX = "ADB8"; | ||||
| 	parameter ADB7MUX = "ADB7"; | ||||
| 	parameter ADB6MUX = "ADB6"; | ||||
| 	parameter ADB5MUX = "ADB5"; | ||||
| 	parameter ADB4MUX = "ADB4"; | ||||
| 	parameter ADB3MUX = "ADB3"; | ||||
| 	parameter ADB2MUX = "ADB2"; | ||||
| 	parameter ADB1MUX = "ADB1"; | ||||
| 	parameter ADB0MUX = "ADB0"; | ||||
| 	parameter CEBMUX = "CEB"; | ||||
| 	parameter OCEBMUX = "OCEB"; | ||||
| 	parameter CLKBMUX = "CLKB"; | ||||
| 	parameter WEBMUX = "WEB"; | ||||
| 	parameter RSTBMUX = "RSTB"; | ||||
| 	parameter CSB2MUX = "CSB2"; | ||||
| 	parameter CSB1MUX = "CSB1"; | ||||
| 	parameter CSB0MUX = "CSB0"; | ||||
| 	parameter DOB17MUX = "DOB17"; | ||||
| 	parameter DOB16MUX = "DOB16"; | ||||
| 	parameter DOB15MUX = "DOB15"; | ||||
| 	parameter DOB14MUX = "DOB14"; | ||||
| 	parameter DOB13MUX = "DOB13"; | ||||
| 	parameter DOB12MUX = "DOB12"; | ||||
| 	parameter DOB11MUX = "DOB11"; | ||||
| 	parameter DOB10MUX = "DOB10"; | ||||
| 	parameter DOB9MUX = "DOB9"; | ||||
| 	parameter DOB8MUX = "DOB8"; | ||||
| 	parameter DOB7MUX = "DOB7"; | ||||
| 	parameter DOB6MUX = "DOB6"; | ||||
| 	parameter DOB5MUX = "DOB5"; | ||||
| 	parameter DOB4MUX = "DOB4"; | ||||
| 	parameter DOB3MUX = "DOB3"; | ||||
| 	parameter DOB2MUX = "DOB2"; | ||||
| 	parameter DOB1MUX = "DOB1"; | ||||
| 	parameter DOB0MUX = "DOB0"; | ||||
| 
 | ||||
| 	parameter WID = 0; | ||||
| 
 | ||||
| 	parameter GSR = "ENABLED"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| # This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. | ||||
| arraycells.v	inst id[0] of | ||||
| defvalue.sv	Initial value not supported | ||||
| dff_different_styles.v | ||||
| dff_init.v	Initial value not supported | ||||
| generate.v	combinational loop | ||||
| hierdefparam.v	inst id[0] of | ||||
| i2c_master_tests.v   $adff | ||||
| implicit_ports.v     not fully initialized | ||||
| macros.v	drops modules | ||||
| mem2reg.v	drops modules | ||||
| mem_arst.v	$adff | ||||
|  | @ -12,7 +14,6 @@ memory.v	$adff | |||
| multiplier.v	inst id[0] of | ||||
| muxtree.v	drops modules | ||||
| omsp_dbg_uart.v	$adff | ||||
| operators.v	$pow | ||||
| partsel.v	drops modules | ||||
| process.v	drops modules | ||||
| realexpr.v	drops modules | ||||
|  | @ -23,5 +24,6 @@ specify.v	no code (empty module generates error | |||
| subbytes.v	$adff | ||||
| task_func.v	drops modules | ||||
| values.v	combinational loop | ||||
| wandwor.v	Invalid connect to an expression that is not a reference or a WritePort. | ||||
| vloghammer.v	combinational loop | ||||
| wreduce.v	original verilog issues ( -x where x isn't declared signed) | ||||
|  |  | |||
							
								
								
									
										148
									
								
								tests/various/opt_expr.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								tests/various/opt_expr.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,148 @@ | |||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o); | ||||
|     assign o = (i << 4) + j; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); | ||||
|     assign o = (i << 4) + j; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o); | ||||
|     assign o = j - (i << 4); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); | ||||
|     assign o = j - (i << 4); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o); | ||||
|     assign o = (i << 4) - j; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module opt_expr_sub_test4(input [3:0] i, output [8:0] o); | ||||
|     assign o = 5'b00010 - i; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr -fine | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
							
								
								
									
										48
									
								
								tests/various/wreduce.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/various/wreduce.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| read_verilog <<EOT | ||||
| module wreduce_sub_test(input [3:0] i, input [7:0] j, output [8:0] o); | ||||
|     assign o = (j >> 4) - i; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr | ||||
| wreduce | ||||
| 
 | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| ########## | ||||
| 
 | ||||
| read_verilog <<EOT | ||||
| module wreduce_sub_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); | ||||
|     assign o = (j >>> 4) - i; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| proc | ||||
| design -save gold | ||||
| 
 | ||||
| opt_expr | ||||
| wreduce | ||||
| 
 | ||||
| dump | ||||
| select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i | ||||
| 
 | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue