Skip to content

Commit

Permalink
sim: document.
Browse files Browse the repository at this point in the history
This commit includes additional non-documentation changes, related to
issues found while documenting it:
- `Simulator.run_until()` no longer accepts a `run_passive=` argument.
  Passive no longer exist and in any case defaulting to `False` does not
  make a lot of sense from an API perspective.
- `add_clock()`'s `phase=` argument, when specified, no longer has
  `period/2` added to it. This wasn't the documented behavior in first
  place and it makes no sense to do that.
- `add_clock()` raises a `NameError` if a clock domain does not exist,
  instead of `ValueError`.
- `add_clock()` raises a `DriverConflict` if a clock domain is already
  being driven by a clock, instead of `ValueError`.
- GTKWave is no longer a part of the installation instructions, and both
  Surfer and GTKWave are recommended (in this order).
  • Loading branch information
whitequark committed Jun 10, 2024
1 parent 3c1060f commit 7870eb3
Show file tree
Hide file tree
Showing 16 changed files with 1,179 additions and 222 deletions.
7 changes: 5 additions & 2 deletions amaranth/sim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from .core import *
from .core import Simulator
from ._async import DomainReset, BrokenTrigger, SimulatorContext, TickTrigger, TriggerCombination
from ._pycoro import Settle, Delay, Tick, Passive, Active


__all__ = [
"DomainReset", "BrokenTrigger", "Simulator",
"DomainReset", "BrokenTrigger",
"SimulatorContext", "Simulator", "TickTrigger", "TriggerCombination",
# deprecated
"Settle", "Delay", "Tick", "Passive", "Active",
]
526 changes: 496 additions & 30 deletions amaranth/sim/_async.py

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions amaranth/sim/_pycoro.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Command:

class Settle(Command):
@deprecated("The `Settle` command is deprecated per RFC 27. Use `add_testbench` to write "
"testbenches; in them, an equivalent of `yield Settle()` is performed "
"automatically.")
"testbenches; there, an equivalent of `yield Settle()` is performed "
"automatically after each `ctx.set()`.")
def __init__(self):
pass

Expand All @@ -37,8 +37,7 @@ def __repr__(self):
class Tick(Command):
def __init__(self, domain="sync"):
if not isinstance(domain, (str, ClockDomain)):
raise TypeError("Domain must be a string or a ClockDomain instance, not {!r}"
.format(domain))
raise TypeError(f"Domain must be a string or a ClockDomain instance, not {domain!r}")
assert domain != "comb"
self.domain = domain

Expand Down
396 changes: 276 additions & 120 deletions amaranth/sim/core.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion amaranth/sim/pysim.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ def add_var(path, var_type, var_size, var_init, value):
suffix = f"[{var_size - 1}:0]"
else:
suffix = ""
self.gtkw_signal_names[signal].append(".".join((*var_scope, field_name)) + suffix)
self.gtkw_signal_names[signal].append(
".".join((*var_scope, field_name)) + suffix)
else:
self.vcd_writer.register_alias(
scope=var_scope, name=field_name,
Expand Down
26 changes: 13 additions & 13 deletions docs/_code/up_counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,29 @@ def elaborate(self, platform):


dut = UpCounter(25)
def bench():
async def bench(ctx):
# Disabled counter should not overflow.
yield dut.en.eq(0)
ctx.set(dut.en, 0)
for _ in range(30):
yield
assert not (yield dut.ovf)
await ctx.tick()
assert not ctx.get(dut.ovf)

# Once enabled, the counter should overflow in 25 cycles.
yield dut.en.eq(1)
for _ in range(25):
yield
assert not (yield dut.ovf)
yield
assert (yield dut.ovf)
ctx.set(dut.en, 1)
for _ in range(24):
await ctx.tick()
assert not ctx.get(dut.ovf)
await ctx.tick()
assert ctx.get(dut.ovf)

# The overflow should clear in one cycle.
yield
assert not (yield dut.ovf)
await ctx.tick()
assert not ctx.get(dut.ovf)


sim = Simulator(dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(bench)
sim.add_testbench(bench)
with sim.write_vcd("up_counter.vcd"):
sim.run()
# --- CONVERT ---
Expand Down
Binary file removed docs/_images/up_counter_gtkwave.png
Binary file not shown.
59 changes: 34 additions & 25 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,23 @@ Migrating from version 0.4

Apply the following changes to code written against Amaranth 0.4 to migrate it to version 0.5:

* Replace uses of ``m.Case()`` with no patterns with ``m.Default()``
* Replace uses of ``Value.matches()`` with no patterns with ``Const(1)``
* Update uses of ``amaranth.utils.log2_int(need_pow2=False)`` to :func:`amaranth.utils.ceil_log2`
* Update uses of ``amaranth.utils.log2_int(need_pow2=True)`` to :func:`amaranth.utils.exact_log2`
* Update uses of ``reset=`` keyword argument to ``init=``
* Convert uses of ``Simulator.add_sync_process`` used as testbenches to ``Simulator.add_testbench``
* Convert other uses of ``Simulator.add_sync_process`` to ``Simulator.add_process``
* Replace uses of ``amaranth.hdl.Memory`` with ``amaranth.lib.memory.Memory``
* Replace imports of ``amaranth.asserts.{Assert, Assume, Cover}`` with imports from ``amaranth.hdl``
* Remove any usage of ``name=`` with assertions, possibly replacing them with custom messages
* Ensure all elaboratables are subclasses of :class:`Elaboratable`
* Replace uses of :py:`m.Case()` with no patterns with :py:`m.Default()`.
* Replace uses of :py:`Value.matches()` with no patterns with :py:`Const(1)`.
* Update uses of :py:`amaranth.utils.log2_int(need_pow2=False)` to :func:`amaranth.utils.ceil_log2`.
* Update uses of :py:`amaranth.utils.log2_int(need_pow2=True)` to :func:`amaranth.utils.exact_log2`.
* Update uses of :py:`reset=` keyword argument to :py:`init=`.
* Convert uses of :py:`Simulator.add_sync_process` used as testbenches to :meth:`Simulator.add_testbench <amaranth.sim.Simulator.add_testbench>`.
* Convert other uses of :py:`Simulator.add_sync_process` to :meth:`Simulator.add_process <amaranth.sim.Simulator.add_process>`.
* Convert simulator processes and testbenches to use the new async API.
* Replace uses of :py:`amaranth.hdl.Memory` with :class:`amaranth.lib.memory.Memory`.
* Replace imports of :py:`amaranth.asserts.Assert`, :py:`Assume`, and :py:`Cover` with imports from :py:`amaranth.hdl`.
* Remove uses of :py:`name=` keyword argument of :py:`Assert`, :py:`Assume`, and :py:`Cover`; a message can be used instead.
* Ensure all elaboratables are subclasses of :class:`Elaboratable`.
* Ensure clock domains aren't used outside the module that defines them, or its submodules; move clock domain definitions upwards in the hierarchy as necessary
* Remove uses of ``amaranth.lib.coding.*`` by inlining or copying the implementation of the modules
* Update uses of ``platform.request`` to pass ``dir="-"`` and use :mod:`amaranth.lib.io` buffers
* Remove uses of :py:`amaranth.lib.coding.*` by inlining or copying the implementation of the modules.
* Update uses of :py:`platform.request` to pass :py:`dir="-"` and use :mod:`amaranth.lib.io` buffers.
* Update uses of :meth:`Simulator.add_clock <amaranth.sim.Simulator.add_clock>` with explicit :py:`phase` to take into account simulator no longer adding implicit :py:`period / 2`. (Previously, :meth:`Simulator.add_clock <amaranth.sim.Simulator.add_clock>` was documented to first toggle the clock at the time :py:`phase`, but actually first toggled the clock at :py:`period / 2 + phase`.)
* Update uses of :meth:`Simulator.run_until <amaranth.sim.Simulator.run_until>` to remove the :py:`run_passive=True` argument. If the code uses :py:`run_passive=False`, ensure it still works with the new behavior.


Implemented RFCs
Expand All @@ -51,6 +54,7 @@ Implemented RFCs
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
.. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.html
.. _RFC 30: https://amaranth-lang.org/rfcs/0030-component-metadata.html
.. _RFC 36: https://amaranth-lang.org/rfcs/0036-async-testbench-functions.html
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.html
.. _RFC 43: https://amaranth-lang.org/rfcs/0043-rename-reset-to-init.html
.. _RFC 45: https://amaranth-lang.org/rfcs/0045-lib-memory.html
Expand All @@ -68,6 +72,7 @@ Implemented RFCs
* `RFC 17`_: Remove ``log2_int``
* `RFC 27`_: Testbench processes for the simulator
* `RFC 30`_: Component metadata
* `RFC 36`_: Async testbench functions
* `RFC 39`_: Change semantics of no-argument ``m.Case()``
* `RFC 43`_: Rename ``reset=`` to ``init=``
* `RFC 45`_: Move ``hdl.Memory`` to ``lib.Memory``
Expand All @@ -94,12 +99,12 @@ Language changes
* Added: :meth:`ShapeCastable.from_bits` method. (`RFC 51`_)
* Added: IO values, :class:`IOPort` objects, :class:`IOBufferInstance` objects. (`RFC 53`_)
* Added: :class:`MemoryData` objects. (`RFC 62`_)
* Changed: ``m.Case()`` with no patterns is never active instead of always active. (`RFC 39`_)
* Changed: ``Value.matches()`` with no patterns is ``Const(0)`` instead of ``Const(1)``. (`RFC 39`_)
* Changed: ``Signal(range(stop), init=stop)`` warning has been changed into a hard error and made to trigger on any out-of range value.
* Changed: ``Signal(range(0))`` is now valid without a warning.
* Changed: ``Shape.cast(range(1))`` is now ``unsigned(0)``. (`RFC 46`_)
* Changed: the ``reset=`` argument of :class:`Signal`, :meth:`Signal.like`, :class:`amaranth.lib.wiring.Member`, :class:`amaranth.lib.cdc.FFSynchronizer`, and ``m.FSM()`` has been renamed to ``init=``. (`RFC 43`_)
* Changed: :py:`m.Case()` with no patterns is never active instead of always active. (`RFC 39`_)
* Changed: :py:`Value.matches()` with no patterns is :py:`Const(0)` instead of :py:`Const(1)`. (`RFC 39`_)
* Changed: :py:`Signal(range(stop), init=stop)` warning has been changed into a hard error and made to trigger on any out-of range value.
* Changed: :py:`Signal(range(0))` is now valid without a warning.
* Changed: :py:`Shape.cast(range(1))` is now :py:`unsigned(0)`. (`RFC 46`_)
* Changed: the :py:`reset=` argument of :class:`Signal`, :meth:`Signal.like`, :class:`amaranth.lib.wiring.Member`, :class:`amaranth.lib.cdc.FFSynchronizer`, and :py:`m.FSM()` has been renamed to :py:`init=`. (`RFC 43`_)
* Changed: :class:`Shape` has been made immutable and hashable.
* Changed: :class:`Assert`, :class:`Assume`, :class:`Cover` have been moved to :mod:`amaranth.hdl` from :mod:`amaranth.asserts`. (`RFC 50`_)
* Changed: :class:`Instance` IO ports now accept only IO values, not plain values. (`RFC 53`_)
Expand Down Expand Up @@ -127,17 +132,21 @@ Standard library changes
* Added: :mod:`amaranth.lib.meta`, :class:`amaranth.lib.wiring.ComponentMetadata`. (`RFC 30`_)
* Deprecated: :mod:`amaranth.lib.coding`. (`RFC 63`_)
* Removed: (deprecated in 0.4) :mod:`amaranth.lib.scheduler`. (`RFC 19`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.FIFOInterface` with ``fwft=False``. (`RFC 20`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.SyncFIFO` with ``fwft=False``. (`RFC 20`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.FIFOInterface` with :py:`fwft=False`. (`RFC 20`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.SyncFIFO` with :py:`fwft=False`. (`RFC 20`_)


Toolchain changes
-----------------

* Added: ``Simulator.add_testbench``. (`RFC 27`_)
* Added: :meth:`Simulator.add_testbench <amaranth.sim.Simulator.add_testbench>`. (`RFC 27`_)
* Added: async function support in :meth:`Simulator.add_testbench <amaranth.sim.Simulator.add_testbench>` and :meth:`Simulator.add_process <amaranth.sim.Simulator.add_process>`. (`RFC 36`_)
* Added: support for :class:`amaranth.hdl.Assert` in simulation. (`RFC 50`_)
* Deprecated: ``Settle`` simulation command. (`RFC 27`_)
* Deprecated: ``Simulator.add_sync_process``. (`RFC 27`_)
* Changed: :meth:`Simulator.add_clock <amaranth.sim.Simulator.add_clock>` no longer implicitly adds :py:`period / 2` when :py:`phase` is specified, actually matching the documentation.
* Changed: :meth:`Simulator.run_until <amaranth.sim.Simulator.run_until>` always runs the simulation until the given deadline, even when no critical processes or testbenches are present.
* Deprecated: :py:`Settle` simulation command. (`RFC 27`_)
* Deprecated: :py:`Simulator.add_sync_process`. (`RFC 27`_)
* Deprecated: the :py:`run_passive` argument to :meth:`Simulator.run_until <amaranth.sim.Simulator.run_until>` has been deprecated, and does nothing.
* Removed: (deprecated in 0.4) use of mixed-case toolchain environment variable names, such as ``NMIGEN_ENV_Diamond`` or ``AMARANTH_ENV_Diamond``; use upper-case environment variable names, such as ``AMARANTH_ENV_DIAMOND``.


Expand All @@ -150,7 +159,7 @@ Platform integration changes
* Added: :meth:`BuildPlan.extract`.
* Added: ``build.sh`` begins with ``#!/bin/sh``.
* Changed: ``IntelPlatform`` renamed to ``AlteraPlatform``.
* Deprecated: argument ``run_script=`` in :meth:`BuildPlan.execute_local`.
* Deprecated: argument :py:`run_script=` in :meth:`BuildPlan.execute_local`.
* Removed: (deprecated in 0.4) :mod:`vendor.intel`, :mod:`vendor.lattice_ecp5`, :mod:`vendor.lattice_ice40`, :mod:`vendor.lattice_machxo2_3l`, :mod:`vendor.quicklogic`, :mod:`vendor.xilinx`. (`RFC 18`_)


Expand Down
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
autodoc_preserve_defaults = True
autodoc_inherit_docstrings = False

# Amaranth mostly does not include typehints, and showing them in some places but not others is
# worse than not showing them at all.
autodoc_typehints = "none"

napoleon_google_docstring = False
napoleon_numpy_docstring = True
napoleon_use_ivar = True
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Language & toolchain
guide
reference
stdlib
simulator
platform
changes
contrib
21 changes: 9 additions & 12 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Amaranth HDL requires Python 3.8; it works on CPython_ 3.8 (or newer), and works

For most workflows, Amaranth requires Yosys_ |yosys-version|. A `compatible version of Yosys <amaranth-yosys_>`_ is distributed via PyPI_ for most popular platforms, so it is usually not necessary to install Yosys separately.

Simulating Amaranth code requires no additional software. However, a waveform viewer like GTKWave_ is invaluable for debugging. As an alternative to GTKWave, the `Amaranth Playground`_ can be used to display waveforms for simple designs.
Simulating Amaranth code requires no additional software. However, a waveform viewer like Surfer_ or GTKWave_ is invaluable for debugging. As an alternative, the `Amaranth Playground`_ can be used to display waveforms for simple designs.

Synthesizing, placing and routing an Amaranth design for an FPGA requires the FPGA family specific toolchain. The open source iCE40, ECP5, MachXO2/3, Nexus, and Gowin toolchains are distributed via PyPI_ for most popular platforms by the YoWASP_ project.

Expand All @@ -39,6 +39,7 @@ Synthesizing, placing and routing an Amaranth design for an FPGA requires the FP
.. _Yosys: https://yosyshq.net/yosys/
.. _amaranth-yosys: https://pypi.org/project/amaranth-yosys/
.. _PyPI: https://pypi.org/
.. _Surfer: https://surfer-project.org/
.. _GTKWave: https://gtkwave.sourceforge.net/
.. _YoWASP: https://yowasp.org/

Expand All @@ -58,10 +59,6 @@ Installing prerequisites

:ref:`Install Python <python:using-on-windows>`, either from Windows Store or using the full installer. If using the full installer, make sure to install a 64-bit version of Python.

`Download GTKWave`_, either win32 or win64 binaries. GTKWave does not need to be installed; it can be unpacked to any convenient location and run from there.

.. _Download GTKWave: https://sourceforge.net/projects/gtkwave/files/

|upgrade-pip|

.. code-block:: doscon
Expand All @@ -71,11 +68,11 @@ Installing prerequisites
.. platform-choice:: macos
:title: macOS

Install Homebrew_. Then, install Python and GTKWave by running:
Install Homebrew_. Then, install Python by running:

.. code-block:: console
$ brew install python gtkwave
$ brew install python
.. _Homebrew: https://brew.sh

Expand All @@ -89,11 +86,11 @@ Installing prerequisites
:altname: linux
:title: Debian

Install Python and GTKWave by running:
Install Python by running:

.. code-block:: console
$ sudo apt-get install python3-pip gtkwave
$ sudo apt-get install python3-pip
On architectures other than |builtin-yosys-architectures|, install Yosys by running:

Expand All @@ -113,16 +110,16 @@ Installing prerequisites
:altname: linux
:title: Arch Linux

Install Python, pip, GTKWave and Yosys by running:
Install Python and pip by running:

.. code-block:: console
$ sudo pacman -S python python-pip gtkwave yosys
$ sudo pacman -S python python-pip
.. platform-choice:: linux
:title: Other Linux

Install Python and GTKWave from the package repository of your distribution.
Install Python from the package repository of your distribution.

On architectures other than |builtin-yosys-architectures|, install Yosys from the package repository of your distribution.

Expand Down
Loading

0 comments on commit 7870eb3

Please sign in to comment.