mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Added "opt_const -keepdc"
This commit is contained in:
		
							parent
							
								
									1873480ca5
								
							
						
					
					
						commit
						137dbf3cf7
					
				
					 2 changed files with 168 additions and 15 deletions
				
			
		|  | @ -31,7 +31,7 @@ struct OptPass : public Pass { | ||||||
| 	{ | 	{ | ||||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    opt [-purge] [-mux_undef] [-mux_bool] [-undriven] [-fine] [selection]\n"); | 		log("    opt [options] [selection]\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("This pass calls all the other opt_* passes in a useful order. This performs\n"); | 		log("This pass calls all the other opt_* passes in a useful order. This performs\n"); | ||||||
| 		log("a series of trivial optimizations and cleanups. This pass executes the other\n"); | 		log("a series of trivial optimizations and cleanups. This pass executes the other\n"); | ||||||
|  | @ -46,8 +46,11 @@ struct OptPass : public Pass { | ||||||
| 		log("        opt_share\n"); | 		log("        opt_share\n"); | ||||||
| 		log("        opt_rmdff\n"); | 		log("        opt_rmdff\n"); | ||||||
| 		log("        opt_clean [-purge]\n"); | 		log("        opt_clean [-purge]\n"); | ||||||
| 		log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine]\n"); | 		log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n"); | ||||||
| 		log("    while [changed design]\n"); | 		log("    while <changed design>\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Note: Options in square brackets (such as [-keepdc]) are passed through to\n"); | ||||||
|  | 		log("the opt_* commands when given to 'opt'.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||||
|  | @ -82,6 +85,10 @@ struct OptPass : public Pass { | ||||||
| 				opt_reduce_args += " -fine"; | 				opt_reduce_args += " -fine"; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-keepdc") { | ||||||
|  | 				opt_const_args += " -keepdc"; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  |  | ||||||
|  | @ -74,6 +74,8 @@ static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| static void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) | static void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) | ||||||
| { | { | ||||||
| 	RTLIL::SigSpec Y = cell->connections[out_port]; | 	RTLIL::SigSpec Y = cell->connections[out_port]; | ||||||
|  | 	out_val.extend_u0(Y.width, false); | ||||||
|  | 
 | ||||||
| 	log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", | 	log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", | ||||||
| 			cell->type.c_str(), cell->name.c_str(), info.c_str(), | 			cell->type.c_str(), cell->name.c_str(), info.c_str(), | ||||||
| 			module->name.c_str(), log_signal(Y), log_signal(out_val)); | 			module->name.c_str(), log_signal(Y), log_signal(out_val)); | ||||||
|  | @ -114,6 +116,12 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com | ||||||
| 		int group_idx = GRP_DYN; | 		int group_idx = GRP_DYN; | ||||||
| 		RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; | 		RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; | ||||||
| 
 | 
 | ||||||
|  | 		if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) | ||||||
|  | 			bit_a = bit_b = RTLIL::State::S1; | ||||||
|  | 
 | ||||||
|  | 		if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) | ||||||
|  | 			bit_a = bit_b = RTLIL::State::S0; | ||||||
|  | 
 | ||||||
| 		if (bit_a.wire == NULL && bit_b.wire == NULL) | 		if (bit_a.wire == NULL && bit_b.wire == NULL) | ||||||
| 			group_idx = GRP_CONST_AB; | 			group_idx = GRP_CONST_AB; | ||||||
| 		else if (bit_a.wire == NULL) | 		else if (bit_a.wire == NULL) | ||||||
|  | @ -181,7 +189,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine) | static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc) | ||||||
| { | { | ||||||
| 	if (!design->selected(module)) | 	if (!design->selected(module)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -204,10 +212,132 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo | ||||||
| #define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) | #define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) | ||||||
| #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) | #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) | ||||||
| 
 | 
 | ||||||
| 		if (do_fine && (cell->type == "$not" || cell->type == "$pos" || cell->type == "$bu0" || | 		if (do_fine) | ||||||
| 				cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor")) | 		{ | ||||||
| 			if (group_cell_inputs(module, cell, true, cell->type != "$pos", assign_map)) | 			if (cell->type == "$not" || cell->type == "$pos" || cell->type == "$bu0" || | ||||||
|  | 					cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") | ||||||
|  | 				if (group_cell_inputs(module, cell, true, cell->type != "$pos", assign_map)) | ||||||
|  | 					goto next_cell; | ||||||
|  | 
 | ||||||
|  | 			if (cell->type == "$reduce_and") | ||||||
|  | 			{ | ||||||
|  | 				RTLIL::SigSpec sig_a = assign_map(cell->connections.at("\\A")); | ||||||
|  | 
 | ||||||
|  | 				RTLIL::State new_a = RTLIL::State::S1; | ||||||
|  | 				for (auto &bit : sig_a.to_sigbit_vector()) | ||||||
|  | 					if (bit == RTLIL::State::Sx) { | ||||||
|  | 						if (new_a == RTLIL::State::S1) | ||||||
|  | 							new_a = RTLIL::State::Sx; | ||||||
|  | 					} else if (bit == RTLIL::State::S0) { | ||||||
|  | 						new_a = RTLIL::State::S0; | ||||||
|  | 						break; | ||||||
|  | 					} else if (bit.wire != NULL) { | ||||||
|  | 						new_a = RTLIL::State::Sm; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | ||||||
|  | 					log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
|  | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | ||||||
|  | 					cell->connections.at("\\A") = sig_a = new_a; | ||||||
|  | 					cell->parameters.at("\\A_WIDTH") = 1; | ||||||
|  | 					OPT_DID_SOMETHING = true; | ||||||
|  | 					did_something = true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") | ||||||
|  | 			{ | ||||||
|  | 				RTLIL::SigSpec sig_a = assign_map(cell->connections.at("\\A")); | ||||||
|  | 
 | ||||||
|  | 				RTLIL::State new_a = RTLIL::State::S0; | ||||||
|  | 				for (auto &bit : sig_a.to_sigbit_vector()) | ||||||
|  | 					if (bit == RTLIL::State::Sx) { | ||||||
|  | 						if (new_a == RTLIL::State::S0) | ||||||
|  | 							new_a = RTLIL::State::Sx; | ||||||
|  | 					} else if (bit == RTLIL::State::S1) { | ||||||
|  | 						new_a = RTLIL::State::S1; | ||||||
|  | 						break; | ||||||
|  | 					} else if (bit.wire != NULL) { | ||||||
|  | 						new_a = RTLIL::State::Sm; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | ||||||
|  | 					log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
|  | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | ||||||
|  | 					cell->connections.at("\\A") = sig_a = new_a; | ||||||
|  | 					cell->parameters.at("\\A_WIDTH") = 1; | ||||||
|  | 					OPT_DID_SOMETHING = true; | ||||||
|  | 					did_something = true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (cell->type == "$logic_and" || cell->type == "$logic_or") | ||||||
|  | 			{ | ||||||
|  | 				RTLIL::SigSpec sig_b = assign_map(cell->connections.at("\\B")); | ||||||
|  | 
 | ||||||
|  | 				RTLIL::State new_b = RTLIL::State::S0; | ||||||
|  | 				for (auto &bit : sig_b.to_sigbit_vector()) | ||||||
|  | 					if (bit == RTLIL::State::Sx) { | ||||||
|  | 						if (new_b == RTLIL::State::S0) | ||||||
|  | 							new_b = RTLIL::State::Sx; | ||||||
|  | 					} else if (bit == RTLIL::State::S1) { | ||||||
|  | 						new_b = RTLIL::State::S1; | ||||||
|  | 						break; | ||||||
|  | 					} else if (bit.wire != NULL) { | ||||||
|  | 						new_b = RTLIL::State::Sm; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { | ||||||
|  | 					log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
|  | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); | ||||||
|  | 					cell->connections.at("\\B") = sig_b = new_b; | ||||||
|  | 					cell->parameters.at("\\B_WIDTH") = 1; | ||||||
|  | 					OPT_DID_SOMETHING = true; | ||||||
|  | 					did_something = true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (cell->type == "$logic_or" && (assign_map(cell->connections.at("\\A")) == RTLIL::State::S1 || assign_map(cell->connections.at("\\B")) == RTLIL::State::S1)) { | ||||||
|  | 			replace_cell(module, cell, "one high", "\\Y", RTLIL::State::S1); | ||||||
|  | 			goto next_cell; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (cell->type == "$logic_and" && (assign_map(cell->connections.at("\\A")) == RTLIL::State::S0 || assign_map(cell->connections.at("\\B")) == RTLIL::State::S0)) { | ||||||
|  | 			replace_cell(module, cell, "one low", "\\Y", RTLIL::State::S0); | ||||||
|  | 			goto next_cell; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || | ||||||
|  | 				cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || | ||||||
|  | 				cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" || | ||||||
|  | 				cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" || | ||||||
|  | 				cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow") | ||||||
|  | 		{ | ||||||
|  | 			RTLIL::SigSpec sig_a = assign_map(cell->connections.at("\\A")); | ||||||
|  | 			RTLIL::SigSpec sig_b = cell->connections.count("\\B") ? assign_map(cell->connections.at("\\B")) : RTLIL::SigSpec(); | ||||||
|  | 
 | ||||||
|  | 			if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") | ||||||
|  | 				sig_a = RTLIL::SigSpec(); | ||||||
|  | 
 | ||||||
|  | 			for (auto &bit : sig_a.to_sigbit_vector()) | ||||||
|  | 				if (bit == RTLIL::State::Sx) | ||||||
|  | 					goto found_the_x_bit; | ||||||
|  | 
 | ||||||
|  | 			for (auto &bit : sig_b.to_sigbit_vector()) | ||||||
|  | 				if (bit == RTLIL::State::Sx) | ||||||
|  | 					goto found_the_x_bit; | ||||||
|  | 
 | ||||||
|  | 			if (0) { | ||||||
|  | 		found_the_x_bit: | ||||||
|  | 				if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || | ||||||
|  | 						cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt") | ||||||
|  | 					replace_cell(module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx); | ||||||
|  | 				else | ||||||
|  | 					replace_cell(module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->connections.at("\\Y").width)); | ||||||
| 				goto next_cell; | 				goto next_cell; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if ((cell->type == "$_INV_" || cell->type == "$not" || cell->type == "$logic_not") && cell->connections["\\Y"].width == 1 && | 		if ((cell->type == "$_INV_" || cell->type == "$not" || cell->type == "$logic_not") && cell->connections["\\Y"].width == 1 && | ||||||
| 				invert_map.count(assign_map(cell->connections["\\A"])) != 0) { | 				invert_map.count(assign_map(cell->connections["\\A"])) != 0) { | ||||||
|  | @ -389,7 +519,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// checking for simple identities
 | 		if (!keepdc) | ||||||
| 		{ | 		{ | ||||||
| 			bool identity_bu0 = false; | 			bool identity_bu0 = false; | ||||||
| 			bool identity_wrt_a = false; | 			bool identity_wrt_a = false; | ||||||
|  | @ -647,7 +777,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo | ||||||
| 				ACTION_DO("\\Y", cell->connections["\\A"]); | 				ACTION_DO("\\Y", cell->connections["\\A"]); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (do_fine && cell->type == "$mul") | 		if (!keepdc && cell->type == "$mul") | ||||||
| 		{ | 		{ | ||||||
| 			bool a_signed = cell->parameters["\\A_SIGNED"].as_bool(); | 			bool a_signed = cell->parameters["\\A_SIGNED"].as_bool(); | ||||||
| 			bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); | 			bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); | ||||||
|  | @ -677,22 +807,27 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo | ||||||
| 					goto next_cell; | 					goto next_cell; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				for (int i = 0; i < sig_a.width - (a_signed ? 1 : 0); i++) | 				for (int i = 1; i < (a_signed ? sig_a.width-1 : sig_a.width); i++) | ||||||
| 					if (a_val == (1 << i)) | 					if (a_val == (1 << i)) | ||||||
| 					{ | 					{ | ||||||
| 						log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | 						log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | ||||||
| 								a_val, cell->name.c_str(), module->name.c_str(), i); | 								a_val, cell->name.c_str(), module->name.c_str(), i); | ||||||
| 
 | 
 | ||||||
| 						if (swapped_ab) { | 						if (!swapped_ab) { | ||||||
| 							cell->connections["\\A"] = cell->connections["\\B"]; | 							cell->connections["\\A"] = cell->connections["\\B"]; | ||||||
| 							cell->parameters["\\A_WIDTH"] = cell->parameters["\\B_WIDTH"]; | 							cell->parameters["\\A_WIDTH"] = cell->parameters["\\B_WIDTH"]; | ||||||
| 							cell->parameters["\\A_SIGNED"] = cell->parameters["\\B_SIGNED"]; | 							cell->parameters["\\A_SIGNED"] = cell->parameters["\\B_SIGNED"]; | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
|  | 						std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); | ||||||
|  | 
 | ||||||
|  | 						while (SIZE(new_b) > 1 && new_b.back() == RTLIL::State::S0) | ||||||
|  | 							new_b.pop_back(); | ||||||
|  | 
 | ||||||
| 						cell->type = "$shl"; | 						cell->type = "$shl"; | ||||||
| 						cell->parameters["\\B_WIDTH"] = 6; | 						cell->parameters["\\B_WIDTH"] = SIZE(new_b); | ||||||
| 						cell->parameters["\\B_SIGNED"] = false; | 						cell->parameters["\\B_SIGNED"] = false; | ||||||
| 						cell->connections["\\B"] = RTLIL::SigSpec(i, 6); | 						cell->connections["\\B"] = new_b; | ||||||
| 						cell->check(); | 						cell->check(); | ||||||
| 
 | 
 | ||||||
| 						OPT_DID_SOMETHING = true; | 						OPT_DID_SOMETHING = true; | ||||||
|  | @ -729,6 +864,12 @@ struct OptConstPass : public Pass { | ||||||
| 		log("    -undriven\n"); | 		log("    -undriven\n"); | ||||||
| 		log("        replace undriven nets with undef (x) constants\n"); | 		log("        replace undriven nets with undef (x) constants\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -keepdc\n"); | ||||||
|  | 		log("        some optimizations change the behavior of the circuit with respect to\n"); | ||||||
|  | 		log("        don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n"); | ||||||
|  | 		log("        all result bits to be set to x. this behavior changes when 'a+0' is\n"); | ||||||
|  | 		log("        replaced by 'a'. the -keepdc option disables all such optimizations.\n"); | ||||||
|  | 		log("\n"); | ||||||
| 		log("    -fine\n"); | 		log("    -fine\n"); | ||||||
| 		log("        perform fine-grain optimizations\n"); | 		log("        perform fine-grain optimizations\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | @ -739,6 +880,7 @@ struct OptConstPass : public Pass { | ||||||
| 		bool mux_bool = false; | 		bool mux_bool = false; | ||||||
| 		bool undriven = false; | 		bool undriven = false; | ||||||
| 		bool do_fine = false; | 		bool do_fine = false; | ||||||
|  | 		bool keepdc = false; | ||||||
| 
 | 
 | ||||||
| 		log_header("Executing OPT_CONST pass (perform const folding).\n"); | 		log_header("Executing OPT_CONST pass (perform const folding).\n"); | ||||||
| 		log_push(); | 		log_push(); | ||||||
|  | @ -761,6 +903,10 @@ struct OptConstPass : public Pass { | ||||||
| 				do_fine = true; | 				do_fine = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-keepdc") { | ||||||
|  | 				keepdc = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  | @ -773,9 +919,9 @@ struct OptConstPass : public Pass { | ||||||
| 			do { | 			do { | ||||||
| 				do { | 				do { | ||||||
| 					did_something = false; | 					did_something = false; | ||||||
| 					replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool, do_fine); | 					replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool, do_fine, keepdc); | ||||||
| 				} while (did_something); | 				} while (did_something); | ||||||
| 				replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool, do_fine); | 				replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool, do_fine, keepdc); | ||||||
| 			} while (did_something); | 			} while (did_something); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue