* 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.
This isn't expected to result in a significant increase in memory use,
so for now it's enabled by default. Elaboration chains where it is not
desired to preserve origins can delete the `origins` attribute from
the fragment and nothing will be stored.
The interface `Fragment.origins` remains private, as is the rest of
the `Fragment` interface (including itself), but it enables certain
codebases that currently use a much more invasive technique to rely on
reading a single private field.
Use _EnumDict._member_names to determine which members to consider.
This way we don't need to redo sunder/dunder checks, and `nonmember`s
(introduced in py3.11) are correctly excluded.
This is a defacto public API, given it remains usable from py3.8
until py3.12 inclusive. (_member_names changes from a list to a
keys-only dict for performance reasons in py3.11, but they iterate the
same.) In current Python main (i.e. what will most likely be 3.13), a
"member_names" property is added which returns those keys.
The new intermediate representation will enable global analyses
on Amaranth code without lowering it to another representation
such as RTLIL.
This commit also changes the RTLIL builder to use the new IR.
Co-authored-by: Wanda <wanda@phinode.net>
This commit also contains a related semantic change: it adds `Shape`
and `ShapeCastable` to the `__all__` list in `amaranth.hdl`. This is
consistent with the policy that is laid out in the new documentation,
which permits such additions without notice.
Co-authored-by: mcclure <mcclure@users.noreply.github.com>
This change completes commit 9dc0617e and makes all the tests pass.
It corresponds with the ongoing langauge reference documentation effort.
Fixes#781.
Reexports of `amaranth.utils` functions are removed from
`amaranth._utils` to avoid a circular import issue (for `deprecated`).
Since this is a private module, this should not be a problem.