mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Some improvements in fsm_opt and fsm_map for FSM with unreachable states
This commit is contained in:
		
							parent
							
								
									51aa5544fb
								
							
						
					
					
						commit
						2faef89738
					
				
					 3 changed files with 104 additions and 52 deletions
				
			
		|  | @ -207,65 +207,72 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module) | |||
| 
 | ||||
| 	// generate next_state signal
 | ||||
| 
 | ||||
| 	RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size()); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < fsm_data.state_table.size(); i++) | ||||
| 	if (SIZE(fsm_data.state_table) == 1) | ||||
| 	{ | ||||
| 		std::map<RTLIL::Const, std::set<int>> pattern_cache; | ||||
| 		std::set<int> fullstate_cache; | ||||
| 
 | ||||
| 		for (size_t j = 0; j < fsm_data.state_table.size(); j++) | ||||
| 			fullstate_cache.insert(j); | ||||
| 
 | ||||
| 		for (auto &tr : fsm_data.transition_table) { | ||||
| 			if (tr.state_out == int(i)) | ||||
| 				pattern_cache[tr.ctrl_in].insert(tr.state_in); | ||||
| 			else | ||||
| 				fullstate_cache.erase(tr.state_in); | ||||
| 		} | ||||
| 
 | ||||
| 		implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 	} | ||||
| 
 | ||||
| 	if (encoding_is_onehot) | ||||
| 	{ | ||||
| 		RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width); | ||||
| 		for (size_t i = 0; i < fsm_data.state_table.size(); i++) { | ||||
| 			RTLIL::Const state = fsm_data.state_table[i]; | ||||
| 			int bit_idx = -1; | ||||
| 			for (size_t j = 0; j < state.bits.size(); j++) | ||||
| 				if (state.bits[j] == RTLIL::State::S1) | ||||
| 					bit_idx = j; | ||||
| 			if (bit_idx >= 0) | ||||
| 				next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 		} | ||||
| 		log_assert(!next_state_sig.has_marked_bits()); | ||||
| 		module->connect(RTLIL::SigSig(next_state_wire, next_state_sig)); | ||||
| 		module->connect(next_state_wire, fsm_data.state_table.front()); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		RTLIL::SigSpec sig_a, sig_b, sig_s; | ||||
| 		int reset_state = fsm_data.reset_state; | ||||
| 		if (reset_state < 0) | ||||
| 			reset_state = 0; | ||||
| 		RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size()); | ||||
| 
 | ||||
| 		for (size_t i = 0; i < fsm_data.state_table.size(); i++) { | ||||
| 			RTLIL::Const state = fsm_data.state_table[i]; | ||||
| 			if (int(i) == fsm_data.reset_state) { | ||||
| 				sig_a = RTLIL::SigSpec(state); | ||||
| 			} else { | ||||
| 				sig_b.append(RTLIL::SigSpec(state)); | ||||
| 				sig_s.append(RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 		for (size_t i = 0; i < fsm_data.state_table.size(); i++) | ||||
| 		{ | ||||
| 			std::map<RTLIL::Const, std::set<int>> pattern_cache; | ||||
| 			std::set<int> fullstate_cache; | ||||
| 
 | ||||
| 			for (size_t j = 0; j < fsm_data.state_table.size(); j++) | ||||
| 				fullstate_cache.insert(j); | ||||
| 
 | ||||
| 			for (auto &tr : fsm_data.transition_table) { | ||||
| 				if (tr.state_out == int(i)) | ||||
| 					pattern_cache[tr.ctrl_in].insert(tr.state_in); | ||||
| 				else | ||||
| 					fullstate_cache.erase(tr.state_in); | ||||
| 			} | ||||
| 
 | ||||
| 			implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 		} | ||||
| 
 | ||||
| 		RTLIL::Cell *mux_cell = module->addCell(NEW_ID, "$safe_pmux"); | ||||
| 		mux_cell->setPort("\\A", sig_a); | ||||
| 		mux_cell->setPort("\\B", sig_b); | ||||
| 		mux_cell->setPort("\\S", sig_s); | ||||
| 		mux_cell->setPort("\\Y", RTLIL::SigSpec(next_state_wire)); | ||||
| 		mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.size()); | ||||
| 		mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.size()); | ||||
| 		if (encoding_is_onehot) | ||||
| 		{ | ||||
| 			RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width); | ||||
| 			for (size_t i = 0; i < fsm_data.state_table.size(); i++) { | ||||
| 				RTLIL::Const state = fsm_data.state_table[i]; | ||||
| 				int bit_idx = -1; | ||||
| 				for (size_t j = 0; j < state.bits.size(); j++) | ||||
| 					if (state.bits[j] == RTLIL::State::S1) | ||||
| 						bit_idx = j; | ||||
| 				if (bit_idx >= 0) | ||||
| 					next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 			} | ||||
| 			log_assert(!next_state_sig.has_marked_bits()); | ||||
| 			module->connect(RTLIL::SigSig(next_state_wire, next_state_sig)); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			RTLIL::SigSpec sig_a, sig_b, sig_s; | ||||
| 			int reset_state = fsm_data.reset_state; | ||||
| 			if (reset_state < 0) | ||||
| 				reset_state = 0; | ||||
| 
 | ||||
| 			for (size_t i = 0; i < fsm_data.state_table.size(); i++) { | ||||
| 				RTLIL::Const state = fsm_data.state_table[i]; | ||||
| 				if (int(i) == fsm_data.reset_state) { | ||||
| 					sig_a = RTLIL::SigSpec(state); | ||||
| 				} else { | ||||
| 					sig_b.append(RTLIL::SigSpec(state)); | ||||
| 					sig_s.append(RTLIL::SigSpec(next_state_onehot, i)); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			RTLIL::Cell *mux_cell = module->addCell(NEW_ID, "$safe_pmux"); | ||||
| 			mux_cell->setPort("\\A", sig_a); | ||||
| 			mux_cell->setPort("\\B", sig_b); | ||||
| 			mux_cell->setPort("\\S", sig_s); | ||||
| 			mux_cell->setPort("\\Y", RTLIL::SigSpec(next_state_wire)); | ||||
| 			mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.size()); | ||||
| 			mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.size()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Generate ctrl_out signal
 | ||||
|  |  | |||
|  | @ -30,6 +30,48 @@ struct FsmOpt | |||
| 	FsmData fsm_data; | ||||
| 	RTLIL::Cell *cell; | ||||
| 	RTLIL::Module *module; | ||||
| 
 | ||||
| 	void opt_unreachable_states() | ||||
| 	{ | ||||
| 		while (1) | ||||
| 		{ | ||||
| 			std::set<int> unreachable_states; | ||||
| 			std::vector<FsmData::transition_t> new_transition_table; | ||||
| 			std::vector<RTLIL::Const> new_state_table; | ||||
| 			std::map<int, int> old_to_new_state; | ||||
| 
 | ||||
| 			for (int i = 0; i < SIZE(fsm_data.state_table); i++) | ||||
| 				if (i != fsm_data.reset_state) | ||||
| 					unreachable_states.insert(i); | ||||
| 
 | ||||
| 			for (auto &trans : fsm_data.transition_table) | ||||
| 				unreachable_states.erase(trans.state_out); | ||||
| 
 | ||||
| 			if (unreachable_states.empty()) | ||||
| 				break; | ||||
| 
 | ||||
| 			for (int i = 0; i < SIZE(fsm_data.state_table); i++) { | ||||
| 				if (unreachable_states.count(i)) { | ||||
| 					log("  Removing unreachable state %s.\n", log_signal(fsm_data.state_table[i])); | ||||
| 					continue; | ||||
| 				} | ||||
| 				old_to_new_state[i] = SIZE(new_state_table); | ||||
| 				new_state_table.push_back(fsm_data.state_table[i]); | ||||
| 			} | ||||
| 
 | ||||
| 			for (auto trans : fsm_data.transition_table) { | ||||
| 				if (unreachable_states.count(trans.state_in)) | ||||
| 					continue; | ||||
| 				trans.state_in = old_to_new_state.at(trans.state_in); | ||||
| 				trans.state_out = old_to_new_state.at(trans.state_out); | ||||
| 				new_transition_table.push_back(trans); | ||||
| 			} | ||||
| 
 | ||||
| 			new_transition_table.swap(fsm_data.transition_table); | ||||
| 			new_state_table.swap(fsm_data.state_table); | ||||
| 			fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	bool signal_is_unused(RTLIL::SigSpec sig) | ||||
| 	{ | ||||
|  | @ -253,6 +295,8 @@ struct FsmOpt | |||
| 		this->cell = cell; | ||||
| 		this->module = module; | ||||
| 
 | ||||
| 		opt_unreachable_states(); | ||||
| 
 | ||||
| 		opt_unused_outputs(); | ||||
| 
 | ||||
| 		opt_alias_inputs(); | ||||
|  |  | |||
|  | @ -17,7 +17,8 @@ python generate.py | |||
| 		idx=$( printf "%05d" $i ) | ||||
| 		echo "temp/uut_${idx}.log: temp/uut_${idx}.ys temp/uut_${idx}.v" | ||||
| 		echo "	@echo -n '[$i]'" | ||||
| 		echo "	@../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys" | ||||
| 		echo "	@../../yosys -ql temp/uut_${idx}.out temp/uut_${idx}.ys" | ||||
| 		echo "	@mv temp/uut_${idx}.out temp/uut_${idx}.log" | ||||
| 		echo "	@grep -q 'SAT proof finished' temp/uut_${idx}.log && echo -n K || echo -n T" | ||||
| 		all_targets="$all_targets temp/uut_${idx}.log" | ||||
| 	done | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue