Skip to content

Commit 480abc0

Browse files
committed
proc_dff: optimize self-assignment at bit granularity
1 parent b7c830b commit 480abc0

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

passes/proc/proc_dff.cc

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,28 +178,50 @@ class Dff {
178178
}
179179

180180
// If the lowest priority async rule assigns the output value to itself,
181-
// remove the rule and fold this into the input signal.
181+
// remove the rule and fold this into the input signal. If the LSB assigns
182+
// the output to itself but higher bits don't, we resize down to just the
183+
// LSBs that assign to themselves, allowing more optimized representations
184+
// for those bits.
182185
void optimize_self_assign(ConstEval& ce) {
183186
SigSpec sig_out_mapped = sig_out;
184187
ce.assign_map.apply(sig_out_mapped);
185188

186-
size_t new_size = async_rules.size();
187-
for (auto it = async_rules.crbegin(); it != async_rules.crend(); it++) {
188-
const auto& [value, trigger] = *it;
189+
// Calculate the number of low priority rules that can be folded into
190+
// the input signal for a given bit position
191+
const auto foldable_rules = [&](const size_t i) {
192+
size_t foldable = 0;
193+
for (auto it = async_rules.crbegin(); it != async_rules.crend(); it++, foldable++) {
194+
const auto& [value, trigger] = *it;
195+
if (value[i] != sig_out_mapped[i])
196+
break;
197+
}
198+
return foldable;
199+
};
200+
201+
// Work out how many bits from the lsb can be folded into the same
202+
// number of rules
203+
const size_t lsb_foldable_rules = foldable_rules(0);
189204

190-
if (value != sig_out_mapped)
205+
size_t new_size;
206+
for (new_size = 1; new_size < size(); new_size++)
207+
if (foldable_rules(new_size) != lsb_foldable_rules)
191208
break;
192209

193-
if (!trigger.inverted)
194-
sig_in = mod.Mux(NEW_ID, sig_in, value, trigger.sig);
195-
else
196-
sig_in = mod.Mux(NEW_ID, value, sig_in, trigger.sig);
210+
resize(new_size);
197211

198-
ce.eval(sig_in);
199-
new_size--;
200-
}
212+
if (lsb_foldable_rules == 0)
213+
return;
214+
215+
// Calculate the disjunction of triggers
216+
SigSpec triggers;
217+
for (size_t i = 0; i < lsb_foldable_rules; i++)
218+
triggers.append(async_rules.crbegin()[i].trigger.positive_trigger(mod));
219+
220+
const auto trigger = mod.ReduceOr(NEW_ID, triggers);
221+
sig_in = mod.Mux(NEW_ID, sig_in, sig_out, trigger);
222+
ce.eval(sig_in);
201223

202-
async_rules.resize(new_size);
224+
async_rules.resize(async_rules.size() - lsb_foldable_rules);
203225
}
204226

205227
// If we have only a single rule, this means we will generate either an $aldff

0 commit comments

Comments
 (0)