mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-29 18:52:30 +00:00 
			
		
		
		
	Merge pull request #3778 from jix/yw_clk2fflogic
This commit is contained in:
		
						commit
						6f5d984bdb
					
				
					 7 changed files with 70 additions and 17 deletions
				
			
		|  | @ -736,6 +736,9 @@ struct AigerWriter | |||
| 				auto sig_qy = cell->getPort(cell->type.in(ID($anyconst), ID($anyseq)) ? ID::Y : ID::Q); | ||||
| 				SigSpec sig = sigmap(sig_qy); | ||||
| 
 | ||||
| 				if (cell->get_bool_attribute(ID(clk2fflogic))) | ||||
| 					sig_qy = cell->getPort(ID::D); // For a clk2fflogic $_FF_ the named signal is the D input not the Q output
 | ||||
| 
 | ||||
| 				for (int i = 0; i < GetSize(sig_qy); i++) { | ||||
| 					if (sig_qy[i].wire == nullptr || sig[i].wire == nullptr) | ||||
| 						continue; | ||||
|  |  | |||
|  | @ -728,6 +728,9 @@ struct BtorWorker | |||
| 			else | ||||
| 				btorf("%d state %d %s\n", nid, sid, log_id(symbol)); | ||||
| 
 | ||||
| 			if (cell->get_bool_attribute(ID(clk2fflogic))) | ||||
| 				ywmap_state(cell->getPort(ID::D)); // For a clk2fflogic FF the named signal is the D input not the Q output
 | ||||
| 			else | ||||
| 				ywmap_state(sig_q); | ||||
| 
 | ||||
| 			if (nid_init_val >= 0) { | ||||
|  |  | |||
|  | @ -626,8 +626,9 @@ struct Smt2Worker | |||
| 				} | ||||
| 
 | ||||
| 				bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst)); | ||||
| 				bool clk2fflogic = cell->type == ID($anyinit) && cell->get_bool_attribute(ID(clk2fflogic)); | ||||
| 				int smtoffset = 0; | ||||
| 				for (auto chunk : cell->getPort(QY).chunks()) { | ||||
| 				for (auto chunk : cell->getPort(clk2fflogic ? ID::D : QY).chunks()) { | ||||
| 					if (chunk.is_wire()) | ||||
| 						decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire, smtoffset)); | ||||
| 					smtoffset += chunk.width; | ||||
|  |  | |||
|  | @ -139,7 +139,12 @@ static bool rename_witness(RTLIL::Design *design, dict<RTLIL::Module *, int> &ca | |||
| 
 | ||||
| 		if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq))) { | ||||
| 			has_witness_signals = true; | ||||
| 			auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y; | ||||
| 			IdString QY; | ||||
| 			bool clk2fflogic = false; | ||||
| 			if (cell->type == ID($anyinit)) | ||||
| 				QY = (clk2fflogic = cell->get_bool_attribute(ID(clk2fflogic))) ? ID::D : ID::Q; | ||||
| 			else | ||||
| 				QY = ID::Y; | ||||
| 			auto sig_out = cell->getPort(QY); | ||||
| 
 | ||||
| 			for (auto chunk : sig_out.chunks()) { | ||||
|  | @ -151,6 +156,9 @@ static bool rename_witness(RTLIL::Design *design, dict<RTLIL::Module *, int> &ca | |||
| 					auto new_id = module->uniquify("\\_witness_." + name); | ||||
| 					auto new_wire = module->addWire(new_id, GetSize(sig_out)); | ||||
| 					new_wire->set_hdlname_attribute({ "_witness_", strstr(new_id.c_str(), ".") + 1 }); | ||||
| 					if (clk2fflogic) | ||||
| 						module->connect({new_wire, sig_out}); | ||||
| 					else | ||||
| 						module->connect({sig_out, new_wire}); | ||||
| 					cell->setPort(QY, new_wire); | ||||
| 					break; | ||||
|  |  | |||
|  | @ -292,10 +292,12 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | |||
| 	if (!purge_mode) | ||||
| 		for (auto &it : module->cells_) { | ||||
| 			RTLIL::Cell *cell = it.second; | ||||
| 			if (ct_reg.cell_known(cell->type)) | ||||
| 			if (ct_reg.cell_known(cell->type)) { | ||||
| 				bool clk2fflogic = cell->get_bool_attribute(ID(clk2fflogic)); | ||||
| 				for (auto &it2 : cell->connections()) | ||||
| 					if (ct_reg.cell_output(cell->type, it2.first)) | ||||
| 					if (clk2fflogic ? it2.first == ID::D : ct_reg.cell_output(cell->type, it2.first)) | ||||
| 						register_signals.add(it2.second); | ||||
| 			} | ||||
| 			for (auto &it2 : cell->connections()) | ||||
| 				connected_signals.add(it2.second); | ||||
| 		} | ||||
|  |  | |||
|  | @ -80,15 +80,27 @@ struct Clk2fflogicPass : public Pass { | |||
| 		return module->Eqx(NEW_ID, {sampled_sig, sig}, polarity ? SigSpec {State::S0, State::S1} : SigSpec {State::S1, State::S0}); | ||||
| 	} | ||||
| 	// Sampled and current value of a data signal.
 | ||||
| 	SampledSig sample_data(Module *module, SigSpec sig, RTLIL::Const init, bool is_fine) { | ||||
| 	SampledSig sample_data(Module *module, SigSpec sig, RTLIL::Const init, bool is_fine, bool set_attribute = false) { | ||||
| 		std::string sig_str = log_signal(sig); | ||||
| 		sig_str.erase(std::remove(sig_str.begin(), sig_str.end(), ' '), sig_str.end()); | ||||
| 
 | ||||
| 
 | ||||
| 		Wire *sampled_sig = module->addWire(NEW_ID_SUFFIX(stringf("%s#sampled", sig_str.c_str())), GetSize(sig)); | ||||
| 		sampled_sig->attributes[ID::init] = init; | ||||
| 
 | ||||
| 		Cell *cell; | ||||
| 		if (is_fine) | ||||
| 			module->addFfGate(NEW_ID, sig, sampled_sig); | ||||
| 			cell = module->addFfGate(NEW_ID, sig, sampled_sig); | ||||
| 		else | ||||
| 			module->addFf(NEW_ID, sig, sampled_sig); | ||||
| 			cell = module->addFf(NEW_ID, sig, sampled_sig); | ||||
| 
 | ||||
| 		if (set_attribute) { | ||||
| 			for (auto &chunk : sig.chunks()) | ||||
| 				if (chunk.wire != nullptr) | ||||
| 					chunk.wire->set_bool_attribute(ID::keep); | ||||
| 			cell->set_bool_attribute(ID(clk2fflogic)); | ||||
| 		} | ||||
| 
 | ||||
| 		return {sampled_sig, sig}; | ||||
| 	} | ||||
| 	SigSpec mux(Module *module, SigSpec a, SigSpec b, SigSpec s, bool is_fine) { | ||||
|  | @ -213,7 +225,7 @@ struct Clk2fflogicPass : public Pass { | |||
| 					if (ff.has_clk) | ||||
| 						ff.unmap_ce_srst(); | ||||
| 
 | ||||
| 					auto next_q = sample_data(module, ff.sig_q, ff.val_init, ff.is_fine).sampled; | ||||
| 					auto next_q = sample_data(module, ff.sig_q, ff.val_init, ff.is_fine, true).sampled; | ||||
| 
 | ||||
| 					if (ff.has_clk) { | ||||
| 						// The init value for the sampled d is never used, so we can set it to fixed zero, reducing uninit'd FFs
 | ||||
|  |  | |||
|  | @ -140,6 +140,7 @@ struct SimInstance | |||
| 	dict<SigBit, pool<Wire*>> upd_outports; | ||||
| 
 | ||||
| 	dict<SigBit, SigBit> in_parent_drivers; | ||||
| 	dict<SigBit, SigBit> clk2fflogic_drivers; | ||||
| 
 | ||||
| 	pool<SigBit> dirty_bits; | ||||
| 	pool<Cell*> dirty_cells; | ||||
|  | @ -270,6 +271,11 @@ struct SimInstance | |||
| 				ff.past_srst = State::Sx; | ||||
| 				ff.data = ff_data; | ||||
| 				ff_database[cell] = ff; | ||||
| 
 | ||||
| 				if (cell->get_bool_attribute(ID(clk2fflogic))) { | ||||
| 					for (int i = 0; i < ff_data.width; i++) | ||||
| 						clk2fflogic_drivers.emplace(sigmap(ff_data.sig_d[i]), sigmap(ff_data.sig_q[i])); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (cell->is_mem_cell()) | ||||
|  | @ -389,6 +395,10 @@ struct SimInstance | |||
| 			auto sigbit = sig[i]; | ||||
| 			auto sigval = value[i]; | ||||
| 
 | ||||
| 			auto clk2fflogic_driver = clk2fflogic_drivers.find(sigbit); | ||||
| 			if (clk2fflogic_driver != clk2fflogic_drivers.end()) | ||||
| 				sigbit = clk2fflogic_driver->second; | ||||
| 
 | ||||
| 			auto in_parent_driver = in_parent_drivers.find(sigbit); | ||||
| 			if (in_parent_driver == in_parent_drivers.end()) | ||||
| 				set_state(sigbit, sigval); | ||||
|  | @ -589,7 +599,7 @@ struct SimInstance | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	bool update_ph2(bool gclk) | ||||
| 	bool update_ph2(bool gclk, bool stable_past_update = false) | ||||
| 	{ | ||||
| 		bool did_something = false; | ||||
| 
 | ||||
|  | @ -600,7 +610,7 @@ struct SimInstance | |||
| 
 | ||||
| 			Const current_q = get_state(ff.data.sig_q); | ||||
| 
 | ||||
| 			if (ff_data.has_clk) { | ||||
| 			if (ff_data.has_clk && !stable_past_update) { | ||||
| 				// flip-flops
 | ||||
| 				State current_clk = get_state(ff_data.sig_clk)[0]; | ||||
| 				if (ff_data.pol_clk ? (ff.past_clk == State::S0 && current_clk != State::S0) : | ||||
|  | @ -621,7 +631,7 @@ struct SimInstance | |||
| 			if (ff_data.has_aload) { | ||||
| 				State current_aload = get_state(ff_data.sig_aload)[0]; | ||||
| 				if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) { | ||||
| 					current_q = ff_data.has_clk ? ff.past_ad : get_state(ff.data.sig_ad); | ||||
| 					current_q = ff_data.has_clk && !stable_past_update ? ff.past_ad : get_state(ff.data.sig_ad); | ||||
| 				} | ||||
| 			} | ||||
| 			// async reset
 | ||||
|  | @ -672,6 +682,8 @@ struct SimInstance | |||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if (stable_past_update) | ||||
| 						continue; | ||||
| 					if (port.clk_polarity ? | ||||
| 							(mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) : | ||||
| 							(mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0)) | ||||
|  | @ -701,7 +713,7 @@ struct SimInstance | |||
| 		} | ||||
| 
 | ||||
| 		for (auto it : children) | ||||
| 			if (it.second->update_ph2(gclk)) { | ||||
| 			if (it.second->update_ph2(gclk, stable_past_update)) { | ||||
| 				dirty_children.insert(it.second); | ||||
| 				did_something = true; | ||||
| 			} | ||||
|  | @ -1196,10 +1208,22 @@ struct SimWorker : SimShared | |||
| 	} | ||||
| 
 | ||||
| 	void initialize_stable_past() | ||||
| 	{ | ||||
| 
 | ||||
| 		while (1) | ||||
| 		{ | ||||
| 			if (debug) | ||||
| 				log("\n-- ph1 (initialize) --\n"); | ||||
| 
 | ||||
| 			top->update_ph1(); | ||||
| 
 | ||||
| 			if (debug) | ||||
| 				log("\n-- ph2 (initialize) --\n"); | ||||
| 
 | ||||
| 			if (!top->update_ph2(false, true)) | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (debug) | ||||
| 			log("\n-- ph3 (initialize) --\n"); | ||||
| 		top->update_ph3(true); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue