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
 | 	// generate next_state signal
 | ||||||
| 
 | 
 | ||||||
| 	RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size()); | 	if (SIZE(fsm_data.state_table) == 1) | ||||||
| 
 |  | ||||||
| 	for (size_t i = 0; i < fsm_data.state_table.size(); i++) |  | ||||||
| 	{ | 	{ | ||||||
| 		std::map<RTLIL::Const, std::set<int>> pattern_cache; | 		module->connect(next_state_wire, fsm_data.state_table.front()); | ||||||
| 		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)); |  | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		RTLIL::SigSpec sig_a, sig_b, sig_s; | 		RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size()); | ||||||
| 		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++) { | 		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) { | 			std::map<RTLIL::Const, std::set<int>> pattern_cache; | ||||||
| 				sig_a = RTLIL::SigSpec(state); | 			std::set<int> fullstate_cache; | ||||||
| 			} else { | 
 | ||||||
| 				sig_b.append(RTLIL::SigSpec(state)); | 			for (size_t j = 0; j < fsm_data.state_table.size(); j++) | ||||||
| 				sig_s.append(RTLIL::SigSpec(next_state_onehot, i)); | 				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"); | 		if (encoding_is_onehot) | ||||||
| 		mux_cell->setPort("\\A", sig_a); | 		{ | ||||||
| 		mux_cell->setPort("\\B", sig_b); | 			RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width); | ||||||
| 		mux_cell->setPort("\\S", sig_s); | 			for (size_t i = 0; i < fsm_data.state_table.size(); i++) { | ||||||
| 		mux_cell->setPort("\\Y", RTLIL::SigSpec(next_state_wire)); | 				RTLIL::Const state = fsm_data.state_table[i]; | ||||||
| 		mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.size()); | 				int bit_idx = -1; | ||||||
| 		mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.size()); | 				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
 | 	// Generate ctrl_out signal
 | ||||||
|  |  | ||||||
|  | @ -31,6 +31,48 @@ struct FsmOpt | ||||||
| 	RTLIL::Cell *cell; | 	RTLIL::Cell *cell; | ||||||
| 	RTLIL::Module *module; | 	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) | 	bool signal_is_unused(RTLIL::SigSpec sig) | ||||||
| 	{ | 	{ | ||||||
| 		RTLIL::SigBit bit = sig.to_single_sigbit(); | 		RTLIL::SigBit bit = sig.to_single_sigbit(); | ||||||
|  | @ -253,6 +295,8 @@ struct FsmOpt | ||||||
| 		this->cell = cell; | 		this->cell = cell; | ||||||
| 		this->module = module; | 		this->module = module; | ||||||
| 
 | 
 | ||||||
|  | 		opt_unreachable_states(); | ||||||
|  | 
 | ||||||
| 		opt_unused_outputs(); | 		opt_unused_outputs(); | ||||||
| 
 | 
 | ||||||
| 		opt_alias_inputs(); | 		opt_alias_inputs(); | ||||||
|  |  | ||||||
|  | @ -17,7 +17,8 @@ python generate.py | ||||||
| 		idx=$( printf "%05d" $i ) | 		idx=$( printf "%05d" $i ) | ||||||
| 		echo "temp/uut_${idx}.log: temp/uut_${idx}.ys temp/uut_${idx}.v" | 		echo "temp/uut_${idx}.log: temp/uut_${idx}.ys temp/uut_${idx}.v" | ||||||
| 		echo "	@echo -n '[$i]'" | 		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" | 		echo "	@grep -q 'SAT proof finished' temp/uut_${idx}.log && echo -n K || echo -n T" | ||||||
| 		all_targets="$all_targets temp/uut_${idx}.log" | 		all_targets="$all_targets temp/uut_${idx}.log" | ||||||
| 	done | 	done | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue