This check was originally added out of abundance of caution, but since
then it was observed that reset-less-ness is purely an implementation
detail (see #1220), and furthermore it interferes with adaptation of
`FIFOInterface`` signals (where `[rw]_data` are reset-less) for RFC 61.
These accessors used to be necessary (in addition to `.shape()`) while
the AST nodes were mutable. However, after commit 2bf1b4da that made
AST nodes immutable, there is no technical requirement to keep them
around. Additionally:
- `len(value)` is shorter than `value.width` and works with any `value`
- `value.shape().signed` is longer than `value.signed` but works with
any `value`
* Given a private name `$\d+` in RTLIL (as they are not named in the IR)
* Not automatically added to VCD files (as they are not named in the IR)
* Cannot be traced to a VCD (as they have no name to put in the file)
* Cannot be used with an unnamed top-level port (as there is no name)
If delta cycles are expanded (i.e. if the `fs_per_delta` argument to
`Simulator.write_vcd` is not zero), then create a string typed variable
for each testbench in the simulation, which reflects the current
command being executed by that testbench. To make all commands visible,
insert a (visual) delta cycle after each executed command, and ensure
that there is a change/crossing point in the waveform display each time
a command is executed, even if several identical ones in a row.
If delta cycles are not expanded, the behavior is unchanged.
This commit adds an option `fs_per_delta=` to `Simulator.write_vcd()`.
Specifying a positive integer value for it causes the simulator to
offset value change times by that many femtoseconds for each delta
cycle after the last timeline advancement.
This option is only suitable for debugging. If the timeline is advanced
by less than the combined duration of expanded delta cycles, an error
similar to the following will be raised:
vcd.writer.VCDPhaseError: Out of order timestamp: 62490
Typically `fs_per_delta=1` is best, since it allows thousands of delta
cycles to be expanded without risking a VCD phase error, but bigger
values can be used for an exaggerated visual effect.
Also, the VCD writer is changed to use 1 fs as the timebase instead of
1 ps. This change is largely invisible to designers, resulting only in
slightly larger VCD files due to longer timestamps.
Since the `fs_per_delta=` option is per VCD writer, it is possible to
simultaneously dump two VCDs, one with and one without delta cycle
expansion:
with sim.write_vcd("sim.vcd"), sim.write_vcd("sim.d.vcd", fs_per_delta=1):
sim.run()
Before this commit, testbenches (generators added with `add_testbench`)
were not only preemptible after any `yield`, but were *guaranteed* to
be preempted by another testbench after *every* yield. This is evil:
if you have any race condition between testbenches, which is common,
this scheduling strategy will maximize the resulting nondeterminism by
interleaving your testbench with every other one as much as possible.
This behavior is an outcome of the way `add_testbench` is implemented,
which is by yielding `Settle()` after every command.
One can observe that:
- `yield value_like` should never preempt;
- `yield assignable.eq()` in `add_process()` should not preempt, since
it only sets a `next` signal state, or appends to `write_queue` of
a memory state, and never wakes up processes;
- `yield assignable.eq()` in `add_testbench()` should only preempt if
changing `assignable` wakes up an RTL process. (It could potentially
also preempt if that wakes up another testbench, but this has no
benefit and requires `sim.set()` from RFC 36 to be awaitable, which
is not desirable.)
After this commit, `PySimEngine._step()` is implemented with two nested
loops instead of one. The outer loop iterates through every testbench
and runs it until an explicit wait point (`Settle()`, `Delay()`, or
`Tick()`), terminating when no testbenches are runnable. The inner loop
is the usual eval/commit loop, running whenever a testbench changes
design state.
`PySimEngine._processes` is a `set`, which doesn't have a deterministic
iteration order. This does not matter for processes, where determinism
is guaranteed by the eval/commit loop, but causes racy testbenches to
pass or fail nondeterministically (in practice depending on the memory
layout of the Python process). While it is best to not have races in
the testbenches, this commit makes `PySimEngine._testbenches` a `list`,
making the outcome of a race deterministic, and enabling a hacky work-
around to make them work: reordering calls to `add_testbench()`.
A potential future improvement is a simulation mode that, instead,
randomizes the scheduling of testbenches, exposing race conditions
early.
The abbreviated form was initially added to match `lib.fifo`, but it
looks very out of place on `lib.memory`, and we may be moving away from
such heavy use of abbreviations anyway.
While technically a breaking change, these attributes have very narrow
usefulness and so this change qualifies as "minor".
Display `shape` and `depth` also. `depth` is redundant although useful
for ease of reading (there are always `depth` elements shown), but
`shape` was just lost.
This attribute is fully redundant with `.__len__()`, and is out of place
on a `list`-like container like `Memory.Init`.
The `.shape` attribute, however, provides a unique function.