mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/eddie/opt_rmdff' into xc7mux
This commit is contained in:
		
						commit
						68359bcd6f
					
				
					 8 changed files with 120 additions and 20 deletions
				
			
		|  | @ -449,8 +449,10 @@ struct FirrtlWorker | ||||||
| 				string primop; | 				string primop; | ||||||
| 				bool always_uint = false; | 				bool always_uint = false; | ||||||
| 				if (cell->type == "$not") primop = "not"; | 				if (cell->type == "$not") primop = "not"; | ||||||
| 				else if (cell->type == "$neg") primop = "neg"; | 				else if (cell->type == "$neg") { | ||||||
| 				else if (cell->type == "$logic_not") { | 					primop = "neg"; | ||||||
|  | 					is_signed = true;	// Result of "neg" is signed (an SInt).
 | ||||||
|  | 				} else if (cell->type == "$logic_not") { | ||||||
|                                         primop = "eq"; |                                         primop = "eq"; | ||||||
|                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str()); |                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str()); | ||||||
|                                 } |                                 } | ||||||
|  | @ -562,6 +564,7 @@ struct FirrtlWorker | ||||||
| 					auto b_sig = cell->getPort("\\B"); | 					auto b_sig = cell->getPort("\\B"); | ||||||
| 					if (b_sig.is_fully_const()) { | 					if (b_sig.is_fully_const()) { | ||||||
| 						primop = "shl"; | 						primop = "shl"; | ||||||
|  | 						b_expr = std::to_string(b_sig.as_int()); | ||||||
| 					} else { | 					} else { | ||||||
| 						primop = "dshl"; | 						primop = "dshl"; | ||||||
| 						// Convert from FIRRTL left shift semantics.
 | 						// Convert from FIRRTL left shift semantics.
 | ||||||
|  | @ -575,6 +578,7 @@ struct FirrtlWorker | ||||||
| 					auto b_sig = cell->getPort("\\B"); | 					auto b_sig = cell->getPort("\\B"); | ||||||
| 					if (b_sig.is_fully_const()) { | 					if (b_sig.is_fully_const()) { | ||||||
| 						primop = "shr"; | 						primop = "shr"; | ||||||
|  | 						b_expr = std::to_string(b_sig.as_int()); | ||||||
| 					} else { | 					} else { | ||||||
| 						primop = "dshr"; | 						primop = "dshr"; | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|  | @ -57,11 +57,15 @@ void AigerReader::parse_aiger() | ||||||
| 
 | 
 | ||||||
|     // Optional values
 |     // Optional values
 | ||||||
|     B = C = J = F = 0; |     B = C = J = F = 0; | ||||||
|     for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) { |     if (f.peek() != ' ') goto end_of_header; | ||||||
|         if (f.peek() != ' ') break; |     if (!(f >> B)) log_error("Invalid AIGER header\n"); | ||||||
|         if (!(f >> i)) |     if (f.peek() != ' ') goto end_of_header; | ||||||
|             log_error("Invalid AIGER header\n"); |     if (!(f >> C)) log_error("Invalid AIGER header\n"); | ||||||
|     } |     if (f.peek() != ' ') goto end_of_header; | ||||||
|  |     if (!(f >> J)) log_error("Invalid AIGER header\n"); | ||||||
|  |     if (f.peek() != ' ') goto end_of_header; | ||||||
|  |     if (!(f >> F)) log_error("Invalid AIGER header\n"); | ||||||
|  | end_of_header: | ||||||
| 
 | 
 | ||||||
|     std::string line; |     std::string line; | ||||||
|     std::getline(f, line); // Ignore up to start of next line, as standard
 |     std::getline(f, line); // Ignore up to start of next line, as standard
 | ||||||
|  |  | ||||||
|  | @ -320,12 +320,10 @@ class SubCircuit::SolverWorker | ||||||
| 
 | 
 | ||||||
| 	static int numberOfPermutations(const std::vector<std::string> &list) | 	static int numberOfPermutations(const std::vector<std::string> &list) | ||||||
| 	{ | 	{ | ||||||
| 		int numPermutations = 1; | 		constexpr size_t mappedPermutationsSize = 10; | ||||||
| 		for (int i = 0; i < int(list.size()); i++) { | 		constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; | ||||||
| 			assert(numPermutations < maxPermutationsLimit); | 		assert(list.size() < mappedPermutationsSize); | ||||||
| 			numPermutations *= i+1; | 		return mappedPermutations[list.size()]; | ||||||
| 		} |  | ||||||
| 		return numPermutations; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx) | 	static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx) | ||||||
|  |  | ||||||
|  | @ -260,8 +260,8 @@ delete_dlatch: | ||||||
| 
 | 
 | ||||||
| bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | ||||||
| { | { | ||||||
| 	RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r; | 	RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e; | ||||||
| 	RTLIL::Const val_cp, val_rp, val_rv; | 	RTLIL::Const val_cp, val_rp, val_rv, val_ep; | ||||||
| 
 | 
 | ||||||
| 	if (dff->type == "$_FF_") { | 	if (dff->type == "$_FF_") { | ||||||
| 		sig_d = dff->getPort("\\D"); | 		sig_d = dff->getPort("\\D"); | ||||||
|  | @ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | ||||||
| 		val_rp = RTLIL::Const(dff->type[7] == 'P', 1); | 		val_rp = RTLIL::Const(dff->type[7] == 'P', 1); | ||||||
| 		val_rv = RTLIL::Const(dff->type[8] == '1', 1); | 		val_rv = RTLIL::Const(dff->type[8] == '1', 1); | ||||||
| 	} | 	} | ||||||
|  | 	else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" && | ||||||
|  | 			(dff->type[7] == 'N' || dff->type[7] == 'P') && | ||||||
|  | 			(dff->type[8] == 'N' || dff->type[8] == 'P')) { | ||||||
|  | 		sig_d = dff->getPort("\\D"); | ||||||
|  | 		sig_q = dff->getPort("\\Q"); | ||||||
|  | 		sig_c = dff->getPort("\\C"); | ||||||
|  | 		sig_e = dff->getPort("\\E"); | ||||||
|  | 		val_cp = RTLIL::Const(dff->type[6] == 'P', 1); | ||||||
|  | 		val_ep = RTLIL::Const(dff->type[7] == 'P', 1); | ||||||
|  | 	} | ||||||
| 	else if (dff->type == "$ff") { | 	else if (dff->type == "$ff") { | ||||||
| 		sig_d = dff->getPort("\\D"); | 		sig_d = dff->getPort("\\D"); | ||||||
| 		sig_q = dff->getPort("\\Q"); | 		sig_q = dff->getPort("\\Q"); | ||||||
|  | @ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | ||||||
| 		sig_c = dff->getPort("\\CLK"); | 		sig_c = dff->getPort("\\CLK"); | ||||||
| 		val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); | 		val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); | ||||||
| 	} | 	} | ||||||
|  | 	else if (dff->type == "$dffe") { | ||||||
|  | 		sig_e = dff->getPort("\\EN"); | ||||||
|  | 		sig_d = dff->getPort("\\D"); | ||||||
|  | 		sig_q = dff->getPort("\\Q"); | ||||||
|  | 		sig_c = dff->getPort("\\CLK"); | ||||||
|  | 		val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); | ||||||
|  | 		val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1); | ||||||
|  | 	} | ||||||
| 	else if (dff->type == "$adff") { | 	else if (dff->type == "$adff") { | ||||||
| 		sig_d = dff->getPort("\\D"); | 		sig_d = dff->getPort("\\D"); | ||||||
| 		sig_q = dff->getPort("\\Q"); | 		sig_q = dff->getPort("\\Q"); | ||||||
|  | @ -320,6 +338,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | ||||||
| 		val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx); | 		val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (sig_e.size()) { | ||||||
|  | 		if (!sig_e.is_fully_const()) | ||||||
|  | 			return false; | ||||||
|  | 		if (sig_e != val_ep) { | ||||||
|  | 			if (has_init) | ||||||
|  | 				mod->connect(sig_q, val_init); | ||||||
|  | 			goto delete_dff; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) { | 	if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) { | ||||||
| 		std::set<RTLIL::Cell*> muxes; | 		std::set<RTLIL::Cell*> muxes; | ||||||
| 		mux_drivers.find(sig_d, muxes); | 		mux_drivers.find(sig_d, muxes); | ||||||
|  | @ -489,7 +517,8 @@ struct OptRmdffPass : public Pass { | ||||||
| 				if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", | 				if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", | ||||||
| 						"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", | 						"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", | ||||||
| 						"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", | 						"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", | ||||||
| 						"$ff", "$dff", "$adff")) | 						"$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_", | ||||||
|  | 						"$ff", "$dff", "$dffe", "$adff")) | ||||||
| 					dff_list.push_back(cell->name); | 					dff_list.push_back(cell->name); | ||||||
| 
 | 
 | ||||||
| 				if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) | 				if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN | ||||||
| struct WreduceConfig | struct WreduceConfig | ||||||
| { | { | ||||||
| 	pool<IdString> supported_cell_types; | 	pool<IdString> supported_cell_types; | ||||||
|  | 	bool keepdc = false; | ||||||
| 
 | 
 | ||||||
| 	WreduceConfig() | 	WreduceConfig() | ||||||
| 	{ | 	{ | ||||||
|  | @ -82,7 +83,7 @@ struct WreduceWorker | ||||||
| 
 | 
 | ||||||
| 			SigBit ref = sig_a[i]; | 			SigBit ref = sig_a[i]; | ||||||
| 			for (int k = 0; k < GetSize(sig_s); k++) { | 			for (int k = 0; k < GetSize(sig_s); k++) { | ||||||
| 				if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i]) | 				if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i]) | ||||||
| 					goto no_match_ab; | 					goto no_match_ab; | ||||||
| 				if (sig_b[k*GetSize(sig_a) + i] != Sx) | 				if (sig_b[k*GetSize(sig_a) + i] != Sx) | ||||||
| 					ref = sig_b[k*GetSize(sig_a) + i]; | 					ref = sig_b[k*GetSize(sig_a) + i]; | ||||||
|  | @ -497,6 +498,9 @@ struct WreducePass : public Pass { | ||||||
| 		log("        Do not change the width of memory address ports. Use this options in\n"); | 		log("        Do not change the width of memory address ports. Use this options in\n"); | ||||||
| 		log("        flows that use the 'memory_memx' pass.\n"); | 		log("        flows that use the 'memory_memx' pass.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -keepdc\n"); | ||||||
|  | 		log("        Do not optimize explicit don't-care values.\n"); | ||||||
|  | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE | 	void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE | ||||||
| 	{ | 	{ | ||||||
|  | @ -511,6 +515,10 @@ struct WreducePass : public Pass { | ||||||
| 				opt_memx = true; | 				opt_memx = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-keepdc") { | ||||||
|  | 				config.keepdc = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  |  | ||||||
|  | @ -195,9 +195,11 @@ struct PrepPass : public ScriptPass | ||||||
| 			run(nokeepdc ? "opt" : "opt -keepdc"); | 			run(nokeepdc ? "opt" : "opt -keepdc"); | ||||||
| 			if (!ifxmode) { | 			if (!ifxmode) { | ||||||
| 				if (help_mode) | 				if (help_mode) | ||||||
| 					run("wreduce [-memx]"); | 					run("wreduce -keepdc [-memx]"); | ||||||
| 				else | 				else if (nokeepdc) | ||||||
| 					run(memxmode ? "wreduce -memx" : "wreduce"); | 					run(memxmode ? "wreduce -memx" : "wreduce"); | ||||||
|  | 				else | ||||||
|  | 					run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc"); | ||||||
| 			} | 			} | ||||||
| 			if (!nomemmode) { | 			if (!nomemmode) { | ||||||
| 				run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); | 				run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								tests/various/opt_rmdff.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/various/opt_rmdff.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | module opt_rmdff_test (input C, input D, input E, output reg [16:0] Q); | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); | ||||||
|  | initial Q[1] = 1'b1; | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[1])); | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep2 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[2])); | ||||||
|  | initial Q[3] = 1'b0; | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[4])); | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[5])); | ||||||
|  | initial Q[6] = 1'b0; | ||||||
|  | \$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep6 (.CLK(C), .D(D), .EN(E), .Q(Q[6])); | ||||||
|  | 
 | ||||||
|  | \$_DFFE_PP_ remove7 (.C(C), .D(D), .E(1'b0), .Q(Q[7])); | ||||||
|  | initial Q[8] = 1'b1; | ||||||
|  | \$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); | ||||||
|  | \$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'bx), .Q(Q[9])); | ||||||
|  | \$_DFFE_PP_ keep10 (.C(C), .D(D), .E(1'b1), .Q(Q[10])); | ||||||
|  | initial Q[11] = 1'b0; | ||||||
|  | \$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); | ||||||
|  | 
 | ||||||
|  | \$_DFFE_NN_ remove12 (.C(C), .D(D), .E(1'b1), .Q(Q[12])); | ||||||
|  | initial Q[13] = 1'b1; | ||||||
|  | \$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); | ||||||
|  | \$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'bx), .Q(Q[14])); | ||||||
|  | \$_DFFE_NN_ keep15 (.C(C), .D(D), .E(1'b0), .Q(Q[15])); | ||||||
|  | initial Q[16] = 1'b0; | ||||||
|  | \$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
							
								
								
									
										25
									
								
								tests/various/opt_rmdff.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/various/opt_rmdff.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | read_verilog -icells opt_rmdff.v | ||||||
|  | prep | ||||||
|  | design -stash gold | ||||||
|  | read_verilog -icells opt_rmdff.v | ||||||
|  | opt_rmdff | ||||||
|  | 
 | ||||||
|  | select -assert-count 0 c:remove* | ||||||
|  | select -assert-min 7 c:keep* | ||||||
|  | 
 | ||||||
|  | prep | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | 
 | ||||||
|  | equiv_make gold gate equiv | ||||||
|  | hierarchy -top equiv | ||||||
|  | equiv_simple -undef | ||||||
|  | equiv_status -assert | ||||||
|  | 
 | ||||||
|  | design -load gold | ||||||
|  | stat | ||||||
|  | 
 | ||||||
|  | design -load gate | ||||||
|  | stat | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue