On Python <3.10, classes without annotations do not get an
`__annotations__` member at all, so the `getattr` on a subclass falls
back to the parent class `__annotations__`, attempting to create
signature members twice. Fix that by looking at the `__dict__` instead.
While the capability of providing signatures for components that are not
parametric is useful, most Amaranth gateware is heavily parameterized,
and the capability is not worth making most subclasses Liskov-incompatible
with the base class (where the derived class would not provide `signature`
as a class method anymore).
This was introduced in commit 44711b7d, and was never used within
Amaranth itself. While technically a breaking change I think this
will not cause enough breakage to warrant a deprecation cycle
(nor can we make this a deprecation this without a lot of work).
The attribute sees essentially no use and the information is much
better served by putting it in the module name. In addition this
means that the entire tree can be renamed simply by renaming the top
module.
Tools like GTKWave show the names of the instances, not the modules,
so they are not affected by the longer names.
It was thought previously (by me) that adding a wire that does
nothing to an empty subfragment is enough to prevent it from being
treated as a blackbox. This is enough for Yosys but not Vivado.
Another workaround could probably be used that satisfies both, but
instead let's just not translate any empty subfragments.
This doesn't account for the case of the empty toplevel, but that
does not seem worth addressing.
Fixes#899.
Tracking #879.
The directions of signals in `Pin` make it convenient to use a pin
signature in a component, such as in:
class LEDDriver(Component):
pins: Out(Signature({"o": Out(1)}))
led_driver = LEDDriver()
connect(led_driver.pins, platform.request("led"))
The `platform.request` call, correspondingly, returns a flipped `Pin`
object.
The design decision of using split memory ports in the internal
representation (copied from Yosys) was misguided and caused no end
of misery. Remove any uses of `$memrd`/`$memwr` and lower memories
directly to a combined memory cell, currently the RTLIL one.
This makes the build impure and also causes the contents of a file
outside of the build directory to be overwritten.
The check in `BuildPlan.execute_local` is also expanded to cover
the possibility of an absolute path sneaking through.
Because `importlib.metadata.PackageNotFoundError` inherits from
`ImportError`, the code did not previously work in the way that was
stated in the comment. We should probably deprecate `__version__`
entirely at some point.
If it adds to the environment then it ultimately creates the same
kind of problem it was intended to solve--a need to reproduce
the calls to `subprocess` in the code outside. It's not that hard
to merge two dicts, plus much of the time enough you can get by with
having just `PATH` and `AMARANTH_ENV_*` (if even that).
If an override is wanted it can be done easily enough with:
.execute_local(env={**os.environ, "VAR": "VALUE"})
Build scripts are explicitly intended to have overrides that are
done through the use of environment variables, and right now this
would require a very awkward `run_script=False` invocation followed
by copying a bit of code out of the Amaranth codebase, which is
clearly suboptimal.
Using `sys.excepthook` to silence the must-use warning has some false
negatives: applications may catch the exception and then quit
normally, e.g. becaue the error is well known and does not require
a traceback to be shown (which would be noisy). The current
implementation prints even more noise in that case.
In addition to the existing heuristic, silence the warning if
*nothing* has been elaborated, which is almost always a reliable
sign. It doesn't work if multiple designs are independently created
in the application and some of them are dropped without being used,
but this is unavoidable as it is not distinguishable from the mistake
this warning is attempting to prevent.
Fixes#848.
The main purpose of this change is migrating glasgow from the compat
`TSTriple` (which allows 0 width) to `Pin`. This sort of change would
normally require a RFC, but `Pin` is already slated for
removal/replacement, so that was deemed to be unnecessary.
There's an actual `py_enum.member` (which we briefly overwrite our loop
index with (!)). We delete our `member`, but it's still in the
`__all__` that came from `py_enum`, so `import *` fails.
Amaranth bitwise negation `~` compiles to Python bitwise negation `~` in
simulation; the same holds for comparison operators such as `==`. Thus
an expression such as `~(a == b)` in simulation will compile to Python
that takes the bitwise negation of the comparison result, which will be
an actual bool.
On 3.12, the result is a `DeprecationWarning` emitted only at simulation
run-time.
When negating in simulation, coerce the value to an int. `mask` is
sufficient as we do no further arithmetic here.
This fixes the following issues:
- on Python 3.10 and earlier, storing to free variables is now handled
correctly
- on Python 3.11, `_varname_from_oparg` is now used, fixing problems
with cell variables that are also arguments
- on all supported versions, EXTENDED_ARG is now parsed, ensuring proper
handling for long functions
Fixes#792.
This is actually an existing correctness requirement (for the similar
reasons that ValueCastable.as_value() must always return the same
value every time) that for some reason wasn't respected.
See amaranth-lang/rfcs#15 and #784.
Note that this RFC breaks the existing syntax for initializing a view
with a new signal. Instances of `View(layout)` *must* be changed to
`Signal(layout)`.
See amaranth-lang/rfcs#15 and #784.
Note that this RFC breaks the existing syntax for initializing a view
with a new signal. Instances of `View(layout)` *must* be changed to
`Signal(layout)`.
The __init_subclass__ method fires on class definition rather than use.
It also has the bonus impact that no __new__ method is defined, so the
classes can be correctly detected as mix-in classes by modules such as
enum.