mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Merge 26e293d71f into d0a41d4f58
				
					
				
			This commit is contained in:
		
						commit
						7b9f79d6d1
					
				
					 24 changed files with 521 additions and 284 deletions
				
			
		| 
						 | 
				
			
			@ -494,8 +494,8 @@ struct FlowGraph {
 | 
			
		|||
	void add_case_rule_defs_uses(Node *node, const RTLIL::CaseRule *case_)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto &action : case_->actions) {
 | 
			
		||||
			add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false);
 | 
			
		||||
			add_uses(node, action.second);
 | 
			
		||||
			add_defs(node, action.lhs, /*is_ff=*/false, /*inlinable=*/false);
 | 
			
		||||
			add_uses(node, action.rhs);
 | 
			
		||||
		}
 | 
			
		||||
		for (auto sub_switch : case_->switches) {
 | 
			
		||||
			add_uses(node, sub_switch->signal);
 | 
			
		||||
| 
						 | 
				
			
			@ -512,10 +512,10 @@ struct FlowGraph {
 | 
			
		|||
		for (auto sync : process->syncs) {
 | 
			
		||||
			for (auto &action : sync->actions) {
 | 
			
		||||
				if (sync->type == RTLIL::STp || sync->type == RTLIL::STn || sync->type == RTLIL::STe)
 | 
			
		||||
					add_defs(node, action.first, /*is_ff=*/true,  /*inlinable=*/false);
 | 
			
		||||
					add_defs(node, action.lhs, /*is_ff=*/true,  /*inlinable=*/false);
 | 
			
		||||
				else
 | 
			
		||||
					add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false);
 | 
			
		||||
				add_uses(node, action.second);
 | 
			
		||||
					add_defs(node, action.lhs, /*is_ff=*/false, /*inlinable=*/false);
 | 
			
		||||
				add_uses(node, action.rhs);
 | 
			
		||||
			}
 | 
			
		||||
			for (auto &memwr : sync->mem_write_actions) {
 | 
			
		||||
				add_uses(node, memwr.address);
 | 
			
		||||
| 
						 | 
				
			
			@ -1623,12 +1623,12 @@ struct CxxrtlWorker {
 | 
			
		|||
				collect_sigspec_rhs(port.second, for_debug, cells);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void dump_assign(const RTLIL::SigSig &sigsig, bool for_debug = false)
 | 
			
		||||
	void dump_assign(const RTLIL::SyncAction &action, bool for_debug = false)
 | 
			
		||||
	{
 | 
			
		||||
		f << indent;
 | 
			
		||||
		dump_sigspec_lhs(sigsig.first, for_debug);
 | 
			
		||||
		dump_sigspec_lhs(action.lhs, for_debug);
 | 
			
		||||
		f << " = ";
 | 
			
		||||
		dump_sigspec_rhs(sigsig.second, for_debug);
 | 
			
		||||
		dump_sigspec_rhs(action.rhs, for_debug);
 | 
			
		||||
		f << ";\n";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,7 +189,7 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
 | 
			
		|||
 | 
			
		||||
void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
 | 
			
		||||
{
 | 
			
		||||
	for (const auto& [lhs, rhs] : cs->actions) {
 | 
			
		||||
	for (const auto& [lhs, rhs, _] : cs->actions) {
 | 
			
		||||
		f << stringf("%s" "assign ", indent);
 | 
			
		||||
		dump_sigspec(f, lhs);
 | 
			
		||||
		f << stringf(" ");
 | 
			
		||||
| 
						 | 
				
			
			@ -243,7 +243,7 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
 | 
			
		|||
	case RTLIL::STi: f << stringf("init\n"); break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (const auto& [lhs, rhs] : sy->actions) {
 | 
			
		||||
	for (const auto& [lhs, rhs, _] : sy->actions) {
 | 
			
		||||
		f << stringf("%s  update ", indent);
 | 
			
		||||
		dump_sigspec(f, lhs);
 | 
			
		||||
		f << stringf(" ");
 | 
			
		||||
| 
						 | 
				
			
			@ -375,8 +375,11 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
 | 
			
		|||
		for (auto* module : design->modules()) {
 | 
			
		||||
			if (design->selected_whole_module(module->name))
 | 
			
		||||
				flag_m = true;
 | 
			
		||||
			if (design->selected(module))
 | 
			
		||||
			if (design->selected(module)) {
 | 
			
		||||
				count_selected_mods++;
 | 
			
		||||
				if (module->has_processes())
 | 
			
		||||
					log_warning("Module %s contains processes. Case action sources attributes will be lost.\n", log_id(module));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (count_selected_mods > 1)
 | 
			
		||||
			flag_m = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2122,13 +2122,14 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
 | 
			
		|||
void dump_case_actions(std::ostream &f, std::string indent, RTLIL::CaseRule *cs)
 | 
			
		||||
{
 | 
			
		||||
	for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
 | 
			
		||||
		if (it->first.size() == 0)
 | 
			
		||||
		if (it->lhs.size() == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		f << stringf("%s  ", indent);
 | 
			
		||||
		dump_sigspec(f, it->first);
 | 
			
		||||
		dump_sigspec(f, it->lhs);
 | 
			
		||||
		f << stringf(" = ");
 | 
			
		||||
		dump_sigspec(f, it->second);
 | 
			
		||||
		dump_sigspec(f, it->rhs);
 | 
			
		||||
		f << stringf(";\n");
 | 
			
		||||
		// TODO
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2259,7 +2260,7 @@ void case_body_find_regs(RTLIL::CaseRule *cs)
 | 
			
		|||
		case_body_find_regs(*it2);
 | 
			
		||||
 | 
			
		||||
	for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
 | 
			
		||||
		for (auto &c : it->first.chunks())
 | 
			
		||||
		for (auto &c : it->lhs.chunks())
 | 
			
		||||
			if (c.wire != NULL)
 | 
			
		||||
				reg_wires.insert(c.wire->name);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2271,7 +2272,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
 | 
			
		|||
		case_body_find_regs(&proc->root_case);
 | 
			
		||||
		for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
 | 
			
		||||
		for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
 | 
			
		||||
			for (auto &c : it2->first.chunks())
 | 
			
		||||
			for (auto &c : it2->lhs.chunks())
 | 
			
		||||
				if (c.wire != NULL)
 | 
			
		||||
					reg_wires.insert(c.wire->name);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2328,12 +2329,12 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
 | 
			
		||||
			if (it->first.size() == 0)
 | 
			
		||||
			if (it->lhs.size() == 0)
 | 
			
		||||
				continue;
 | 
			
		||||
			f << stringf("%s  ", indent);
 | 
			
		||||
			dump_sigspec(f, it->first);
 | 
			
		||||
			dump_sigspec(f, it->lhs);
 | 
			
		||||
			f << stringf(" <= ");
 | 
			
		||||
			dump_sigspec(f, it->second);
 | 
			
		||||
			dump_sigspec(f, it->rhs);
 | 
			
		||||
			f << stringf(";\n");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ value from the ``B`` input is sent to the output. So the `$mux` cell implements
 | 
			
		|||
the function :verilog:`Y = S ? B : A`.
 | 
			
		||||
 | 
			
		||||
The `$pmux` cell is used to multiplex between many inputs using a one-hot select
 | 
			
		||||
signal. Cells of this type have a ``WIDTH`` and a ``S_WIDTH`` parameter and
 | 
			
		||||
signal. Cells of this type have a ``WIDTH`` and an ``S_WIDTH`` parameter and
 | 
			
		||||
inputs ``A``, ``B``, and ``S`` and an output ``Y``. The ``S`` input is
 | 
			
		||||
``S_WIDTH`` bits wide. The ``A`` input and the output are both ``WIDTH`` bits
 | 
			
		||||
wide and the ``B`` input is ``WIDTH*S_WIDTH`` bits wide. When all bits of ``S``
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -382,7 +382,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		if (found_anyedge_syncs) {
 | 
			
		||||
			if (found_global_syncs)
 | 
			
		||||
				always->input_error("Found non-synthesizable event list!\n");
 | 
			
		||||
			log("Note: Assuming pure combinatorial block at %s in\n", always->loc_string());
 | 
			
		||||
			log("Note: Assuming pure combinatorial block at %s in\n", always->location.to_string());
 | 
			
		||||
			log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");
 | 
			
		||||
			log("use of @* instead of @(...) for better match of synthesis and simulation.\n");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -402,14 +402,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				syncrule->signal = child->children[0]->genRTLIL();
 | 
			
		||||
				if (GetSize(syncrule->signal) != 1)
 | 
			
		||||
					always->input_error("Found posedge/negedge event on a signal that is not 1 bit wide!\n");
 | 
			
		||||
				addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
 | 
			
		||||
				addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, child.get(), true);
 | 
			
		||||
				proc->syncs.push_back(syncrule);
 | 
			
		||||
			}
 | 
			
		||||
		if (proc->syncs.empty()) {
 | 
			
		||||
			RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
 | 
			
		||||
			syncrule->type = found_global_syncs ? RTLIL::STg : RTLIL::STa;
 | 
			
		||||
			syncrule->signal = RTLIL::SigSpec();
 | 
			
		||||
			addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
 | 
			
		||||
			addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, always.get(), true);
 | 
			
		||||
			proc->syncs.push_back(syncrule);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +417,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		if ((flag_nolatches || always->get_bool_attribute(ID::nolatches) || current_module->get_bool_attribute(ID::nolatches)) && !found_clocked_sync) {
 | 
			
		||||
			subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
 | 
			
		||||
		} else {
 | 
			
		||||
			addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
 | 
			
		||||
			addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from, always.get());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// process the AST
 | 
			
		||||
| 
						 | 
				
			
			@ -441,7 +441,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				RTLIL::SigSpec lhs = init_lvalue_c;
 | 
			
		||||
				RTLIL::SigSpec rhs = init_rvalue.extract(offset, init_lvalue_c.width);
 | 
			
		||||
				remove_unwanted_lvalue_bits(lhs, rhs);
 | 
			
		||||
				sync->actions.push_back(RTLIL::SigSig(lhs, rhs));
 | 
			
		||||
				// TODO
 | 
			
		||||
				sync->actions.push_back({lhs, rhs, Const("")});
 | 
			
		||||
				offset += lhs.size();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -548,7 +549,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
	void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
 | 
			
		||||
			it->first.remove2(pattern, &it->second);
 | 
			
		||||
			it->lhs.remove2(pattern, &it->rhs);
 | 
			
		||||
 | 
			
		||||
		for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
 | 
			
		||||
			for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
 | 
			
		||||
| 
						 | 
				
			
			@ -557,7 +558,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
	// add an assignment (aka "action") but split it up in chunks. this way huge assignments
 | 
			
		||||
	// are avoided and the generated $mux cells have a more "natural" size.
 | 
			
		||||
	void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool inSyncRule = false)
 | 
			
		||||
	void addChunkActions(std::vector<RTLIL::SyncAction> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, AstNode* ast, bool inSyncRule = false)
 | 
			
		||||
	{
 | 
			
		||||
		if (inSyncRule && initSyncSignals.size() > 0) {
 | 
			
		||||
			init_lvalue.append(lvalue.extract(initSyncSignals));
 | 
			
		||||
| 
						 | 
				
			
			@ -573,7 +574,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
			if (inSyncRule && lvalue_c.wire && lvalue_c.wire->get_bool_attribute(ID::nosync))
 | 
			
		||||
				rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.size());
 | 
			
		||||
			remove_unwanted_lvalue_bits(lhs, rhs);
 | 
			
		||||
			actions.push_back(RTLIL::SigSig(lhs, rhs));
 | 
			
		||||
			actions.push_back({lhs, rhs, ast ? ast->loc_string() : ""});
 | 
			
		||||
			offset += lhs.size();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -613,7 +614,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
				removeSignalFromCaseTree(lvalue, current_case);
 | 
			
		||||
				remove_unwanted_lvalue_bits(lvalue, rvalue);
 | 
			
		||||
				current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
 | 
			
		||||
				current_case->actions.push_back({lvalue, rvalue, ast->loc_string()});
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -657,10 +658,11 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
						subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
 | 
			
		||||
 | 
			
		||||
					RTLIL::CaseRule *backup_case = current_case;
 | 
			
		||||
					// here
 | 
			
		||||
					current_case = new RTLIL::CaseRule;
 | 
			
		||||
					set_src_attr(current_case, child.get());
 | 
			
		||||
					last_generated_case = current_case;
 | 
			
		||||
					addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
 | 
			
		||||
					addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue, child.get());
 | 
			
		||||
					for (auto& node : child->children) {
 | 
			
		||||
						if (node->type == AST_DEFAULT)
 | 
			
		||||
							default_case = current_case;
 | 
			
		||||
| 
						 | 
				
			
			@ -687,13 +689,13 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
					last_generated_case->compare.clear();
 | 
			
		||||
			#else
 | 
			
		||||
					default_case = new RTLIL::CaseRule;
 | 
			
		||||
					addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
 | 
			
		||||
					addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)), ast);
 | 
			
		||||
					sw->cases.push_back(default_case);
 | 
			
		||||
			#endif
 | 
			
		||||
				} else {
 | 
			
		||||
					if (default_case == nullptr) {
 | 
			
		||||
						default_case = new RTLIL::CaseRule;
 | 
			
		||||
						addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
 | 
			
		||||
						addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue, ast);
 | 
			
		||||
					}
 | 
			
		||||
					sw->cases.push_back(default_case);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -703,7 +705,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
				this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
 | 
			
		||||
				removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
 | 
			
		||||
				addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
 | 
			
		||||
				addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp, ast);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -728,8 +730,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
				Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
 | 
			
		||||
				set_src_attr(en, ast);
 | 
			
		||||
				proc->root_case.actions.push_back(SigSig(en, false));
 | 
			
		||||
				current_case->actions.push_back(SigSig(en, true));
 | 
			
		||||
				proc->root_case.actions.push_back({en, SigSpec(false), ast->loc_string()});
 | 
			
		||||
				current_case->actions.push_back({en, SigSpec(true), ast->loc_string()});
 | 
			
		||||
 | 
			
		||||
				RTLIL::SigSpec triggers;
 | 
			
		||||
				RTLIL::Const::Builder polarity_builder;
 | 
			
		||||
| 
						 | 
				
			
			@ -826,8 +828,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
				Wire *en = current_module->addWire(cellname.str() + "_EN", 1);
 | 
			
		||||
				set_src_attr(en, ast);
 | 
			
		||||
				proc->root_case.actions.push_back(SigSig(en, false));
 | 
			
		||||
				current_case->actions.push_back(SigSig(en, true));
 | 
			
		||||
				proc->root_case.actions.push_back({en, SigSpec(false), ast->loc_string()});
 | 
			
		||||
				current_case->actions.push_back({en, SigSpec(true), ast->loc_string()});
 | 
			
		||||
 | 
			
		||||
				RTLIL::SigSpec triggers;
 | 
			
		||||
				RTLIL::Const::Builder polarity_builder;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
 | 
			
		||||
#include "kernel/register.h"
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include "kernel/utils.h"
 | 
			
		||||
#include <charconv>
 | 
			
		||||
#include <deque>
 | 
			
		||||
| 
						 | 
				
			
			@ -623,7 +624,7 @@ struct RTLILFrontendWorker {
 | 
			
		|||
						"The assign statement is reordered to come before all switch statements.");
 | 
			
		||||
				RTLIL::SigSpec s1 = parse_sigspec();
 | 
			
		||||
				RTLIL::SigSpec s2 = parse_sigspec();
 | 
			
		||||
				current_case->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2)));
 | 
			
		||||
				current_case->actions.push_back({std::move(s1), std::move(s2), Const("")});
 | 
			
		||||
				expect_eol();
 | 
			
		||||
			} else
 | 
			
		||||
				return;
 | 
			
		||||
| 
						 | 
				
			
			@ -714,7 +715,7 @@ struct RTLILFrontendWorker {
 | 
			
		|||
				if (try_parse_keyword("update")) {
 | 
			
		||||
					RTLIL::SigSpec s1 = parse_sigspec();
 | 
			
		||||
					RTLIL::SigSpec s2 = parse_sigspec();
 | 
			
		||||
					rule->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2)));
 | 
			
		||||
					rule->actions.push_back({std::move(s1), std::move(s2), Const("")});
 | 
			
		||||
					expect_eol();
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3026,6 +3026,7 @@ case_item:
 | 
			
		|||
		extra->case_type_stack.pop_back();
 | 
			
		||||
		SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4);
 | 
			
		||||
		extra->ast_stack.pop_back();
 | 
			
		||||
		SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2);
 | 
			
		||||
		extra->ast_stack.pop_back();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,6 +116,7 @@ namespace RTLIL
 | 
			
		|||
	struct CaseRule;
 | 
			
		||||
	struct SwitchRule;
 | 
			
		||||
	struct MemWriteAction;
 | 
			
		||||
	struct SyncAction;
 | 
			
		||||
	struct SyncRule;
 | 
			
		||||
	struct Process;
 | 
			
		||||
	struct Binding;
 | 
			
		||||
| 
						 | 
				
			
			@ -1113,6 +1114,13 @@ struct RTLIL::AttrObject
 | 
			
		|||
	std::string get_src_attribute() const {
 | 
			
		||||
		return get_string_attribute(ID::src);
 | 
			
		||||
	}
 | 
			
		||||
	void transfer_attribute(const AttrObject* from, const IdString& attr) {
 | 
			
		||||
		if (from->has_attribute(attr))
 | 
			
		||||
			attributes[attr] = from->attributes.at(attr);
 | 
			
		||||
	}
 | 
			
		||||
	void transfer_src_attribute(const AttrObject* from) {
 | 
			
		||||
		transfer_attribute(from, ID::src);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_hdlname_attribute(const vector<string> &hierarchy);
 | 
			
		||||
	vector<string> get_hdlname_attribute() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -2194,7 +2202,7 @@ public:
 | 
			
		|||
struct RTLIL::CaseRule : public RTLIL::AttrObject
 | 
			
		||||
{
 | 
			
		||||
	std::vector<RTLIL::SigSpec> compare;
 | 
			
		||||
	std::vector<RTLIL::SigSig> actions;
 | 
			
		||||
	std::vector<RTLIL::SyncAction> actions;
 | 
			
		||||
	std::vector<RTLIL::SwitchRule*> switches;
 | 
			
		||||
 | 
			
		||||
	~CaseRule();
 | 
			
		||||
| 
						 | 
				
			
			@ -2229,11 +2237,18 @@ struct RTLIL::MemWriteAction : RTLIL::AttrObject
 | 
			
		|||
	RTLIL::Const priority_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RTLIL::SyncAction
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SigSpec lhs;
 | 
			
		||||
	RTLIL::SigSpec rhs;
 | 
			
		||||
	RTLIL::Const src;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RTLIL::SyncRule
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SyncType type;
 | 
			
		||||
	RTLIL::SigSpec signal;
 | 
			
		||||
	std::vector<RTLIL::SigSig> actions;
 | 
			
		||||
	std::vector<RTLIL::SyncAction> actions;
 | 
			
		||||
	std::vector<RTLIL::MemWriteAction> mem_write_actions;
 | 
			
		||||
 | 
			
		||||
	template<typename T> void rewrite_sigspecs(T &functor);
 | 
			
		||||
| 
						 | 
				
			
			@ -2363,8 +2378,8 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
 | 
			
		|||
	for (auto &it : compare)
 | 
			
		||||
		functor(it);
 | 
			
		||||
	for (auto &it : actions) {
 | 
			
		||||
		functor(it.first);
 | 
			
		||||
		functor(it.second);
 | 
			
		||||
		functor(it.lhs);
 | 
			
		||||
		functor(it.rhs);
 | 
			
		||||
	}
 | 
			
		||||
	for (auto it : switches)
 | 
			
		||||
		it->rewrite_sigspecs(functor);
 | 
			
		||||
| 
						 | 
				
			
			@ -2375,7 +2390,7 @@ void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
 | 
			
		|||
	for (auto &it : compare)
 | 
			
		||||
		functor(it);
 | 
			
		||||
	for (auto &it : actions) {
 | 
			
		||||
		functor(it.first, it.second);
 | 
			
		||||
		functor(it.lhs, it.rhs);
 | 
			
		||||
	}
 | 
			
		||||
	for (auto it : switches)
 | 
			
		||||
		it->rewrite_sigspecs2(functor);
 | 
			
		||||
| 
						 | 
				
			
			@ -2402,8 +2417,8 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
 | 
			
		|||
{
 | 
			
		||||
	functor(signal);
 | 
			
		||||
	for (auto &it : actions) {
 | 
			
		||||
		functor(it.first);
 | 
			
		||||
		functor(it.second);
 | 
			
		||||
		functor(it.lhs);
 | 
			
		||||
		functor(it.rhs);
 | 
			
		||||
	}
 | 
			
		||||
	for (auto &it : mem_write_actions) {
 | 
			
		||||
		functor(it.address);
 | 
			
		||||
| 
						 | 
				
			
			@ -2417,7 +2432,7 @@ void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
 | 
			
		|||
{
 | 
			
		||||
	functor(signal);
 | 
			
		||||
	for (auto &it : actions) {
 | 
			
		||||
		functor(it.first, it.second);
 | 
			
		||||
		functor(it.lhs, it.rhs);
 | 
			
		||||
	}
 | 
			
		||||
	for (auto &it : mem_write_actions) {
 | 
			
		||||
		functor(it.address);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -363,7 +363,7 @@ struct BugpointPass : public Pass {
 | 
			
		|||
						{
 | 
			
		||||
							if (index++ == seed)
 | 
			
		||||
							{
 | 
			
		||||
								log_header(design, "Trying to remove assign %s %s in %s.%s.\n", log_signal(it->first), log_signal(it->second), log_id(mod), log_id(pr.first));
 | 
			
		||||
								log_header(design, "Trying to remove assign %s %s in %s.%s.\n", log_signal(it->lhs), log_signal(it->rhs), log_id(mod), log_id(pr.first));
 | 
			
		||||
								cs->actions.erase(it);
 | 
			
		||||
								return design_copy;
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +389,7 @@ struct BugpointPass : public Pass {
 | 
			
		|||
						{
 | 
			
		||||
							if (index++ == seed)
 | 
			
		||||
							{
 | 
			
		||||
								log_header(design, "Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal(it->first), log_signal(it->second), log_id(mod), log_id(pr.first));
 | 
			
		||||
								log_header(design, "Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal(it->lhs), log_signal(it->rhs), log_id(mod), log_id(pr.first));
 | 
			
		||||
								sy->actions.erase(it);
 | 
			
		||||
								return design_copy;
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -130,12 +130,12 @@ struct CheckPass : public Pass {
 | 
			
		|||
				std::vector<RTLIL::CaseRule*> all_cases = {&proc_it.second->root_case};
 | 
			
		||||
				for (size_t i = 0; i < all_cases.size(); i++) {
 | 
			
		||||
					for (auto action : all_cases[i]->actions) {
 | 
			
		||||
						for (auto bit : sigmap(action.first))
 | 
			
		||||
						for (auto bit : sigmap(action.lhs))
 | 
			
		||||
							wire_drivers[bit].push_back(
 | 
			
		||||
								stringf("action %s <= %s (case rule) in process %s",
 | 
			
		||||
										log_signal(action.first), log_signal(action.second), log_id(proc_it.first)));
 | 
			
		||||
										log_signal(action.lhs), log_signal(action.rhs), log_id(proc_it.first)));
 | 
			
		||||
 | 
			
		||||
						for (auto bit : sigmap(action.second))
 | 
			
		||||
						for (auto bit : sigmap(action.rhs))
 | 
			
		||||
							if (bit.wire) used_wires.insert(bit);
 | 
			
		||||
					}
 | 
			
		||||
					for (auto switch_ : all_cases[i]->switches) {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +151,11 @@ struct CheckPass : public Pass {
 | 
			
		|||
					for (auto bit : sigmap(sync->signal))
 | 
			
		||||
						if (bit.wire) used_wires.insert(bit);
 | 
			
		||||
					for (auto action : sync->actions) {
 | 
			
		||||
						for (auto bit : sigmap(action.first))
 | 
			
		||||
						for (auto bit : sigmap(action.lhs))
 | 
			
		||||
							wire_drivers[bit].push_back(
 | 
			
		||||
								stringf("action %s <= %s (sync rule) in process %s",
 | 
			
		||||
										log_signal(action.first), log_signal(action.second), log_id(proc_it.first)));
 | 
			
		||||
						for (auto bit : sigmap(action.second))
 | 
			
		||||
										log_signal(action.lhs), log_signal(action.rhs), log_id(proc_it.first)));
 | 
			
		||||
						for (auto bit : sigmap(action.rhs))
 | 
			
		||||
							if (bit.wire) used_wires.insert(bit);
 | 
			
		||||
					}
 | 
			
		||||
					for (auto memwr : sync->mem_write_actions) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "kernel/celltypes.h"
 | 
			
		||||
#include "kernel/mem.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -40,9 +41,9 @@ struct CleanZeroWidthPass : public Pass {
 | 
			
		|||
 | 
			
		||||
	void clean_case(RTLIL::CaseRule *cs)
 | 
			
		||||
	{
 | 
			
		||||
		std::vector<SigSig> new_actions;
 | 
			
		||||
		std::vector<RTLIL::SyncAction> new_actions;
 | 
			
		||||
		for (auto &action : cs->actions)
 | 
			
		||||
			if (GetSize(action.first) != 0)
 | 
			
		||||
			if (GetSize(action.lhs) != 0)
 | 
			
		||||
				new_actions.push_back(action);
 | 
			
		||||
		std::swap(new_actions, cs->actions);
 | 
			
		||||
		for (auto sw : cs->switches)
 | 
			
		||||
| 
						 | 
				
			
			@ -167,9 +168,9 @@ struct CleanZeroWidthPass : public Pass {
 | 
			
		|||
						new_memwr_actions.push_back(memwr);
 | 
			
		||||
					}
 | 
			
		||||
					std::swap(new_memwr_actions, sync->mem_write_actions);
 | 
			
		||||
					std::vector<SigSig> new_actions;
 | 
			
		||||
					std::vector<RTLIL::SyncAction> new_actions;
 | 
			
		||||
					for (auto &action : sync->actions)
 | 
			
		||||
						if (GetSize(action.first) != 0)
 | 
			
		||||
						if (GetSize(action.lhs) != 0)
 | 
			
		||||
							new_actions.push_back(action);
 | 
			
		||||
					std::swap(new_actions, sync->actions);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "kernel/celltypes.h"
 | 
			
		||||
#include "kernel/log_help.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -370,12 +371,12 @@ struct ShowWorker
 | 
			
		|||
				signals.insert(it);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void collect_proc_signals(std::vector<RTLIL::SigSig> &obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
 | 
			
		||||
	void collect_proc_signals(std::vector<RTLIL::SyncAction> &obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto &it : obj) {
 | 
			
		||||
			output_signals.insert(it.first);
 | 
			
		||||
			if (!it.second.is_fully_const())
 | 
			
		||||
				input_signals.insert(it.second);
 | 
			
		||||
			output_signals.insert(it.lhs);
 | 
			
		||||
			if (!it.rhs.is_fully_const())
 | 
			
		||||
				input_signals.insert(it.rhs);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/register.h"
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include "kernel/sigtools.h"
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -89,9 +90,9 @@ void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec
 | 
			
		|||
{
 | 
			
		||||
	for (auto &action : cs->actions) {
 | 
			
		||||
		if (unknown)
 | 
			
		||||
			rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.size()), &rval);
 | 
			
		||||
			rspec.replace(action.lhs, RTLIL::SigSpec(RTLIL::State::Sm, action.rhs.size()), &rval);
 | 
			
		||||
		else
 | 
			
		||||
			rspec.replace(action.first, action.second, &rval);
 | 
			
		||||
			rspec.replace(action.lhs, action.rhs, &rval);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (auto sw : cs->switches) {
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +210,7 @@ void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
 | 
			
		|||
					arst_syncs.push_back(sync);
 | 
			
		||||
					edge_syncs.erase(it);
 | 
			
		||||
					for (auto &action : sync->actions) {
 | 
			
		||||
						action.second = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, action.second, action.first);
 | 
			
		||||
						action.rhs = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, action.rhs, action.lhs);
 | 
			
		||||
					}
 | 
			
		||||
					for (auto &memwr : sync->mem_write_actions) {
 | 
			
		||||
						RTLIL::SigSpec en = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.enable, memwr.enable);
 | 
			
		||||
| 
						 | 
				
			
			@ -294,12 +295,12 @@ struct ProcArstPass : public Pass {
 | 
			
		|||
				proc_arst(mod, proc, assign_map);
 | 
			
		||||
				if (global_arst.empty() || mod->wire(global_arst) == nullptr)
 | 
			
		||||
					continue;
 | 
			
		||||
				std::vector<RTLIL::SigSig> arst_actions;
 | 
			
		||||
				std::vector<RTLIL::SyncAction> arst_actions;
 | 
			
		||||
				for (auto sync : proc->syncs)
 | 
			
		||||
					if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
 | 
			
		||||
						for (auto &act : sync->actions) {
 | 
			
		||||
							RTLIL::SigSpec arst_sig, arst_val;
 | 
			
		||||
							for (auto &chunk : act.first.chunks())
 | 
			
		||||
							for (auto &chunk : act.lhs.chunks())
 | 
			
		||||
								if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
 | 
			
		||||
									RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
 | 
			
		||||
									value.extend_u0(chunk.wire->width, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +311,7 @@ struct ProcArstPass : public Pass {
 | 
			
		|||
							if (arst_sig.size()) {
 | 
			
		||||
								log("Added global reset to process %s: %s <- %s\n",
 | 
			
		||||
										proc->name.c_str(), log_signal(arst_sig), log_signal(arst_val));
 | 
			
		||||
								arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
 | 
			
		||||
								arst_actions.push_back({arst_sig, arst_val, act.src});
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
				if (!arst_actions.empty()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,7 +133,7 @@ YOSYS_NAMESPACE_BEGIN
 | 
			
		|||
void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth)
 | 
			
		||||
{
 | 
			
		||||
	for (size_t i = 0; i < cs->actions.size(); i++) {
 | 
			
		||||
		if (cs->actions[i].first.size() == 0) {
 | 
			
		||||
		if (cs->actions[i].lhs.size() == 0) {
 | 
			
		||||
			did_something = true;
 | 
			
		||||
			cs->actions.erase(cs->actions.begin() + (i--));
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +159,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool
 | 
			
		|||
	bool did_something = true;
 | 
			
		||||
	for (size_t i = 0; i < proc->syncs.size(); i++) {
 | 
			
		||||
		for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
 | 
			
		||||
			if (proc->syncs[i]->actions[j].first.size() == 0)
 | 
			
		||||
			if (proc->syncs[i]->actions[j].lhs.size() == 0)
 | 
			
		||||
				proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
 | 
			
		||||
		if (proc->syncs[i]->actions.size() == 0 && proc->syncs[i]->mem_write_actions.size() == 0) {
 | 
			
		||||
			delete proc->syncs[i];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,8 +34,8 @@ RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
 | 
			
		|||
 | 
			
		||||
	for (auto sync : proc->syncs)
 | 
			
		||||
	for (auto &action : sync->actions)
 | 
			
		||||
		if (action.first.size() > 0) {
 | 
			
		||||
			lvalue = action.first;
 | 
			
		||||
		if (action.lhs.size() > 0) {
 | 
			
		||||
			lvalue = action.lhs;
 | 
			
		||||
			lvalue.sort_and_unify();
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
 | 
			
		|||
	for (auto sync : proc->syncs) {
 | 
			
		||||
		RTLIL::SigSpec this_lvalue;
 | 
			
		||||
		for (auto &action : sync->actions)
 | 
			
		||||
			this_lvalue.append(action.first);
 | 
			
		||||
			this_lvalue.append(action.lhs);
 | 
			
		||||
		this_lvalue.sort_and_unify();
 | 
			
		||||
		RTLIL::SigSpec common_sig = this_lvalue.extract(lvalue);
 | 
			
		||||
		if (common_sig.size() > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -172,35 +172,35 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
 | 
			
		|||
		for (auto sync : proc->syncs)
 | 
			
		||||
		for (auto &action : sync->actions)
 | 
			
		||||
		{
 | 
			
		||||
			if (action.first.extract(sig).size() == 0)
 | 
			
		||||
			if (action.lhs.extract(sig).size() == 0)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
 | 
			
		||||
				RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
 | 
			
		||||
				sig.replace(action.first, action.second, &rstval);
 | 
			
		||||
				sig.replace(action.lhs, action.rhs, &rstval);
 | 
			
		||||
				async_rules.emplace_back(rstval, sync);
 | 
			
		||||
			}
 | 
			
		||||
			else if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
 | 
			
		||||
				if (sync_edge != NULL && sync_edge != sync)
 | 
			
		||||
					log_error("Multiple edge sensitive events found for this signal!\n");
 | 
			
		||||
				sig.replace(action.first, action.second, &insig);
 | 
			
		||||
				sig.replace(action.lhs, action.rhs, &insig);
 | 
			
		||||
				sync_edge = sync;
 | 
			
		||||
			}
 | 
			
		||||
			else if (sync->type == RTLIL::SyncType::STa) {
 | 
			
		||||
				if (sync_always != NULL && sync_always != sync)
 | 
			
		||||
					log_error("Multiple always events found for this signal!\n");
 | 
			
		||||
				sig.replace(action.first, action.second, &insig);
 | 
			
		||||
				sig.replace(action.lhs, action.rhs, &insig);
 | 
			
		||||
				sync_always = sync;
 | 
			
		||||
			}
 | 
			
		||||
			else if (sync->type == RTLIL::SyncType::STg) {
 | 
			
		||||
				sig.replace(action.first, action.second, &insig);
 | 
			
		||||
				sig.replace(action.lhs, action.rhs, &insig);
 | 
			
		||||
				global_clock = true;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				log_error("Event with any-edge sensitivity found for this signal!\n");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			action.first.remove2(sig, &action.second);
 | 
			
		||||
			action.lhs.remove2(sig, &action.rhs);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If all async rules assign the same value, priority ordering between
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +223,8 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
 | 
			
		|||
			// as ones coming from the module
 | 
			
		||||
			single_async_rule.type = RTLIL::SyncType::ST1;
 | 
			
		||||
			single_async_rule.signal = mod->ReduceOr(NEW_ID, triggers);
 | 
			
		||||
			single_async_rule.actions.push_back(RTLIL::SigSig(sig, rstval));
 | 
			
		||||
			// TODO
 | 
			
		||||
			single_async_rule.actions.push_back({sig, rstval, Const("")});
 | 
			
		||||
 | 
			
		||||
			// Replace existing rules with this new rule
 | 
			
		||||
			async_rules.clear();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -364,17 +364,17 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
			
		|||
 | 
			
		||||
		for (auto ss : sr->actions)
 | 
			
		||||
		{
 | 
			
		||||
			db.sigmap.apply(ss.first);
 | 
			
		||||
			db.sigmap.apply(ss.second);
 | 
			
		||||
			db.sigmap.apply(ss.lhs);
 | 
			
		||||
			db.sigmap.apply(ss.rhs);
 | 
			
		||||
 | 
			
		||||
			if (!db.quickcheck(ss.second, ss.first)) {
 | 
			
		||||
				nolatches_bits.first.append(ss.first);
 | 
			
		||||
				nolatches_bits.second.append(ss.second);
 | 
			
		||||
			if (!db.quickcheck(ss.rhs, ss.lhs)) {
 | 
			
		||||
				nolatches_bits.first.append(ss.lhs);
 | 
			
		||||
				nolatches_bits.second.append(ss.rhs);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < GetSize(ss.first); i++)
 | 
			
		||||
				latches_out_in[ss.first[i]] = ss.second[i];
 | 
			
		||||
			for (int i = 0; i < GetSize(ss.lhs); i++)
 | 
			
		||||
				latches_out_in[ss.lhs[i]] = ss.rhs[i];
 | 
			
		||||
		}
 | 
			
		||||
		sr->actions.clear();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,8 +35,8 @@ void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
 | 
			
		|||
 | 
			
		||||
			for (auto &action : sync->actions)
 | 
			
		||||
			{
 | 
			
		||||
				RTLIL::SigSpec lhs = action.first;
 | 
			
		||||
				RTLIL::SigSpec rhs = sigmap(action.second);
 | 
			
		||||
				RTLIL::SigSpec lhs = action.lhs;
 | 
			
		||||
				RTLIL::SigSpec rhs = sigmap(action.rhs);
 | 
			
		||||
 | 
			
		||||
				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));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include "kernel/register.h"
 | 
			
		||||
#include "kernel/bitpattern.h"
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -27,11 +28,37 @@
 | 
			
		|||
USING_YOSYS_NAMESPACE
 | 
			
		||||
PRIVATE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
using SnippetSourceMap = dict<std::pair<int, const RTLIL::CaseRule*>, const Const*>;
 | 
			
		||||
struct SnippetSourceMapBuilder {
 | 
			
		||||
	SnippetSourceMap map;
 | 
			
		||||
	void insert(int snippet, const RTLIL::CaseRule* cs, const RTLIL::SyncAction& action) {
 | 
			
		||||
		if (action.src.size())
 | 
			
		||||
			map[std::make_pair(snippet, cs)] = &action.src;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
struct SnippetSourceMapper {
 | 
			
		||||
	const SnippetSourceMap map;
 | 
			
		||||
	void try_map_into(pool<std::string>& sources, int snippet, const RTLIL::CaseRule* cs) const {
 | 
			
		||||
		auto src_it = map.find(std::make_pair(snippet, cs));
 | 
			
		||||
		if (src_it != map.end()) {
 | 
			
		||||
			sources.insert(src_it->second->decode_string());
 | 
			
		||||
		} else {
 | 
			
		||||
			auto cs_src = cs->get_src_attribute();
 | 
			
		||||
			if (cs_src.size()) {
 | 
			
		||||
				sources.insert(cs_src);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SigSnippets
 | 
			
		||||
{
 | 
			
		||||
	idict<SigSpec> sigidx;
 | 
			
		||||
	dict<SigBit, int> bit2snippet;
 | 
			
		||||
	pool<int> snippets;
 | 
			
		||||
	SnippetSourceMapBuilder source_builder;
 | 
			
		||||
 | 
			
		||||
	void insert(SigSpec sig)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +124,11 @@ struct SigSnippets
 | 
			
		|||
 | 
			
		||||
	void insert(const RTLIL::CaseRule *cs)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto &action : cs->actions)
 | 
			
		||||
			insert(action.first);
 | 
			
		||||
		for (auto &action : cs->actions) {
 | 
			
		||||
			insert(action.lhs);
 | 
			
		||||
			int idx = sigidx(action.lhs);
 | 
			
		||||
			source_builder.insert(idx, cs, action);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto sw : cs->switches)
 | 
			
		||||
		for (auto cs2 : sw->cases)
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +151,7 @@ struct SnippetSwCache
 | 
			
		|||
	void insert(const RTLIL::CaseRule *cs, vector<RTLIL::SwitchRule*> &sw_stack)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto &action : cs->actions)
 | 
			
		||||
		for (auto bit : action.first) {
 | 
			
		||||
		for (auto bit : action.lhs) {
 | 
			
		||||
			int sn = snippets->bit2snippet.at(bit, -1);
 | 
			
		||||
			if (sn < 0)
 | 
			
		||||
				continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -144,20 +174,37 @@ struct SnippetSwCache
 | 
			
		|||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs)
 | 
			
		||||
void apply_attrs(RTLIL::Cell *cell, const RTLIL::CaseRule *cs)
 | 
			
		||||
{
 | 
			
		||||
	cell->attributes = sw->attributes;
 | 
			
		||||
	cell->add_strpool_attribute(ID::src, cs->get_strpool_attribute(ID::src));
 | 
			
		||||
	Const old_src;
 | 
			
		||||
	if (cell->attributes.count(ID::src)) {
 | 
			
		||||
		std::swap(old_src, cell->attributes[ID::src]);
 | 
			
		||||
	}
 | 
			
		||||
	cell->attributes = cs->attributes;
 | 
			
		||||
	if (old_src.size()) {
 | 
			
		||||
		std::swap(old_src, cell->attributes[ID::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)
 | 
			
		||||
{
 | 
			
		||||
struct MuxGenCtx {
 | 
			
		||||
	RTLIL::Module *mod;
 | 
			
		||||
	const RTLIL::SigSpec &signal;
 | 
			
		||||
	const std::vector<RTLIL::SigSpec> *compare;
 | 
			
		||||
	RTLIL::Cell *last_mux_cell;
 | 
			
		||||
	RTLIL::SwitchRule *sw;
 | 
			
		||||
	RTLIL::CaseRule *cs;
 | 
			
		||||
	bool ifxmode;
 | 
			
		||||
	const SnippetSourceMapper& source_mapper;
 | 
			
		||||
	int current_snippet;
 | 
			
		||||
	pool<std::string>& snippet_sources;
 | 
			
		||||
 | 
			
		||||
	RTLIL::SigSpec gen_cmp() {
 | 
			
		||||
		std::stringstream sstr;
 | 
			
		||||
		sstr << "$procmux$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
		RTLIL::Wire *cmp_wire = mod->addWire(sstr.str() + "_CMP", 0);
 | 
			
		||||
 | 
			
		||||
	for (auto comp : compare)
 | 
			
		||||
		for (auto comp : *compare)
 | 
			
		||||
		{
 | 
			
		||||
			RTLIL::SigSpec sig = signal;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +226,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(), cmp_wire->width), ifxmode ? ID($eqx) : ID($eq));
 | 
			
		||||
			apply_attrs(eq_cell, sw, cs);
 | 
			
		||||
				apply_attrs(eq_cell, cs);
 | 
			
		||||
 | 
			
		||||
				eq_cell->parameters[ID::A_SIGNED] = RTLIL::Const(0);
 | 
			
		||||
				eq_cell->parameters[ID::B_SIGNED] = RTLIL::Const(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -205,7 +252,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", ID($reduce_or));
 | 
			
		||||
		apply_attrs(any_cell, sw, cs);
 | 
			
		||||
			apply_attrs(any_cell, cs);
 | 
			
		||||
 | 
			
		||||
			any_cell->parameters[ID::A_SIGNED] = RTLIL::Const(0);
 | 
			
		||||
			any_cell->parameters[ID::A_WIDTH] = RTLIL::Const(cmp_wire->width);
 | 
			
		||||
| 
						 | 
				
			
			@ -218,19 +265,18 @@ 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, RTLIL::CaseRule *cs, bool ifxmode)
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SigSpec gen_mux(RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal) {
 | 
			
		||||
		log_assert(when_signal.size() == else_signal.size());
 | 
			
		||||
 | 
			
		||||
		std::stringstream sstr;
 | 
			
		||||
		sstr << "$procmux$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
		// the trivial cases
 | 
			
		||||
	if (compare.size() == 0 || when_signal == else_signal)
 | 
			
		||||
		if (compare->size() == 0 || when_signal == else_signal)
 | 
			
		||||
			return when_signal;
 | 
			
		||||
 | 
			
		||||
		// compare results
 | 
			
		||||
	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);
 | 
			
		||||
		RTLIL::SigSpec ctrl_sig = gen_cmp();
 | 
			
		||||
		if (ctrl_sig.size() == 0)
 | 
			
		||||
			return when_signal;
 | 
			
		||||
		log_assert(ctrl_sig.size() == 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -240,7 +286,6 @@ 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(), ID($mux));
 | 
			
		||||
	apply_attrs(mux_cell, sw, cs);
 | 
			
		||||
 | 
			
		||||
		mux_cell->parameters[ID::WIDTH] = RTLIL::Const(when_signal.size());
 | 
			
		||||
		mux_cell->setPort(ID::A, else_signal);
 | 
			
		||||
| 
						 | 
				
			
			@ -248,19 +293,22 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
 | 
			
		|||
		mux_cell->setPort(ID::S, ctrl_sig);
 | 
			
		||||
		mux_cell->setPort(ID::Y, RTLIL::SigSpec(result_wire));
 | 
			
		||||
 | 
			
		||||
		source_mapper.try_map_into(snippet_sources, current_snippet, cs);
 | 
			
		||||
 | 
			
		||||
		last_mux_cell = mux_cell;
 | 
			
		||||
		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, RTLIL::CaseRule *cs, bool ifxmode)
 | 
			
		||||
{
 | 
			
		||||
	void append_pmux(RTLIL::SigSpec when_signal) {
 | 
			
		||||
		log_assert(last_mux_cell != NULL);
 | 
			
		||||
		log_assert(when_signal.size() == last_mux_cell->getPort(ID::A).size());
 | 
			
		||||
 | 
			
		||||
	if (when_signal == last_mux_cell->getPort(ID::A))
 | 
			
		||||
		if (when_signal == last_mux_cell->getPort(ID::A)) {
 | 
			
		||||
			// when_signal already covered by the default value at port A
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);
 | 
			
		||||
		RTLIL::SigSpec ctrl_sig = gen_cmp();
 | 
			
		||||
		log_assert(ctrl_sig.size() == 1);
 | 
			
		||||
		last_mux_cell->type = ID($pmux);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -273,7 +321,10 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
 | 
			
		|||
		last_mux_cell->setPort(ID::B, new_b);
 | 
			
		||||
 | 
			
		||||
		last_mux_cell->parameters[ID::S_WIDTH] = last_mux_cell->getPort(ID::S).size();
 | 
			
		||||
 | 
			
		||||
		source_mapper.try_map_into(snippet_sources, current_snippet, cs);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -290,7 +341,7 @@ const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRul
 | 
			
		|||
				pool<SigBit> case_bits;
 | 
			
		||||
 | 
			
		||||
				for (auto it : cs->actions) {
 | 
			
		||||
					for (auto bit : it.first)
 | 
			
		||||
					for (auto bit : it.lhs)
 | 
			
		||||
						case_bits.insert(bit);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -317,26 +368,20 @@ const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRul
 | 
			
		|||
 | 
			
		||||
	return swcache.full_case_bits_cache.at(sw);
 | 
			
		||||
}
 | 
			
		||||
struct MuxTreeContext {
 | 
			
		||||
	RTLIL::Module* mod;
 | 
			
		||||
	SnippetSwCache& swcache;
 | 
			
		||||
	const SnippetSourceMapper& source_mapper;
 | 
			
		||||
	dict<RTLIL::SwitchRule*, bool> &swpara;
 | 
			
		||||
	RTLIL::CaseRule *cs;
 | 
			
		||||
	const RTLIL::SigSpec &sig;
 | 
			
		||||
	RTLIL::SigSpec defval;
 | 
			
		||||
	const bool ifxmode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool> &swpara,
 | 
			
		||||
		RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
 | 
			
		||||
bool is_simple_parallel_case(RTLIL::SwitchRule* sw, dict<RTLIL::SwitchRule*, bool> &swpara)
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SigSpec result = defval;
 | 
			
		||||
 | 
			
		||||
	for (auto &action : cs->actions) {
 | 
			
		||||
		sig.replace(action.first, action.second, &result);
 | 
			
		||||
		action.first.remove2(sig, &action.second);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (auto sw : cs->switches)
 | 
			
		||||
	{
 | 
			
		||||
		if (!swcache.check(sw))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		// detect groups of parallel cases
 | 
			
		||||
		std::vector<int> pgroups(sw->cases.size());
 | 
			
		||||
		bool is_simple_parallel_case = true;
 | 
			
		||||
 | 
			
		||||
	bool ret = true;
 | 
			
		||||
	if (!sw->get_bool_attribute(ID::parallel_case)) {
 | 
			
		||||
		if (!swpara.count(sw)) {
 | 
			
		||||
			pool<Const> case_values;
 | 
			
		||||
| 
						 | 
				
			
			@ -344,23 +389,40 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
 | 
			
		|||
				RTLIL::CaseRule *cs2 = sw->cases[i];
 | 
			
		||||
				for (auto pat : cs2->compare) {
 | 
			
		||||
					if (!pat.is_fully_def())
 | 
			
		||||
							goto not_simple_parallel_case;
 | 
			
		||||
						return false;
 | 
			
		||||
					Const cpat = pat.as_const();
 | 
			
		||||
					if (case_values.count(cpat))
 | 
			
		||||
							goto not_simple_parallel_case;
 | 
			
		||||
						return false;
 | 
			
		||||
					case_values.insert(cpat);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
				if (0)
 | 
			
		||||
			not_simple_parallel_case:
 | 
			
		||||
					is_simple_parallel_case = false;
 | 
			
		||||
				swpara[sw] = is_simple_parallel_case;
 | 
			
		||||
			swpara[sw] = ret;
 | 
			
		||||
		} else {
 | 
			
		||||
				is_simple_parallel_case = swpara.at(sw);
 | 
			
		||||
			return swpara.at(sw);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		if (!is_simple_parallel_case) {
 | 
			
		||||
RTLIL::SigSpec signal_to_mux_tree(MuxTreeContext ctx)
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SigSpec result = ctx.defval;
 | 
			
		||||
 | 
			
		||||
	for (auto &action : ctx.cs->actions) {
 | 
			
		||||
		ctx.sig.replace(action.lhs, action.rhs, &result);
 | 
			
		||||
		action.lhs.remove2(ctx.sig, &action.rhs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (auto sw : ctx.cs->switches)
 | 
			
		||||
	{
 | 
			
		||||
		if (!ctx.swcache.check(sw))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		// detect groups of parallel cases
 | 
			
		||||
		std::vector<int> pgroups(sw->cases.size());
 | 
			
		||||
		pool<std::string> case_sources;
 | 
			
		||||
 | 
			
		||||
		if (!is_simple_parallel_case(sw, ctx.swpara)) {
 | 
			
		||||
			BitPatternPool pool(sw->signal.size());
 | 
			
		||||
			bool extra_group_for_next_case = false;
 | 
			
		||||
			for (size_t i = 0; i < sw->cases.size(); i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -382,28 +444,52 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
 | 
			
		|||
				for (auto pat : cs2->compare)
 | 
			
		||||
					if (!pat.is_fully_const())
 | 
			
		||||
						extra_group_for_next_case = true;
 | 
			
		||||
					else if (!ifxmode)
 | 
			
		||||
					else if (!ctx.ifxmode)
 | 
			
		||||
						pool.take(pat);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Create sources for default cases
 | 
			
		||||
		for (auto cs2 : sw -> cases) {
 | 
			
		||||
			if (cs2->compare.empty()) {
 | 
			
		||||
				int sn = ctx.swcache.current_snippet;
 | 
			
		||||
				ctx.source_mapper.try_map_into(case_sources, sn, cs2);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// mask default bits that are irrelevant because the output is driven by a full case
 | 
			
		||||
		const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw);
 | 
			
		||||
		for (int i = 0; i < GetSize(sig); i++)
 | 
			
		||||
			if (full_case_bits.count(sig[i]))
 | 
			
		||||
		const pool<SigBit> &full_case_bits = get_full_case_bits(ctx.swcache, sw);
 | 
			
		||||
		for (int i = 0; i < GetSize(ctx.sig); i++)
 | 
			
		||||
			if (full_case_bits.count(ctx.sig[i]))
 | 
			
		||||
				result[i] = State::Sx;
 | 
			
		||||
 | 
			
		||||
		// evaluate in reverse order to give the first entry the top priority
 | 
			
		||||
		RTLIL::SigSpec initial_val = result;
 | 
			
		||||
		RTLIL::Cell *last_mux_cell = NULL;
 | 
			
		||||
		MuxGenCtx mux_gen_ctx {ctx.mod,
 | 
			
		||||
			sw->signal,
 | 
			
		||||
			nullptr,
 | 
			
		||||
			nullptr,
 | 
			
		||||
			sw,
 | 
			
		||||
			nullptr,
 | 
			
		||||
			ctx.ifxmode,
 | 
			
		||||
			ctx.source_mapper,
 | 
			
		||||
			ctx.swcache.current_snippet,
 | 
			
		||||
			case_sources
 | 
			
		||||
		};
 | 
			
		||||
		// evaluate in reverse order to give the first entry the top priority
 | 
			
		||||
		for (size_t i = 0; i < sw->cases.size(); i++) {
 | 
			
		||||
			int case_idx = sw->cases.size() - i - 1;
 | 
			
		||||
			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, cs2, ifxmode);
 | 
			
		||||
			else
 | 
			
		||||
				result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, cs2, ifxmode);
 | 
			
		||||
			MuxTreeContext new_ctx = ctx;
 | 
			
		||||
			new_ctx.cs = sw->cases[case_idx];
 | 
			
		||||
			new_ctx.defval = initial_val;
 | 
			
		||||
			RTLIL::SigSpec value = signal_to_mux_tree(new_ctx);
 | 
			
		||||
			mux_gen_ctx.cs = new_ctx.cs;
 | 
			
		||||
			mux_gen_ctx.compare = &new_ctx.cs->compare;
 | 
			
		||||
			if (mux_gen_ctx.last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1]) {
 | 
			
		||||
				mux_gen_ctx.append_pmux(value);
 | 
			
		||||
			} else {
 | 
			
		||||
				result = mux_gen_ctx.gen_mux(value, result);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (mux_gen_ctx.last_mux_cell) {
 | 
			
		||||
			mux_gen_ctx.last_mux_cell->set_strpool_attribute(ID::src, case_sources);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -429,9 +515,19 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
 | 
			
		|||
		swcache.current_snippet = idx;
 | 
			
		||||
		RTLIL::SigSpec sig = sigsnip.sigidx[idx];
 | 
			
		||||
 | 
			
		||||
		log("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig));
 | 
			
		||||
		log_debug("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig));
 | 
			
		||||
 | 
			
		||||
		RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()), ifxmode);
 | 
			
		||||
		const SnippetSourceMapper mapper{sigsnip.source_builder.map};
 | 
			
		||||
		RTLIL::SigSpec value = signal_to_mux_tree({
 | 
			
		||||
			mod,
 | 
			
		||||
			swcache,
 | 
			
		||||
			mapper,
 | 
			
		||||
			swpara,
 | 
			
		||||
			&proc->root_case,
 | 
			
		||||
			sig,
 | 
			
		||||
			RTLIL::SigSpec(RTLIL::State::Sx, sig.size()),
 | 
			
		||||
			ifxmode
 | 
			
		||||
		});
 | 
			
		||||
		mod->connect(RTLIL::SigSig(sig, value));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,8 +66,8 @@ struct PruneWorker
 | 
			
		|||
			assigned.insert(sw_assigned.begin(), sw_assigned.end());
 | 
			
		||||
		}
 | 
			
		||||
		for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) {
 | 
			
		||||
			RTLIL::SigSpec lhs = sigmap(it->first);
 | 
			
		||||
			RTLIL::SigSpec rhs = sigmap(it->second);
 | 
			
		||||
			RTLIL::SigSpec lhs = sigmap(it->lhs);
 | 
			
		||||
			RTLIL::SigSpec rhs = sigmap(it->rhs);
 | 
			
		||||
			SigSpec new_lhs, new_rhs;
 | 
			
		||||
			SigSpec conn_lhs, conn_rhs;
 | 
			
		||||
			for (int i = 0; i < GetSize(lhs); i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -93,8 +93,8 @@ struct PruneWorker
 | 
			
		|||
					removed_count++;
 | 
			
		||||
				it = decltype(cs->actions)::reverse_iterator(cs->actions.erase(it.base() - 1));
 | 
			
		||||
			} else {
 | 
			
		||||
				it->first = new_lhs;
 | 
			
		||||
				it->second = new_rhs;
 | 
			
		||||
				it->lhs = new_lhs;
 | 
			
		||||
				it->rhs = new_rhs;
 | 
			
		||||
				it++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ struct RomWorker
 | 
			
		|||
		SigSpec lhs;
 | 
			
		||||
		dict<SigBit, int> lhs_lookup;
 | 
			
		||||
		for (auto &it: sw->cases[0]->actions) {
 | 
			
		||||
			for (auto bit: it.first) {
 | 
			
		||||
			for (auto bit: it.lhs) {
 | 
			
		||||
				if (!lhs_lookup.count(bit)) {
 | 
			
		||||
					lhs_lookup[bit] = GetSize(lhs);
 | 
			
		||||
					lhs.append(bit);
 | 
			
		||||
| 
						 | 
				
			
			@ -87,17 +87,17 @@ struct RomWorker
 | 
			
		|||
			}
 | 
			
		||||
			Const val = Const(State::Sm, GetSize(lhs));
 | 
			
		||||
			for (auto &it: cs->actions) {
 | 
			
		||||
				if (!it.second.is_fully_const()) {
 | 
			
		||||
				if (!it.rhs.is_fully_const()) {
 | 
			
		||||
					log_debug("rejecting switch: rhs not const\n");
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				for (int i = 0; i < GetSize(it.first); i++) {
 | 
			
		||||
					auto it2 = lhs_lookup.find(it.first[i]);
 | 
			
		||||
				for (int i = 0; i < GetSize(it.lhs); i++) {
 | 
			
		||||
					auto it2 = lhs_lookup.find(it.lhs[i]);
 | 
			
		||||
					if (it2 == lhs_lookup.end()) {
 | 
			
		||||
						log_debug("rejecting switch: lhs not uniform\n");
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
					val.set(it2->second, it.second[i].data);
 | 
			
		||||
					val.set(it2->second, it.rhs[i].data);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for (auto bit: val) {
 | 
			
		||||
| 
						 | 
				
			
			@ -193,19 +193,20 @@ struct RomWorker
 | 
			
		|||
			delete cs;
 | 
			
		||||
		sw->cases.clear();
 | 
			
		||||
		sw->signal = sw->signal.extract(0, swsigbits);
 | 
			
		||||
		Const action_src = mem.has_attribute(ID::src) ? mem.attributes[ID::src] : Const("");
 | 
			
		||||
		if (abits == GetSize(sw->signal)) {
 | 
			
		||||
			sw->signal = SigSpec();
 | 
			
		||||
			RTLIL::CaseRule *cs = new RTLIL::CaseRule;
 | 
			
		||||
			cs->actions.push_back(SigSig(lhs, rdata));
 | 
			
		||||
			cs->actions.push_back({lhs, rdata, std::move(action_src)});
 | 
			
		||||
			sw->cases.push_back(cs);
 | 
			
		||||
		} else {
 | 
			
		||||
			sw->signal = sw->signal.extract_end(abits);
 | 
			
		||||
			RTLIL::CaseRule *cs = new RTLIL::CaseRule;
 | 
			
		||||
			cs->compare.push_back(Const(State::S0, GetSize(sw->signal)));
 | 
			
		||||
			cs->actions.push_back(SigSig(lhs, rdata));
 | 
			
		||||
			cs->actions.push_back({lhs, rdata, action_src});
 | 
			
		||||
			sw->cases.push_back(cs);
 | 
			
		||||
			RTLIL::CaseRule *cs2 = new RTLIL::CaseRule;
 | 
			
		||||
			cs2->actions.push_back(SigSig(lhs, default_val));
 | 
			
		||||
			cs2->actions.push_back({lhs, default_val, std::move(action_src)});
 | 
			
		||||
			sw->cases.push_back(cs2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,14 +27,6 @@
 | 
			
		|||
USING_YOSYS_NAMESPACE
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
static void transfer_attr (Cell* to, const Cell* from, const IdString& attr) {
 | 
			
		||||
	if (from->has_attribute(attr))
 | 
			
		||||
		to->attributes[attr] = from->attributes.at(attr);
 | 
			
		||||
}
 | 
			
		||||
static void transfer_src (Cell* to, const Cell* from) {
 | 
			
		||||
	transfer_attr(to, from, ID::src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		||||
{
 | 
			
		||||
	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +36,7 @@ void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	for (int i = 0; i < GetSize(sig_y); i++) {
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
		gate->setPort(ID::Y, sig_y[i]);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +96,7 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	for (int i = 0; i < GetSize(sig_y); i++) {
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
		gate->setPort(ID::B, sig_b[i]);
 | 
			
		||||
		gate->setPort(ID::Y, sig_y[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +147,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 | 
			
		||||
			transfer_src(gate, cell);
 | 
			
		||||
			gate->transfer_src_attribute(cell);
 | 
			
		||||
			gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
			gate->setPort(ID::B, sig_a[i+1]);
 | 
			
		||||
			gate->setPort(ID::Y, sig_t[i/2]);
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +160,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
	if (cell->type == ID($reduce_xnor)) {
 | 
			
		||||
		RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a);
 | 
			
		||||
		gate->setPort(ID::Y, sig_t);
 | 
			
		||||
		last_output_cell = gate;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +188,7 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_));
 | 
			
		||||
			transfer_src(gate, cell);
 | 
			
		||||
			gate->transfer_src_attribute(cell);
 | 
			
		||||
			gate->setPort(ID::A, sig[i]);
 | 
			
		||||
			gate->setPort(ID::B, sig[i+1]);
 | 
			
		||||
			gate->setPort(ID::Y, sig_t[i/2]);
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +217,7 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 | 
			
		||||
	transfer_src(gate, cell);
 | 
			
		||||
	gate->transfer_src_attribute(cell);
 | 
			
		||||
	gate->setPort(ID::A, sig_a);
 | 
			
		||||
	gate->setPort(ID::Y, sig_y);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +246,7 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
	log_assert(!gate_type.empty());
 | 
			
		||||
 | 
			
		||||
	RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 | 
			
		||||
	transfer_src(gate, cell);
 | 
			
		||||
	gate->transfer_src_attribute(cell);
 | 
			
		||||
	gate->setPort(ID::A, sig_a);
 | 
			
		||||
	gate->setPort(ID::B, sig_b);
 | 
			
		||||
	gate->setPort(ID::Y, sig_y);
 | 
			
		||||
| 
						 | 
				
			
			@ -270,19 +262,19 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b)));
 | 
			
		||||
	RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed);
 | 
			
		||||
	transfer_src(xor_cell, cell);
 | 
			
		||||
	xor_cell->transfer_src_attribute(cell);
 | 
			
		||||
	simplemap_bitop(module, xor_cell);
 | 
			
		||||
	module->remove(xor_cell);
 | 
			
		||||
 | 
			
		||||
	RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID);
 | 
			
		||||
	RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out);
 | 
			
		||||
	transfer_src(reduce_cell, cell);
 | 
			
		||||
	reduce_cell->transfer_src_attribute(cell);
 | 
			
		||||
	simplemap_reduce(module, reduce_cell);
 | 
			
		||||
	module->remove(reduce_cell);
 | 
			
		||||
 | 
			
		||||
	if (!is_ne) {
 | 
			
		||||
		RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y);
 | 
			
		||||
		transfer_src(not_cell, cell);
 | 
			
		||||
		not_cell->transfer_src_attribute(cell);
 | 
			
		||||
		simplemap_lognot(module, not_cell);
 | 
			
		||||
		module->remove(not_cell);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -296,7 +288,7 @@ void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	for (int i = 0; i < GetSize(sig_y); i++) {
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
		gate->setPort(ID::B, sig_b[i]);
 | 
			
		||||
		gate->setPort(ID::S, cell->getPort(ID::S));
 | 
			
		||||
| 
						 | 
				
			
			@ -313,7 +305,7 @@ void simplemap_bwmux(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	for (int i = 0; i < GetSize(sig_y); i++) {
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
		gate->setPort(ID::B, sig_b[i]);
 | 
			
		||||
		gate->setPort(ID::S, sig_s[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +321,7 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
 | 
			
		||||
	for (int i = 0; i < GetSize(sig_y); i++) {
 | 
			
		||||
		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_));
 | 
			
		||||
		transfer_src(gate, cell);
 | 
			
		||||
		gate->transfer_src_attribute(cell);
 | 
			
		||||
		gate->setPort(ID::A, sig_a[i]);
 | 
			
		||||
		gate->setPort(ID::E, sig_e);
 | 
			
		||||
		gate->setPort(ID::Y, sig_y[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +339,7 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
		for (int i = 0; i < GetSize(new_data); i += width) {
 | 
			
		||||
			for (int k = 0; k < width; k++) {
 | 
			
		||||
				RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 | 
			
		||||
				transfer_src(gate, cell);
 | 
			
		||||
				gate->transfer_src_attribute(cell);
 | 
			
		||||
				gate->setPort(ID::A, data[i*2+k]);
 | 
			
		||||
				gate->setPort(ID::B, data[i*2+width+k]);
 | 
			
		||||
				gate->setPort(ID::S, sel[idx]);
 | 
			
		||||
| 
						 | 
				
			
			@ -370,7 +362,7 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
 | 
			
		|||
		SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2);
 | 
			
		||||
		for (int i = 0; i < GetSize(lut_data); i += 2) {
 | 
			
		||||
			RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 | 
			
		||||
			transfer_src(gate, cell);
 | 
			
		||||
			gate->transfer_src_attribute(cell);
 | 
			
		||||
			gate->setPort(ID::A, lut_data[i]);
 | 
			
		||||
			gate->setPort(ID::B, lut_data[i+1]);
 | 
			
		||||
			gate->setPort(ID::S, lut_ctrl[idx]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,6 @@ proc
 | 
			
		|||
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
 | 
			
		||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 | 
			
		||||
cd mux4 # Constrain all select calls below inside the top module
 | 
			
		||||
select -assert-count 4 t:LUT*
 | 
			
		||||
select -assert-count 2 t:MUX2_LUT5
 | 
			
		||||
select -assert-count 1 t:MUX2_LUT6
 | 
			
		||||
select -assert-count 6 t:IBUF
 | 
			
		||||
| 
						 | 
				
			
			@ -32,9 +31,6 @@ proc
 | 
			
		|||
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
 | 
			
		||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 | 
			
		||||
cd mux8 # Constrain all select calls below inside the top module
 | 
			
		||||
select -assert-count 3 t:LUT1
 | 
			
		||||
select -assert-count 2 t:LUT3
 | 
			
		||||
select -assert-count 1 t:LUT4
 | 
			
		||||
select -assert-count 5 t:MUX2_LUT5
 | 
			
		||||
select -assert-count 2 t:MUX2_LUT6
 | 
			
		||||
select -assert-count 1 t:MUX2_LUT7
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										92
									
								
								tests/proc/proc_mux_src.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								tests/proc/proc_mux_src.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
module nested(
 | 
			
		||||
	input clk,
 | 
			
		||||
	input [7:0] A,
 | 
			
		||||
	input [7:0] B,
 | 
			
		||||
	input [3:0] mode1,
 | 
			
		||||
	input [3:0] mode2,
 | 
			
		||||
	output reg [7:0] result1,
 | 
			
		||||
	output reg [7:0] result2,
 | 
			
		||||
	output reg [1:0] arith
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
	localparam OP_A = 4'b0000;
 | 
			
		||||
	localparam OP_BA = 4'b0001;
 | 
			
		||||
	localparam OP_BB = 4'b0010;
 | 
			
		||||
	localparam OP_C = 4'b0011;
 | 
			
		||||
 | 
			
		||||
	always @(posedge clk)
 | 
			
		||||
	begin
 | 
			
		||||
		case (mode1)
 | 
			
		||||
			OP_A: begin
 | 
			
		||||
				result1 = A + B;
 | 
			
		||||
				result2 = A - B;
 | 
			
		||||
				arith = 2'b01;
 | 
			
		||||
			end
 | 
			
		||||
			OP_BA , OP_BB : begin
 | 
			
		||||
				result1 = A * B;
 | 
			
		||||
				result2 = A / B;
 | 
			
		||||
				arith = 2'b00;
 | 
			
		||||
			end
 | 
			
		||||
			OP_C : begin
 | 
			
		||||
				arith = 2'b10;
 | 
			
		||||
				case (mode2)
 | 
			
		||||
					OP_A: begin
 | 
			
		||||
						result1 = ~B;
 | 
			
		||||
						result2 = B;
 | 
			
		||||
					end
 | 
			
		||||
					OP_C: begin
 | 
			
		||||
						result1 = A ^ B;
 | 
			
		||||
						result2 = A == B;
 | 
			
		||||
					end
 | 
			
		||||
					default: begin
 | 
			
		||||
						result1 = 1'b0;
 | 
			
		||||
						// result2 omitted
 | 
			
		||||
					end
 | 
			
		||||
				endcase
 | 
			
		||||
			end
 | 
			
		||||
			default: begin
 | 
			
		||||
				result1 = 8'b0;
 | 
			
		||||
				result2 = 8'b0;
 | 
			
		||||
				arith = 2'b11;
 | 
			
		||||
			end
 | 
			
		||||
		endcase
 | 
			
		||||
	end
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module tiny(
 | 
			
		||||
	input clk,
 | 
			
		||||
	input ya,
 | 
			
		||||
	input [7:0] in,
 | 
			
		||||
	output reg [7:0] out,
 | 
			
		||||
);
 | 
			
		||||
	always @(posedge clk)
 | 
			
		||||
	begin
 | 
			
		||||
		case (ya)
 | 
			
		||||
			1'b1: begin
 | 
			
		||||
				out = in;
 | 
			
		||||
			end
 | 
			
		||||
		endcase
 | 
			
		||||
	end
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module tiny2(
 | 
			
		||||
	input clk,
 | 
			
		||||
	input [1:0] ya,
 | 
			
		||||
	input [7:0] in,
 | 
			
		||||
	output reg [7:0] out,
 | 
			
		||||
);
 | 
			
		||||
	always @(posedge clk)
 | 
			
		||||
	begin
 | 
			
		||||
		case (ya)
 | 
			
		||||
			2'b01: begin
 | 
			
		||||
				out = in;
 | 
			
		||||
			end
 | 
			
		||||
			2'b10: begin
 | 
			
		||||
				out = 1'b1;
 | 
			
		||||
			end
 | 
			
		||||
			default begin
 | 
			
		||||
				out = 1'b0;
 | 
			
		||||
			end
 | 
			
		||||
		endcase
 | 
			
		||||
	end
 | 
			
		||||
endmodule
 | 
			
		||||
							
								
								
									
										33
									
								
								tests/proc/proc_mux_src.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/proc/proc_mux_src.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
read_verilog proc_mux_src.v
 | 
			
		||||
proc -noopt
 | 
			
		||||
check -assert
 | 
			
		||||
# eq refer to the values compared against
 | 
			
		||||
select -assert-count 2 tiny2/t:$eq
 | 
			
		||||
select -assert-count 1 tiny2/t:$eq a:src=proc_mux_src.v:81.4-81.10 %i
 | 
			
		||||
select -assert-count 1 tiny2/t:$eq a:src=proc_mux_src.v:84.4-84.10 %i
 | 
			
		||||
# Flops cover the whole process
 | 
			
		||||
select -assert-count 1 tiny2/t:$dff
 | 
			
		||||
select -assert-count 1 tiny2/t:$dff a:src=proc_mux_src.v:78.2-91.5 %i
 | 
			
		||||
# Muxes are marked to the exact assignment statements they represent including the explicit default case
 | 
			
		||||
select -assert-count 1 tiny2/t:$pmux
 | 
			
		||||
select -assert-count 1 tiny2/t:$pmux a:src=proc_mux_src.v:80.5-80.13|proc_mux_src.v:83.5-83.15|proc_mux_src.v:86.5-86.15
 | 
			
		||||
select -assert-count 0 tiny/t:$reduce_or
 | 
			
		||||
 | 
			
		||||
# Implicit default cases add src attributes to muxes that cover the whole switch
 | 
			
		||||
select -assert-count 1 tiny/t:$mux
 | 
			
		||||
select -assert-count 1 tiny/t:$mux a:proc_mux_src.v:65.5-65.13|proc_mux_src.v:63.3-67.10
 | 
			
		||||
select -assert-count 0 tiny/t:$reduce_or
 | 
			
		||||
 | 
			
		||||
dump nested
 | 
			
		||||
#dump nested/t:$pmux
 | 
			
		||||
# $reduce_or src covers the entire list of comparison RHSs
 | 
			
		||||
# Each snippet is treated separately so it gets its own $eq and $reduce_or etc
 | 
			
		||||
select -assert-count 3 nested/t:$reduce_or
 | 
			
		||||
select -assert-count 3 nested/t:$reduce_or a:src=proc_mux_src.v:25.4-25.19 %i
 | 
			
		||||
# When switches are nested, the top mux considers the inner switch the entire source
 | 
			
		||||
# for one of its inputs. Here, that's proc_mux_src.v:32.5-45.12
 | 
			
		||||
select -assert-count 5 nested/t:$pmux
 | 
			
		||||
select -assert-count 1 nested/t:$pmux a:src=proc_mux_src.v:21.5-21.20|proc_mux_src.v:26.5-26.20|proc_mux_src.v:32.5-45.12|proc_mux_src.v:48.5-48.19 %i
 | 
			
		||||
# No nesting for output reg arith
 | 
			
		||||
select -assert-count 1 nested/t:$pmux a:src=proc_mux_src.v:23.5-23.18|proc_mux_src.v:28.5-28.18|proc_mux_src.v:31.5-31.18|proc_mux_src.v:50.5-50.18 %i
 | 
			
		||||
dump nested/t:$pmux
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue