This warning is usually quite handy, but is problematic in tests:
although it can be suppressed by using Fragment.get on elaboratable,
that is not always possible, in particular when writing tests for
exceptions raised by __init__, e.g.:
def test_wrong_csr_bus(self):
with self.assertRaisesRegex(ValueError, r"blah blah"):
WishboneCSRBridge(csr_bus=object())
In theory, it should be possible to suppress warnings per-module
and even per-line using code such as:
import re, warnings
from nmigen.hdl.ir import UnusedElaboratable
warnings.filterwarnings("ignore", category=UnusedElaboratable,
module=re.escape(__name__))
Unfortunately, not only is this code quite convoluted, but it also
does not actually work; we are using warnings.warn_explicit() because
we collect source locations on our own, but it requires the caller
to extract the __warningregistry__ dictionary from module globals,
or warning suppression would not work. Not only is this not feasible
in most diagnostic sites in nMigen, but also I never got it to work
anyway, even when passing all of module, registry, and module_globals
to warn_explicit().
Instead, use a magic comment at the start of a file to do this job,
which might not be elegant but is simple and practical. For now,
only UnusedElaboratable can be suppressed with it, but in future,
other linter parameters may become tweakable this way.
We don't have any other convenient shortcut for x[off*w:(off+1)*w],
but using word_select to extract a single static range would result
in severe bloat of emitted code through expansion to dead branches.
Recognize and simplify this pattern.
It turns out that while Python does not import _private identifiers
when using * imports, it does nevertheless import all submodules.
Avoid polluting the namespace in the prelude by explicitly listing
all exported identifiers.
Although constructor methods can improve clarity, there are many
contexts in which it is useful to use range() as a shape: notably
Layout, but also Const and AnyConst/AnyValue. Instead of duplicating
these constructor methods everywhere (which is not even easily
possible for Layout), use casting to Shape, introduced in 6aabdc0a.
Fixes#225.
Shapes have long been a part of nMigen, but represented using tuples.
This commit adds a Shape class (using namedtuple for backwards
compatibility), and accepts anything castable to Shape (including
enums, ranges, etc) anywhere a tuple was accepted previously.
In addition, `signed(n)` and `unsigned(n)` are added as aliases for
`Shape(n, signed=True)` and `Shape(n, signed=False)`, transforming
code such as `Signal((8, True))` to `Signal(signed(8))`.
These aliases are also included in prelude.
Preparation for #225.
This can cause confusion:
* If the erroneous object is None, it is printed as 'None', which
appears as a string (and could be the result of converting None
to a string.)
* If the erroneous object is a string, it is printed as ''<val>'',
which is a rather strange combination of quotes.
The write port priority in Yosys is derived directly from the order
in which the ports are declared in the Verilog frontend. It is being
removed for several reasons:
1. It is not clear if it works correctly for all cases (FFRAM,
LUTRAM, BRAM).
2. Although it is roundtripped via Verilog with correct simulation
semantics, the resulting code has a high chance of being
interpreted incorrectly by Xilinx tools.
3. It cannot be roundtripped via FIRRTL, which is an alternative
backend that is an interesting future option. (FIRRTL leaves
write collision completely undefined.)
3. It is a niche feature that, if it is needed, can be completely
replaced using an explicit comparator, priority encoder, and
write enable gating circuit. (This is what Xilinx recommends
for handling this case.)
In the future we should extend nMigen's formal verification to assert
that a write collision does not happen.
Almost no code would specify Signal(_, name) as a positional argument
on purpose, but forgetting parens and accidentally placing signedness
into the name position is so common that we had a test for it.
This is necessary for consistency, since for transparent read ports,
we currently do not support .en at all (it is fixed at 1) due to
YosysHQ/yosys#760. Before this commit, changing port transparency
would require adding or removing an assignment to .en, which is
confusing and error-prone.
Also, most read ports are always enabled, so this behavior is also
convenient.
Also, replace `bits, sign = x.shape()` with more idiomatic
`width, signed = x.shape()`.
This unifies all properties corresponding to `len(x)` to `x.width`.
(Not all values have a `width` property.)
Fixes#210.
Platform.prepare() was completely broken after addition of local
clock domains, and only really worked before by a series of
accidents because there was a circular dependency between creation
of missing domains, fragment preparation, and insertion of pin
subfragments.
This commit untangles the dependency by adding a separate public
method Fragment.create_missing_domains(), used in build.plat.
It also makes DomainCollector consider both used and defined domains,
such that it will work on fragments before domain propagation, since
create_missing_domains() can be called by user code before prepare().
The fragment driving missing clock domain is not flattened anymore,
because flattening does not work well combined with local domains.
The elaboratable is already likely driving the clk/rst signals in
some way appropriate for the platform; if we expose them as ports
nevertheless it will cause problems downstream.
This pattern usually produces an extremely hard to notice bug that
will usually break a design when it is triggered, but will also be
hidden unless the pathological value of a boolean switch is used.
Fixes#159.
This might help with propagation of locations through optimizer
passes, since not all of them take care to preserve cells at all,
but usually wires stay intact when possible.
Also fixes incorrect source location on value.part().
Before this commit, it was a print statement, and therefore, command
interpreter options like -Wignore did not affect it. There is no API
to access the warning filter list, so it was turned into a real
warning; and further, since Python 3.6, tracemalloc can be used
as a standard method to display traceback to allocation site instead
of the ad-hoc traceback logic that was used in Elaboratable before.
This primarily fixes the problem with source location precision in
Module (which used to trace locations from __exit__ of the context
managers, by which point everything interesting has been lost), but
also improves memory port and control inserter source locations.
On the sample of examples/basic/*.py, the only incorrectly inferred
remaining location is clk pointing to hdl/mem.py:166.
This means that instead of:
with m.Case(0b00):
<body>
with m.Case(0b01):
<body>
it is legal to write:
with m.Case(0b00, 0b01):
<body>
with no change in semantics, and slightly nicer RTLIL or Verilog
output.
Fixes#103.
This simplifies creation of related signals with nice names during
metaprogramming, e.g.
def make_ff(m, sig):
sig_ff = Signal.like(sig, name_suffix="_ff")
m.d.sync += sig_ff.eq(sig)
return sig_ff
The coercion is carefully chosen to accept (other than normal ints)
instances of e.g. np.int64, but reject instances of e.g. float.
See https://stackoverflow.com/a/48940855/254415 for details.
Fixes#93.
This commit:
* moves lists of universally useful imports from `nmigen` to
`nmigen.hdl` and `nmigen.lib`, reimporting them in `nmigen`;
* replaces lots of imports from individual parts of `nmigen.hdl`
with a star import from `nmigen.hdl`;
* replaces imports in tests with what we expect downstream code
to use;
* adds some missing imports in `nmigen.formal`.