* Instead of an ad hoc mix of optimizations and inferences, this tries
to make it more principled by first extracting a set of asynchronous
update rules from the process, then optimizing them before lowering
them to a concrete flip-flop type, preferring simpler ones
* early return caused proc_dff to stop considering rules after seeing
one async rule - this is because continue should have been used to
continue to procecssing the next rule instead of returning from the
function
* This fixes#4560, where previously the order that sync rules were
processed in depended on the order they were pulled out of a std::map.
This PR changes this to process them in the order they are found in,
respecting the priorities among the async signals
See the test case. PROC_ROM will consider this for evaluation, even
though -- without any actions -- lhs is empty (but still "uniform").
A zero-width memory is constructed, which later fails check with:
ERROR: Assert `width != 0' failed in kernel/mem.cc:518.
Ensure we don't proceed if there's nothing to encode.
An `std::vector<T>::reverse_iterator` stores the
`std::vector<T>::iterator` which points to the (forwards-ordered)
*following* item. Thus while `vec.rbegin()` dereferences to the final
item of `vec`, the iterator it wraps (`vec.rbegin().base()`) is equal to
`vec.end()`.
In the remove case here, we advance `it` (backwards), erasing the item
we just advanced past by grabbing its (pre-increment) base
forward-iterator and subtracting 1.
The iterator maths here is obviously all OK, but the forward-iterator
that `it` wraps post-increment actually points to the item we just
removed. That iterator was invalidated by the `erase()` call.
That this works anyway is (AFAICT) some combination of luck and/or
promises that aren't part of the C++ spec, but MSVC's debug iterator
support picks this up.
`erase()` returns the new iterator that follows the item just erased,
which happens to be the exact one we want our reverse-iterator to wrap
for the next loop; we get a fresh iterator to the same base, now without
the preceding item.
If width of a case expression was large, explicit patterns could cause
the existing logic to take an extremely long time, or exhaust the
maximum size of the underlying set. For cases where all of the patterns
are fully defined and there are no constants in the case expression,
this change uses a simple set to track which patterns have been seen.
Spotted during compilation:
passes/proc/proc_init.cc: In function ‘void {anonymous}::proc_init(Yosys::RTLIL::Module*, Yosys::SigMap&, Yosys::RTLIL::Process*)’:
passes/proc/proc_init.cc:31:7: warning: variable ‘found_init’ set but not used [-Wunused-but-set-variable]
The already-existing special case for conditionals on clock has been
remade as follows:
- now triggered for the last remaining edge trigger after all others
have been converted to async reset, not just when there is only one
sync rule in the first place
- does not require all contained assignments to be constant, as opposed
to a reset conditional — merely const-folds the condition
In addition, the code has been refactored a bit; as a bonus, the
priority order of async resets found is now preserved in resulting sync
rule ordering (though this is not yet respected by proc_dff).
Fixes#2656.
Before this commit, in a process like:
process $proc$bug.v:8$3
assign $foo \bar
switch \sel
case 1'1
assign $foo 1'1
assign $foo 1'1
case
assign $foo 1'0
end
end
both of the "assign $foo 1'1" would incorrectly be removed.
Fixes#1243.