diff options
Diffstat (limited to 'passes')
| -rw-r--r-- | passes/cmds/bugpoint.cc | 90 | ||||
| -rw-r--r-- | passes/proc/Makefile.inc | 2 | ||||
| -rw-r--r-- | passes/proc/proc.cc | 2 | ||||
| -rw-r--r-- | passes/proc/proc_arst.cc | 2 | ||||
| -rw-r--r-- | passes/proc/proc_clean.cc | 32 | ||||
| -rw-r--r-- | passes/proc/proc_init.cc | 26 | ||||
| -rw-r--r-- | passes/proc/proc_mux.cc | 26 | ||||
| -rw-r--r-- | passes/proc/proc_prune.cc | 158 | ||||
| -rw-r--r-- | passes/sat/clk2fflogic.cc | 7 | ||||
| -rw-r--r-- | passes/techmap/muxcover.cc | 27 | ||||
| -rw-r--r-- | passes/techmap/techmap.cc | 3 | 
11 files changed, 318 insertions, 57 deletions
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index 038ab7c7c..5a47988ec 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -51,14 +51,14 @@ struct BugpointPass : public Pass {  		log("        only consider crashes that place this string in the log file.\n");  		log("\n");  		log("    -fast\n"); -		log("        run `clean -purge` after each minimization step. converges faster, but\n"); -		log("        produces larger testcases, and may fail to produce any testcase at all if\n"); -		log("        the crash is related to dangling wires.\n"); +		log("        run `proc_clean; clean -purge` after each minimization step. converges\n"); +		log("        faster, but produces larger testcases, and may fail to produce any\n"); +		log("        testcase at all if the crash is related to dangling wires.\n");  		log("\n");  		log("    -clean\n"); -		log("        run `clean -purge` before checking testcase and after finishing. produces\n"); -		log("        smaller and more useful testcases, but may fail to produce any testcase\n"); -		log("        at all if the crash is related to dangling wires.\n"); +		log("        run `proc_clean; clean -purge` before checking testcase and after\n"); +		log("        finishing. produces smaller and more useful testcases, but may fail to\n"); +		log("        produce any testcase at all if the crash is related to dangling wires.\n");  		log("\n");  		log("    -modules\n");  		log("        try to remove modules.\n"); @@ -72,6 +72,12 @@ struct BugpointPass : public Pass {  		log("    -connections\n");  		log("        try to reconnect ports to 'x.\n");  		log("\n"); +		log("    -assigns\n"); +		log("        try to remove process assigns from cases.\n"); +		log("\n"); +		log("    -updates\n"); +		log("        try to remove process updates from syncs.\n"); +		log("\n");  	}  	bool run_yosys(RTLIL::Design *design, string yosys_cmd, string script) @@ -110,6 +116,7 @@ struct BugpointPass : public Pass {  		RTLIL::Design *design_copy = new RTLIL::Design;  		for (auto &it : design->modules_)  			design_copy->add(it.second->clone()); +		Pass::call(design_copy, "proc_clean -quiet");  		Pass::call(design_copy, "clean -purge");  		if (do_delete) @@ -117,7 +124,7 @@ struct BugpointPass : public Pass {  		return design_copy;  	} -	RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections) +	RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections, bool assigns, bool updates)  	{  		RTLIL::Design *design_copy = new RTLIL::Design;  		for (auto &it : design->modules_) @@ -225,6 +232,59 @@ struct BugpointPass : public Pass {  				}  			}  		} +		if (assigns) +		{ +			for (auto mod : design_copy->modules()) +			{ +				if (mod->get_blackbox_attribute()) +					continue; + +				for (auto &pr : mod->processes) +				{ +					vector<RTLIL::CaseRule*> cases = {&pr.second->root_case}; +					while (!cases.empty()) +					{ +						RTLIL::CaseRule *cs = cases[0]; +						cases.erase(cases.begin()); +						for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) +						{ +							if (index++ == seed) +							{ +								log("Trying to remove assign %s %s in %s.%s.\n", log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); +								cs->actions.erase(it); +								return design_copy; +							} +						} +						for (auto &sw : cs->switches) +							cases.insert(cases.end(), sw->cases.begin(), sw->cases.end()); +					} +				} +			} +		} +		if (updates) +		{ +			for (auto mod : design_copy->modules()) +			{ +				if (mod->get_blackbox_attribute()) +					continue; + +				for (auto &pr : mod->processes) +				{ +					for (auto &sy : pr.second->syncs) +					{ +						for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) +						{ +							if (index++ == seed) +							{ +								log("Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); +								sy->actions.erase(it); +								return design_copy; +							} +						} +					} +				} +			} +		}  		return NULL;  	} @@ -232,7 +292,7 @@ struct BugpointPass : public Pass {  	{  		string yosys_cmd = "yosys", script, grep;  		bool fast = false, clean = false; -		bool modules = false, ports = false, cells = false, connections = false, has_part = false; +		bool modules = false, ports = false, cells = false, connections = false, assigns = false, updates = false, has_part = false;  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) @@ -277,6 +337,16 @@ struct BugpointPass : public Pass {  				has_part = true;  				continue;  			} +			if (args[argidx] == "-assigns") { +				assigns = true; +				has_part = true; +				continue; +			} +			if (args[argidx] == "-updates") { +				updates = true; +				has_part = true; +				continue; +			}  			break;  		}  		extra_args(args, argidx, design); @@ -290,6 +360,8 @@ struct BugpointPass : public Pass {  			ports = true;  			cells = true;  			connections = true; +			assigns = true; +			updates = true;  		}  		if (!design->full_selection()) @@ -305,7 +377,7 @@ struct BugpointPass : public Pass {  		bool found_something = false, stage2 = false;  		while (true)  		{ -			if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections)) +			if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections, assigns, updates))  			{  				simplified = clean_design(simplified, fast, /*do_delete=*/true); diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc index 397fe46a1..4b56979f8 100644 --- a/passes/proc/Makefile.inc +++ b/passes/proc/Makefile.inc @@ -1,5 +1,6 @@  OBJS += passes/proc/proc.o +OBJS += passes/proc/proc_prune.o  OBJS += passes/proc/proc_clean.o  OBJS += passes/proc/proc_rmdead.o  OBJS += passes/proc/proc_init.o @@ -7,4 +8,3 @@ OBJS += passes/proc/proc_arst.o  OBJS += passes/proc/proc_mux.o  OBJS += passes/proc/proc_dlatch.o  OBJS += passes/proc/proc_dff.o - diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc index ef7cb0f71..a5b4a3112 100644 --- a/passes/proc/proc.cc +++ b/passes/proc/proc.cc @@ -37,6 +37,7 @@ struct ProcPass : public Pass {  		log("\n");  		log("    proc_clean\n");  		log("    proc_rmdead\n"); +		log("    proc_prune\n");  		log("    proc_init\n");  		log("    proc_arst\n");  		log("    proc_mux\n"); @@ -83,6 +84,7 @@ struct ProcPass : public Pass {  		Pass::call(design, "proc_clean");  		if (!ifxmode)  			Pass::call(design, "proc_rmdead"); +		Pass::call(design, "proc_prune");  		Pass::call(design, "proc_init");  		if (global_arst.empty())  			Pass::call(design, "proc_arst"); diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index b69eba3f9..d069f152a 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -172,7 +172,7 @@ restart_proc_arst:  					sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;  				}  				for (auto &action : sync->actions) { -					RTLIL::SigSpec rspec = action.second; +					RTLIL::SigSpec rspec = assign_map(action.second);  					RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());  					for (int i = 0; i < GetSize(rspec); i++)  						if (rspec[i].wire == NULL) diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 52141a8ec..97f4c6573 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -143,7 +143,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m  YOSYS_NAMESPACE_END  PRIVATE_NAMESPACE_BEGIN -void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count) +void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool quiet)  {  	int count = 0;  	bool did_something = true; @@ -160,7 +160,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)  		did_something = false;  		proc_clean_case(&proc->root_case, did_something, count, -1);  	} -	if (count > 0) +	if (count > 0 && !quiet)  		log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count, count == 1 ? "" : "es", mod->name.c_str(), proc->name.c_str());  	total_count += count;  } @@ -171,7 +171,10 @@ struct ProcCleanPass : public Pass {  	{  		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|  		log("\n"); -		log("    proc_clean [selection]\n"); +		log("    proc_clean [options] [selection]\n"); +		log("\n"); +		log("    -quiet\n"); +		log("        do not print any messages.\n");  		log("\n");  		log("This pass removes empty parts of processes and ultimately removes a process\n");  		log("if it contains only empty structures.\n"); @@ -180,9 +183,20 @@ struct ProcCleanPass : public Pass {  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE  	{  		int total_count = 0; -		log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); +		bool quiet = false; + +		if (find(args.begin(), args.end(), "-quiet") == args.end()) +			log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); -		extra_args(args, 1, design); +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) +		{ +			if (args[argidx] == "-quiet") { +				quiet = true; +				continue; +			} +		} +		extra_args(args, argidx, design);  		for (auto mod : design->modules()) {  			std::vector<RTLIL::IdString> delme; @@ -191,10 +205,11 @@ struct ProcCleanPass : public Pass {  			for (auto &proc_it : mod->processes) {  				if (!design->selected(mod, proc_it.second))  					continue; -				proc_clean(mod, proc_it.second, total_count); +				proc_clean(mod, proc_it.second, total_count, quiet);  				if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&  						proc_it.second->root_case.actions.size() == 0) { -					log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); +					if (!quiet) +						log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());  					delme.push_back(proc_it.first);  				}  			} @@ -204,7 +219,8 @@ struct ProcCleanPass : public Pass {  			}  		} -		log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es"); +		if (!quiet) +			log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es");  	}  } ProcCleanPass; diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc index e2dc07e53..462a384b7 100644 --- a/passes/proc/proc_init.cc +++ b/passes/proc/proc_init.cc @@ -26,21 +26,7 @@  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN -void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule) -{ -	log_assert(rule.compare.size() == 0); - -	while (1) { -		RTLIL::SigSpec tmp = sig; -		for (auto &it : rule.actions) -			tmp.replace(it.first, it.second); -		if (tmp == sig) -			break; -		sig = tmp; -	} -} - -void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) +void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)  {  	bool found_init = false; @@ -53,9 +39,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)  			for (auto &action : sync->actions)  			{  				RTLIL::SigSpec lhs = action.first; -				RTLIL::SigSpec rhs = action.second; - -				proc_get_const(rhs, proc->root_case); +				RTLIL::SigSpec rhs = sigmap(action.second);  				if (!rhs.is_fully_const())  					log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs)); @@ -120,10 +104,12 @@ struct ProcInitPass : public Pass {  		extra_args(args, 1, design);  		for (auto mod : design->modules()) -			if (design->selected(mod)) +			if (design->selected(mod)) { +				SigMap sigmap(mod);  				for (auto &proc_it : mod->processes)  					if (design->selected(mod, proc_it.second)) -						proc_init(mod, proc_it.second); +						proc_init(mod, sigmap, proc_it.second); +			}  	}  } ProcInitPass; diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index aac0b121c..d029282fd 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -144,7 +144,13 @@ struct SnippetSwCache  	}  }; -RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, bool ifxmode) +void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs) +{ +	cell->attributes = sw->attributes; +	cell->add_strpool_attribute("\\src", cs->get_strpool_attribute("\\src")); +} + +RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)  {  	std::stringstream sstr;  	sstr << "$procmux$" << (autoidx++); @@ -173,7 +179,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  		{  			// create compare cell  			RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq"); -			eq_cell->attributes = sw->attributes; +			apply_attrs(eq_cell, sw, cs);  			eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);  			eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0); @@ -199,7 +205,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  		// reduce cmp vector to one logic signal  		RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or"); -		any_cell->attributes = sw->attributes; +		apply_attrs(any_cell, sw, cs);  		any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);  		any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width); @@ -212,7 +218,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  	return RTLIL::SigSpec(ctrl_wire);  } -RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)  {  	log_assert(when_signal.size() == else_signal.size()); @@ -224,7 +230,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  		return when_signal;  	// compare results -	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); +	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);  	if (ctrl_sig.size() == 0)  		return when_signal;  	log_assert(ctrl_sig.size() == 1); @@ -234,7 +240,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  	// create the multiplexer itself  	RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux"); -	mux_cell->attributes = sw->attributes; +	apply_attrs(mux_cell, sw, cs);  	mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size());  	mux_cell->setPort("\\A", else_signal); @@ -246,7 +252,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s  	return RTLIL::SigSpec(result_wire);  } -void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)  {  	log_assert(last_mux_cell != NULL);  	log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size()); @@ -254,7 +260,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve  	if (when_signal == last_mux_cell->getPort("\\A"))  		return; -	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); +	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);  	log_assert(ctrl_sig.size() == 1);  	last_mux_cell->type = "$pmux"; @@ -395,9 +401,9 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d  			RTLIL::CaseRule *cs2 = sw->cases[case_idx];  			RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode);  			if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1]) -				append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); +				append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, cs2, ifxmode);  			else -				result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); +				result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, cs2, ifxmode);  		}  	} diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc new file mode 100644 index 000000000..9e00b0a8a --- /dev/null +++ b/passes/proc/proc_prune.cc @@ -0,0 +1,158 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2019  whitequark <whitequark@whitequark.org> + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/log.h" +#include <stdlib.h> +#include <stdio.h> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct PruneWorker +{ +	RTLIL::Module *module; +	SigMap sigmap; + +	int removed_count = 0, promoted_count = 0; + +	PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {} + +	pool<RTLIL::SigBit> do_switch(RTLIL::SwitchRule *sw, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected) +	{ +		pool<RTLIL::SigBit> all_assigned; +		bool full_case = sw->get_bool_attribute("\\full_case"); +		bool first = true; +		for (auto it : sw->cases) { +			if (it->compare.empty()) +				full_case = true; +			pool<RTLIL::SigBit> case_assigned = do_case(it, assigned, affected); +			if (first) { +				first = false; +				all_assigned = case_assigned; +			} else { +				for (auto &bit : all_assigned) +					if (!case_assigned[bit]) +						all_assigned.erase(bit); +			} +		} +		if (full_case) +			assigned.insert(all_assigned.begin(), all_assigned.end()); +		return assigned; +	} + +	pool<RTLIL::SigBit> do_case(RTLIL::CaseRule *cs, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected, +	                            bool root = false) +	{ +		for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) { +			pool<RTLIL::SigBit> sw_assigned = do_switch((*it), assigned, affected); +			assigned.insert(sw_assigned.begin(), sw_assigned.end()); +		} +		pool<RTLIL::SigSig> remove; +		for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) { +			RTLIL::SigSpec lhs = sigmap(it->first); +			bool redundant = true; +			for (auto &bit : lhs) { +				if (bit.wire && !assigned[bit]) { +					redundant = false; +					break; +				} +			} +			if (redundant) { +				removed_count++; +				remove.insert(*it); +			} else { +				if (root) { +					bool promotable = true; +					for (auto &bit : lhs) { +						if (bit.wire && affected[bit]) { +							promotable = false; +							break; +						} +					} +					if (promotable) { +						promoted_count++; +						module->connect(*it); +						remove.insert(*it); +					} +				} +				for (auto &bit : lhs) +					if (bit.wire) +						assigned.insert(bit); +				for (auto &bit : lhs) +					if (bit.wire) +						affected.insert(bit); +			} +		} +		for (auto it = cs->actions.begin(); it != cs->actions.end(); ) { +			if (remove[*it]) { +				it = cs->actions.erase(it); +			} else it++; +		} +		return assigned; +	} + +	void do_process(RTLIL::Process *pr) +	{ +		pool<RTLIL::SigBit> affected; +		do_case(&pr->root_case, {}, affected, /*root=*/true); +	} +}; + +struct ProcPrunePass : public Pass { +	ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { } +	void help() YS_OVERRIDE +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    proc_prune [selection]\n"); +		log("\n"); +		log("This pass identifies assignments in processes that are always overwritten by\n"); +		log("a later assignment to the same signal and removes them.\n"); +		log("\n"); +	} +	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE +	{ +		int total_removed_count = 0, total_promoted_count = 0; +		log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n"); + +		extra_args(args, 1, design); + +		for (auto mod : design->modules()) { +			if (!design->selected(mod)) +				continue; +			PruneWorker worker(mod); +			for (auto &proc_it : mod->processes) { +				if (!design->selected(mod, proc_it.second)) +					continue; +				worker.do_process(proc_it.second); +			} +			total_removed_count += worker.removed_count; +			total_promoted_count += worker.promoted_count; +		} + +		log("Removed %d redundant assignment%s.\n", +		    total_removed_count, total_removed_count == 1 ? "" : "s"); +		log("Promoted %d assignment%s to connection%s.\n", +		    total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s"); +	} +} ProcPrunePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 49ec795d3..4bb4aa047 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -253,6 +253,13 @@ struct Clk2fflogicPass : public Pass {  						SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);  						Const rstval = cell->parameters["\\ARST_VALUE"]; +						Wire *past_arst = module->addWire(NEW_ID); +						module->addFf(NEW_ID, arst, past_arst); +						if (cell->parameters["\\ARST_POLARITY"].as_bool()) +							arst = module->LogicOr(NEW_ID, arst, past_arst); +						else +							arst = module->LogicAnd(NEW_ID, arst, past_arst); +  						if (cell->parameters["\\ARST_POLARITY"].as_bool())  							module->addMux(NEW_ID, qval, rstval, arst, sig_q);  						else diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index c84cfc39a..d53378a29 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -632,10 +632,15 @@ struct MuxcoverPass : public Pass {  		log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n");  		log("\n");  		log("    -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); -		log("        Use the specified types of MUXes (with optional integer costs). If none\n"); -		log("        of these options are given, the effect is the same as if all of them are.\n"); -		log("        Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); -		log("                       $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16); +		log("        Cover $_MUX_ trees using the specified types of MUXes (with optional\n"); +		log("        integer costs). If none of these options are given, the effect is the\n"); +		log("        same as if all of them are.\n"); +		log("        Default costs: $_MUX4_ = %d, $_MUX8_ = %d, \n", COST_MUX4, COST_MUX8); +		log("                       $_MUX16_ = %d\n", COST_MUX16); +		log("\n"); +		log("    -mux2=cost\n"); +		log("        Use the specified cost for $_MUX_ cells when making covering decisions.\n"); +		log("        Default cost: $_MUX_ = %d\n", COST_MUX2);  		log("\n");  		log("    -dmux=cost\n");  		log("        Use the specified cost for $_MUX_ cells used in decoders.\n"); @@ -661,6 +666,7 @@ struct MuxcoverPass : public Pass {  		bool nodecode = false;  		bool nopartial = false;  		int cost_dmux = COST_DMUX; +		int cost_mux2 = COST_MUX2;  		int cost_mux4 = COST_MUX4;  		int cost_mux8 = COST_MUX8;  		int cost_mux16 = COST_MUX16; @@ -669,11 +675,15 @@ struct MuxcoverPass : public Pass {  		for (argidx = 1; argidx < args.size(); argidx++)  		{  			const auto &arg = args[argidx]; +			if (arg.size() >= 6 && arg.substr(0,6) == "-mux2=") { +				cost_mux2 = std::stoi(arg.substr(6)); +				continue; +			}  			if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") {  				use_mux4 = true;  				if (arg.size() > 5) {  					if (arg[5] != '=') break; -					cost_mux4 = atoi(arg.substr(6).c_str()); +					cost_mux4 = std::stoi(arg.substr(6));  				}  				continue;  			} @@ -681,7 +691,7 @@ struct MuxcoverPass : public Pass {  				use_mux8 = true;  				if (arg.size() > 5) {  					if (arg[5] != '=') break; -					cost_mux8 = atoi(arg.substr(6).c_str()); +					cost_mux8 = std::stoi(arg.substr(6));  				}  				continue;  			} @@ -689,12 +699,12 @@ struct MuxcoverPass : public Pass {  				use_mux16 = true;  				if (arg.size() > 6) {  					if (arg[6] != '=') break; -					cost_mux16 = atoi(arg.substr(7).c_str()); +					cost_mux16 = std::stoi(arg.substr(7));  				}  				continue;  			}  			if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") { -				cost_dmux = atoi(arg.substr(6).c_str()); +				cost_dmux = std::stoi(arg.substr(6));  				continue;  			}  			if (arg == "-nodecode") { @@ -722,6 +732,7 @@ struct MuxcoverPass : public Pass {  			worker.use_mux8 = use_mux8;  			worker.use_mux16 = use_mux16;  			worker.cost_dmux = cost_dmux; +			worker.cost_mux2 = cost_mux2;  			worker.cost_mux4 = cost_mux4;  			worker.cost_mux8 = cost_mux8;  			worker.cost_mux16 = cost_mux16; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index ab0bd3b54..ceb053825 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -649,10 +649,13 @@ struct TechmapWorker  									unique_bit_id[bit] = unique_bit_id_counter++;  						} +					// Find highest bit set  					int bits = 0;  					for (int i = 0; i < 32; i++)  						if (((unique_bit_id_counter-1) & (1 << i)) != 0)  							bits = i; +					// Increment index by one to get number of bits +					bits++;  					if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_"))  						parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits;  | 
