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
				
			
		|  | @ -146,7 +146,7 @@ struct FirrtlWorker | |||
| 			if (!mask.is_fully_def()) | ||||
| 				this->ena = SigSpec(RTLIL::Const(1)); | ||||
| 		} | ||||
| 	  string gen_read(const char * /* indent */) { | ||||
| 		string gen_read(const char * /* indent */) { | ||||
| 			log_error("gen_read called on write_port: %s\n", name.c_str()); | ||||
| 			return stringf("gen_read called on write_port: %s\n", name.c_str()); | ||||
| 		} | ||||
|  | @ -449,8 +449,10 @@ struct FirrtlWorker | |||
| 				string primop; | ||||
| 				bool always_uint = false; | ||||
| 				if (cell->type == "$not") primop = "not"; | ||||
| 				else if (cell->type == "$neg") primop = "neg"; | ||||
| 				else if (cell->type == "$logic_not") { | ||||
| 				else if (cell->type == "$neg") { | ||||
| 					primop = "neg"; | ||||
| 					is_signed = true;	// Result of "neg" is signed (an SInt).
 | ||||
| 				} else if (cell->type == "$logic_not") { | ||||
|                                         primop = "eq"; | ||||
|                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str()); | ||||
|                                 } | ||||
|  | @ -562,6 +564,7 @@ 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()); | ||||
| 					} else { | ||||
| 						primop = "dshl"; | ||||
| 						// Convert from FIRRTL left shift semantics.
 | ||||
|  | @ -575,6 +578,7 @@ 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()); | ||||
| 					} else { | ||||
| 						primop = "dshr"; | ||||
| 					} | ||||
|  |  | |||
|  | @ -57,11 +57,15 @@ void AigerReader::parse_aiger() | |||
| 
 | ||||
|     // Optional values
 | ||||
|     B = C = J = F = 0; | ||||
|     for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) { | ||||
|         if (f.peek() != ' ') break; | ||||
|         if (!(f >> i)) | ||||
|             log_error("Invalid AIGER header\n"); | ||||
|     } | ||||
|     if (f.peek() != ' ') goto end_of_header; | ||||
|     if (!(f >> B)) log_error("Invalid AIGER header\n"); | ||||
|     if (f.peek() != ' ') goto end_of_header; | ||||
|     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::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) | ||||
| 	{ | ||||
| 		int numPermutations = 1; | ||||
| 		for (int i = 0; i < int(list.size()); i++) { | ||||
| 			assert(numPermutations < maxPermutationsLimit); | ||||
| 			numPermutations *= i+1; | ||||
| 		} | ||||
| 		return numPermutations; | ||||
| 		constexpr size_t mappedPermutationsSize = 10; | ||||
| 		constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; | ||||
| 		assert(list.size() < mappedPermutationsSize); | ||||
| 		return mappedPermutations[list.size()]; | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| { | ||||
| 	RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r; | ||||
| 	RTLIL::Const val_cp, val_rp, val_rv; | ||||
| 	RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e; | ||||
| 	RTLIL::Const val_cp, val_rp, val_rv, val_ep; | ||||
| 
 | ||||
| 	if (dff->type == "$_FF_") { | ||||
| 		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_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") { | ||||
| 		sig_d = dff->getPort("\\D"); | ||||
| 		sig_q = dff->getPort("\\Q"); | ||||
|  | @ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) | |||
| 		sig_c = dff->getPort("\\CLK"); | ||||
| 		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") { | ||||
| 		sig_d = dff->getPort("\\D"); | ||||
| 		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); | ||||
| 	} | ||||
| 
 | ||||
| 	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)) { | ||||
| 		std::set<RTLIL::Cell*> muxes; | ||||
| 		mux_drivers.find(sig_d, muxes); | ||||
|  | @ -489,7 +517,8 @@ struct OptRmdffPass : public Pass { | |||
| 				if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", | ||||
| 						"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", | ||||
| 						"$_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); | ||||
| 
 | ||||
| 				if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN | |||
| struct WreduceConfig | ||||
| { | ||||
| 	pool<IdString> supported_cell_types; | ||||
| 	bool keepdc = false; | ||||
| 
 | ||||
| 	WreduceConfig() | ||||
| 	{ | ||||
|  | @ -82,7 +83,7 @@ struct WreduceWorker | |||
| 
 | ||||
| 			SigBit ref = sig_a[i]; | ||||
| 			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; | ||||
| 				if (sig_b[k*GetSize(sig_a) + i] != Sx) | ||||
| 					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("        flows that use the 'memory_memx' pass.\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 | ||||
| 	{ | ||||
|  | @ -511,6 +515,10 @@ struct WreducePass : public Pass { | |||
| 				opt_memx = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-keepdc") { | ||||
| 				config.keepdc = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  |  | |||
|  | @ -195,9 +195,11 @@ struct PrepPass : public ScriptPass | |||
| 			run(nokeepdc ? "opt" : "opt -keepdc"); | ||||
| 			if (!ifxmode) { | ||||
| 				if (help_mode) | ||||
| 					run("wreduce [-memx]"); | ||||
| 				else | ||||
| 					run("wreduce -keepdc [-memx]"); | ||||
| 				else if (nokeepdc) | ||||
| 					run(memxmode ? "wreduce -memx" : "wreduce"); | ||||
| 				else | ||||
| 					run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc"); | ||||
| 			} | ||||
| 			if (!nomemmode) { | ||||
| 				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