diff options
| -rw-r--r-- | passes/opt/opt_dff.cc | 210 | 
1 files changed, 112 insertions, 98 deletions
diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 98b66dee3..73d674c8d 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -58,13 +58,10 @@ struct OptDffWorker  	typedef std::pair<RTLIL::SigBit, bool> ctrl_t;  	typedef std::set<ctrl_t> ctrls_t; -	ModWalker modwalker; -	QuickConeSat qcsat; -  	// Used as a queue.  	std::vector<Cell *> dff_cells; -	OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod), modwalker(module->design, module), qcsat(modwalker) { +	OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod) {  		// Gathering two kinds of information here for every sigmapped SigBit:  		//  		// - bitusers: how many users it has (muxes will only be merged into FFs if this is 1, making the FF the only user) @@ -569,100 +566,6 @@ struct OptDffWorker  				changed = true;  			} -			// Now check if any bit can be replaced by a constant. -			pool<int> removed_sigbits; -			for (int i = 0; i < ff.width; i++) { -				State val = ff.val_init[i]; -				if (ff.has_arst) -					val = combine_const(val, ff.val_arst[i]); -				if (ff.has_srst) -					val = combine_const(val, ff.val_srst[i]); -				if (ff.has_sr) { -					if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1)) -						val = combine_const(val, State::S0); -					if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1)) -						val = combine_const(val, State::S1); -				} -				if (val == State::Sm) -					continue; -				if (ff.has_clk || ff.has_gclk) { -					if (!ff.sig_d[i].wire) { -						val = combine_const(val, ff.sig_d[i].data); -						if (val == State::Sm) -							continue; -					} else { -						if (!opt.sat) -							continue; -						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it -						if (!modwalker.has_drivers(ff.sig_d.extract(i))) -							continue; -						if (val != State::S0 && val != State::S1) -							continue; - -						int init_sat_pi = qcsat.importSigBit(val); -						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]); -						int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]); - -						qcsat.prepare(); - -						// Try to find out whether the register bit can change under some circumstances -						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi))); - -						// If the register bit cannot change, we can replace it with a constant -						if (counter_example_found) -							continue; -					} -				} -				if (ff.has_aload) { -					if (!ff.sig_ad[i].wire) { -						val = combine_const(val, ff.sig_ad[i].data); -						if (val == State::Sm) -							continue; -					} else { -						if (!opt.sat) -							continue; -						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it -						if (!modwalker.has_drivers(ff.sig_ad.extract(i))) -							continue; -						if (val != State::S0 && val != State::S1) -							continue; - -						int init_sat_pi = qcsat.importSigBit(val); -						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]); -						int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]); - -						qcsat.prepare(); - -						// Try to find out whether the register bit can change under some circumstances -						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi))); - -						// If the register bit cannot change, we can replace it with a constant -						if (counter_example_found) -							continue; -					} -				} -				log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0, -						i, log_id(cell), log_id(cell->type), log_id(module)); - -				initvals.remove_init(ff.sig_q[i]); -				module->connect(ff.sig_q[i], val); -				removed_sigbits.insert(i); -			} -			if (!removed_sigbits.empty()) { -				std::vector<int> keep_bits; -				for (int i = 0; i < ff.width; i++) -					if (!removed_sigbits.count(i)) -						keep_bits.push_back(i); -				if (keep_bits.empty()) { -					module->remove(cell); -					did_something = true; -					continue; -				} -				ff = ff.slice(keep_bits); -				ff.cell = cell; -				changed = true; -			} -  			// The cell has been simplified as much as possible already.  Now try to spice it up with enables / sync resets.  			if (ff.has_clk) {  				if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) { @@ -818,6 +721,115 @@ struct OptDffWorker  		}  		return did_something;  	} + +	bool run_constbits() { +		ModWalker modwalker(module->design, module); +		QuickConeSat qcsat(modwalker); + +		// Run as a separate sub-pass, so that we don't mutate (non-FF) cells under ModWalker. +		bool did_something = false; +		for (auto cell : module->selected_cells()) { +			if (!RTLIL::builtin_ff_cell_types().count(cell->type)) +				continue; +			FfData ff(&initvals, cell); + +			// Now check if any bit can be replaced by a constant. +			pool<int> removed_sigbits; +			for (int i = 0; i < ff.width; i++) { +				State val = ff.val_init[i]; +				if (ff.has_arst) +					val = combine_const(val, ff.val_arst[i]); +				if (ff.has_srst) +					val = combine_const(val, ff.val_srst[i]); +				if (ff.has_sr) { +					if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1)) +						val = combine_const(val, State::S0); +					if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1)) +						val = combine_const(val, State::S1); +				} +				if (val == State::Sm) +					continue; +				if (ff.has_clk || ff.has_gclk) { +					if (!ff.sig_d[i].wire) { +						val = combine_const(val, ff.sig_d[i].data); +						if (val == State::Sm) +							continue; +					} else { +						if (!opt.sat) +							continue; +						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it +						if (!modwalker.has_drivers(ff.sig_d.extract(i))) +							continue; +						if (val != State::S0 && val != State::S1) +							continue; + +						int init_sat_pi = qcsat.importSigBit(val); +						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]); +						int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]); + +						qcsat.prepare(); + +						// Try to find out whether the register bit can change under some circumstances +						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi))); + +						// If the register bit cannot change, we can replace it with a constant +						if (counter_example_found) +							continue; +					} +				} +				if (ff.has_aload) { +					if (!ff.sig_ad[i].wire) { +						val = combine_const(val, ff.sig_ad[i].data); +						if (val == State::Sm) +							continue; +					} else { +						if (!opt.sat) +							continue; +						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it +						if (!modwalker.has_drivers(ff.sig_ad.extract(i))) +							continue; +						if (val != State::S0 && val != State::S1) +							continue; + +						int init_sat_pi = qcsat.importSigBit(val); +						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]); +						int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]); + +						qcsat.prepare(); + +						// Try to find out whether the register bit can change under some circumstances +						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi))); + +						// If the register bit cannot change, we can replace it with a constant +						if (counter_example_found) +							continue; +					} +				} +				log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0, +						i, log_id(cell), log_id(cell->type), log_id(module)); + +				initvals.remove_init(ff.sig_q[i]); +				module->connect(ff.sig_q[i], val); +				removed_sigbits.insert(i); +			} +			if (!removed_sigbits.empty()) { +				std::vector<int> keep_bits; +				for (int i = 0; i < ff.width; i++) +					if (!removed_sigbits.count(i)) +						keep_bits.push_back(i); +				if (keep_bits.empty()) { +					module->remove(cell); +					did_something = true; +					continue; +				} +				ff = ff.slice(keep_bits); +				ff.cell = cell; +				ff.emit(); +				did_something = true; +			} +		} +		return did_something; +	}  };  struct OptDffPass : public Pass { @@ -894,6 +906,8 @@ struct OptDffPass : public Pass {  			OptDffWorker worker(opt, mod);  			if (worker.run())  				did_something = true; +			if (worker.run_constbits()) +				did_something = true;  		}  		if (did_something)  | 
