Yosys offers no stability guarantees for individual `proc_*` passes,
though so far it worked out fine. This commit changes the Verilog
backend to use `proc -nomux` instead, which is guaranteed to have
backwards-compatible behavior.
Fixes#479.
Before this commit, each simulation engine (which is only pysim at
the moment, but also cxxsim soon) was a subclass of SimulatorCore,
and every simulation engine module would essentially duplicate
the complete structure of a simulator, with code partially shared.
This was a really bad idea: it was inconvenient to use, with
downstream code having to branch between e.g. PySettle and CxxSettle;
it had no well-defined external interface; it had multiple virtually
identical entry points; and it had no separation between simulation
algorithms and glue code.
This commit completely rearranges simulation code.
1. sim._base defines internal simulation interfaces. The clarity of
these internal interfaces is important because simulation
engines mix and match components to provide a consistent API
regardless of the chosen engine.
2. sim.core defines the external simulation interface: the commands
and the simulator facade. The facade provides a single entry
point and, when possible, validates or lowers user input.
It also imports built-in simulation engines by their symbolic
name, avoiding eager imports of pyvcd or ctypes.
3. sim.xxxsim (currently, only sim.pysim) defines the simulator
implementation: time and state management, process scheduling,
and waveform dumping.
The new simulator structure has none of the downsides of the old one.
See #324.
The overhead of coroutine processes is fairly high. A clock driver
implemented through a coroutine process is mostly overhead. This was
partially addressed in commit 2398b792 by microoptimizing yielding.
This commit eliminates the coroutine process overhead completely by
introducing dedicated clock processes. It also simplifies the logic
to a simple toggle.
This change improves runtime by about 12% on Minerva SRAM SoC.
Compared to tests in the repository root, tests in the package have
many downsides:
* Unless explicitly excluded in find_packages(), tests and their
support code effectively become a part of public API.
This, unfortunately, happened with FHDLTestCase, which was never
intended for downstream use.
* Even if explicitly excluded from the setuptools package, using
an editable install, or setting PYTHONPATH still allows accessing
the tests.
* Having a sub-package that is present in the source tree but not
exported (or, worse, exported only sometimes) is confusing.
* The name `nmigen.test` cannot be used for anything else, such as
testing utilities that *are* intended for downstream use.
In commit 9faa1d37, the RTLIL backend was changed to ignore modules
without ports completely, since Yosys would recognize empty modules
as black boxes without explicit `write_verilog -noblackbox` and break
the design. That change had many flaws:
* It removed instances without ports, which are used in e.g. SoC
FPGAs to instantiate a dummy CPU.
* It removed fragments without ports, which can appear in e.g. SoC
FPGAs in case the fabric is not connected to any I/O ports.
* Finally, it was just conceptually unjustified.
This commit changes the logic to actually check for empty fragments,
and instead of removing them, it adds a dummy wire inside. It would
be possible to use the Yosys-specific (*noblackbox*) attribute.
However, it would be necessary to strip it for most targets right
away, and also the wire doubles as documentation.
Fixes#441.
Verilog has an edge case where an `always @*` process, which is used
to describe a combinatorial function procedurally, may not execute
at time zero because none of the signals in its implicit sensitivity
list change, i.e. when the process doesn't read any signals. This
causes the wires driven by the process to stay undefined.
The workaround to this problem (assuming SystemVerilog `always_comb`
is not available) is to introduce a dummy signal that changes only
at time zero and is optimized out during synthesis. nMigen has had
its own workaround, `$verilog_initial_trigger`, for a while. However,
`proc_prune`, while increasing readability, pulls references to this
signal out of the process. Because of this, a similar workaround was
implemented in Yosys' `write_verilog` itself.
This commit ensures we use our workaround on versions of Yosys
without the updated `write_verilog`, and Yosys' workaround on later
versions.
Fixes#418.
When a literal is used on the left-hand side of a numeric operator,
Python is able to constant-fold some expressions:
>>> dis.dis(lambda x: 0 + 0 + x)
1 0 LOAD_CONST 1 (0)
2 LOAD_FAST 0 (x)
4 BINARY_ADD
6 RETURN_VALUE
If a literal is used on the right-hand side such that the left-hand
side is variable, this doesn't happen:
>>> dis.dis(lambda x: x + 0 + 0)
1 0 LOAD_FAST 0 (x)
2 LOAD_CONST 1 (0)
4 BINARY_ADD
6 LOAD_CONST 1 (0)
8 BINARY_ADD
10 RETURN_VALUE
PyRTL generates fairly redundant code due to the pervasive masking,
and because of that, transforming expressions into the former form,
where possible, improves runtime by about 10% on Minerva SRAM SoC.
Before this commit, ArrayProxy would add sign padding (an extra bit)
a homogeneous array of signed values, or an array where all unsigned
values are smaller than the largest signed one. After this commit,
ArrayProxy would only add padding in arrays with mixed signedness
where all signed values are smaller or equal in size to the largest
unsigned value.
Fixes#476.
Co-authored-by: Pepijn de Vos <pepijndevos@gmail.com>
When a port component is skipped, it should appear neither in the RTL
nor in the constraint file. However, passing around components of
differential ports explicitly makes that harder.
Fixes#456.
Supersedes #457.
Co-authored-by: Jean THOMAS <git0@pub.jeanthomas.me>
The parameter defaults to "ULTRASCALE", even when synthesizing for
7-series devices. This could lead to a simulation/synthesis mismatch,
and causes a warning.
Fixes#438.
This was added in commit bfd4538d based on a misunderstanding of how
Xilinx part numbers work.
* non-ultrascale 7-series parts don't have temperature grades;
* ultrascale parts have temperature grade as a part of speed grade.
This commit also fixes an issue introduced in 2606ee33 that regressed
simulator startup time and bloated VCD files. (It's actually about
10% faster now than *before* the regression was introduced.)
Compiled process names were never particularly useful (comments in
the source would make more sense for debugging), and coroutine
process names were actually source locations.
Since commit b9799b4c, the discovery mechanism for the Yosys required
to produce Verilog is different from the usual require_tool(); namely
it is possible to produce Verilog without a `yosys` binary on PATH.
Fixes#419.
Some people's workflows involve not using `pip`. This is not
a recommended way to use nMigen, but is prevalent enough for good
enough reason that we try to keep them working anyway.
This package is deprecated and introduces a massive amount of startup
latency. On my machine with 264 installed Python packages, it reduces
the time required to `import nmigen` from ~100ms to ~200ms.
Remove _EvalContext, which was a level of indirection serving almost
no purpose. (The only case where it would be useful is repeatedly
resetting a simulation that, each time it is reset, would create new
signals to communicate with between coroutine processes. In that case
the signal states would not be persisted in _SimulatorState, but
would be removed with the _EvalContext that is recreated each time
the simulation is reset. But this could be solved with a weak map
instead.)
This regresses simulator startup time by 10-15% for unknown reasons
but is necessary to align pysim and future cxxsim.
Do not use yosys binaries with unparseable version numbers. This ensures
that nmigen always knows what version of yosys it is generating RTLIL
for.
The effect of this change is that if the version number of the system
yosys is unparsable, nmigen will attempt to fallback to the builtin
Yosys.
Fixes#409.
Preserve the original user-provided shape, while still checking
its validity. This allows Enum decoders to work when specifying
record fields with Enums.
Fixes#393.
The nmigen-yosys PyPI package provides a custom, minimal build of
Yosys that uses (at the moment) wasmtime-py to deliver a single
WASM binary that can run on many platforms, and eliminates the need
to build Yosys from source.
Not only does this lower barrier to entry for new nMigen developers,
but also decouples nMigen from Yosys' yearly release cycle, which
lets us use new features and drop workarounds for Yosys bugs earlier.
The source for the nmigen-yosys package is provided at:
https://github.com/nmigen/nmigen-yosys
The package is built from upstream source and released automatically
with no manual steps.
Fixes#371.
For unknown reasons, Quartus treats {foo} and "foo" in completely
different ways, which is not true for normal Tcl code; specifically,
it preserves the braces if they are used. Because of this, since
commit 6cee2804, the vendor.intel package was completely broken.
In commit 892cff05, `-decimal` was used when writing Verilog for
Vivado targets because it treats (* keep=32'd1 *) and (* keep=1 *)
differently in violation of Verilog LRM. However, it is possible
to avoid that workaround by using (* keep="TRUE" *). Do that,
and remove `-decimal` to avoid special-casing 32-bit constants.
Refs #373.
It's not very nice to add more internal mutable state to Platform
related classes, but our whole approach for Platform is inherently
stateful, and other solutions (like changing every individual vendor
platform to check for unused signals) are even worse.
Fixes#374.
If the clock signal is not a top-level port and has aliases, it can
be optimized out, and then the constraint will no longer apply.
To prevent this, make sure the constrained signal is preferred over
any aliases by using the `keep` attribute.
Vivado does not parse attributes like (* keep = 32'd1 *) as valid
even though, AFAICT, they are equivalent to (* keep = 1 *) or simply
(* keep *) per IEEE 1364. To work around this, use the solution we
currently use for Quartus, which is `write_verilog -decimal`.
Fixes#373.
Before this commit, there was only occasional quoting of some names
used in any Tcl files. (I'm not sure what I was thinking.)
After this commit, any substs that may include Tcl special characters
are escaped. This does not include build names (which are explicitly
restricted to ASCII to avoid this problem), or attribute names (which
are chosen from a predefined set). Ideally we'd use a more principled
approach but Jinja2 does not support custom escaping mechanisms.
Note that Vivado restricts clock names to a more restrictive set that
forbids using Tcl special characters even when escaped.
Fixes#375.