Update doc with new simulation API

This commit is contained in:
Sebastien Bourdeauducq 2014-02-07 23:08:59 +01:00
parent 2ab939e69d
commit d26330a9b9
5 changed files with 70 additions and 27 deletions

8
README
View File

@ -1,4 +1,4 @@
Migen (Milkymist Generator) Migen (Milkymist generator)
a Python toolbox for building complex digital hardware a Python toolbox for building complex digital hardware
Despite being faster than schematics entry, hardware design with Verilog and Despite being faster than schematics entry, hardware design with Verilog and
@ -53,7 +53,7 @@ Even though we do not require you to do so, those things are awesome, so please
do them if possible: do them if possible:
* tell us that you are using Migen * tell us that you are using Migen
* put the Migen logo (doc/migen_logo.svg) on the page of a product using it, * put the Migen logo (doc/migen_logo.svg) on the page of a product using it,
with a link to milkymist.org with a link to m-labs.hk
* cite Migen in publications related to research it has helped * cite Migen in publications related to research it has helped
* send us feedback and suggestions for improvements * send us feedback and suggestions for improvements
* send us bug reports when something goes wrong * send us bug reports when something goes wrong
@ -62,7 +62,9 @@ do them if possible:
complex and/or you are not sure how to proceed, feel free to discuss it on complex and/or you are not sure how to proceed, feel free to discuss it on
the mailing list or IRC (#m-labs on Freenode) beforehand. the mailing list or IRC (#m-labs on Freenode) beforehand.
Note that Migen is not spelled MiGen.
See LICENSE file for full copyright and license info. You can contact us on the See LICENSE file for full copyright and license info. You can contact us on the
public mailing list devel [AT] lists.milkymist.org. public mailing list devel [AT] lists.m-labs.hk.
"Electricity! It's like magic!" "Electricity! It's like magic!"

View File

@ -341,7 +341,7 @@ The clock domain management mechanism explained above happens during finalizatio
Simulation Simulation
========== ==========
The ``do_simulation`` method of the ``Module`` class can be overloaded and will be executed at each clock cycle. See :ref:`simulating` for more information on using the simulator. The ``do_simulation`` method of the ``Module`` class can be defined and will be executed at each clock cycle, or the generator-style API can be used by defining ``gen_simulation`` instead. The generator yields the number of cycles it wants to wait for. See :ref:`simulating` for more information on using the simulator.
Simulation of designs with several clock domains is not supported yet. Simulation of designs with several clock domains is not supported yet.
@ -350,6 +350,4 @@ Conversion for synthesis
Any FHDL module (except, of course, its simulation functions) can be converted into synthesizable Verilog HDL. This is accomplished by using the ``convert`` function in the ``verilog`` module. Any FHDL module (except, of course, its simulation functions) can be converted into synthesizable Verilog HDL. This is accomplished by using the ``convert`` function in the ``verilog`` module.
Migen does not provide support for any specific synthesis tools or ASIC/FPGA technologies. Users must run themselves the generated code through the appropriate tool flow for hardware implementation. The Mibuild component provides scripts to interface third-party FPGA tools to Migen and a database of boards for the easy deployment of designs.
The Mibuild package, available separately from the Migen website, provides scripts to interface third-party FPGA tools to Migen and a database of boards for the easy deployment of designs.

View File

@ -12,7 +12,7 @@ Background
Even though the Milkymist system-on-chip [mm]_ is technically successful, it suffers from several limitations stemming from its implementation in manually written Verilog HDL: Even though the Milkymist system-on-chip [mm]_ is technically successful, it suffers from several limitations stemming from its implementation in manually written Verilog HDL:
.. [mm] http://www.milkymist.org .. [mm] http://m-labs.hk
#. The "event-driven" paradigm of today's dominant hardware descriptions languages (Verilog and VHDL, collectively referred to as "V*HDL" in the rest of this document) is often too general. Today's FPGA architectures are optimized for the implementation of fully synchronous circuits. This means that the bulk of the code for an efficient FPGA design falls into three categories: #. The "event-driven" paradigm of today's dominant hardware descriptions languages (Verilog and VHDL, collectively referred to as "V*HDL" in the rest of this document) is often too general. Today's FPGA architectures are optimized for the implementation of fully synchronous circuits. This means that the bulk of the code for an efficient FPGA design falls into three categories:
@ -40,7 +40,7 @@ Even though the Milkymist system-on-chip [mm]_ is technically successful, it suf
#. Many hardware acceleration problems can fit into the dataflow programming model. Manual dataflow implementation in V*HDL has, again, a lot of redundancy and potential for human errors. See the Milkymist texture mapping unit [mthesis]_ [mxcell]_ for an example of this. The amount of detail to deal with manually also makes the design space exploration difficult, and therefore hinders the design of efficient architectures. #. Many hardware acceleration problems can fit into the dataflow programming model. Manual dataflow implementation in V*HDL has, again, a lot of redundancy and potential for human errors. See the Milkymist texture mapping unit [mthesis]_ [mxcell]_ for an example of this. The amount of detail to deal with manually also makes the design space exploration difficult, and therefore hinders the design of efficient architectures.
#. Pre-computation of values, such as filter coefficients for DSP or even simply trigonometric tables, must often be done using external tools whose results are copy-and-pasted (in the best cases, automatically) into the V*HDL source. #. Pre-computation of values, such as filter coefficients for DSP or even simply trigonometric tables, must often be done using external tools whose results are copy-and-pasted (in the best cases, automatically) into the V*HDL source.
.. [mthesis] http://milkymist.org/thesis/thesis.pdf .. [mthesis] http://m-labs.hk/thesis/thesis.pdf
.. [mxcell] http://www.xilinx.com/publications/archives/xcell/Xcell77.pdf p30-35 .. [mxcell] http://www.xilinx.com/publications/archives/xcell/Xcell77.pdf p30-35
Enter Migen, a Python toolbox for building complex digital hardware. We could have designed a brand new programming language, but that would have been reinventing the wheel instead of being able to benefit from Python's rich features and immense library. The price to pay is a slightly cluttered syntax at times when writing descriptions in FHDL, but we believe this is totally acceptable, particularly when compared to VHDL ;-) Enter Migen, a Python toolbox for building complex digital hardware. We could have designed a brand new programming language, but that would have been reinventing the wheel instead of being able to benefit from Python's rich features and immense library. The price to pay is a slightly cluttered syntax at times when writing descriptions in FHDL, but we believe this is totally acceptable, particularly when compared to VHDL ;-)
@ -55,4 +55,4 @@ For simulation support, an extra step is needed. See :ref:`vpisetup`.
Feedback Feedback
******** ********
Feedback concerning Migen or this manual should be sent to the Milkymist developers' mailing list at devel@lists.milkymist.org. Feedback concerning Migen or this manual should be sent to the M-Labs developers' mailing list at devel@lists.m-labs.hk.

View File

@ -2,6 +2,7 @@
Simulating a Migen design Simulating a Migen design
######################### #########################
Migen allows you to easily simulate your FHDL design and interface it with arbitrary Python code. Migen allows you to easily simulate your FHDL design and interface it with arbitrary Python code.
To interpret the design, the FHDL structure is simply converted into Verilog and then simulated using an external program (e.g. Icarus Verilog). This is is intrinsically compatible with VHDL/Verilog instantiations from Migen and maximizes software reuse. To interpret the design, the FHDL structure is simply converted into Verilog and then simulated using an external program (e.g. Icarus Verilog). This is is intrinsically compatible with VHDL/Verilog instantiations from Migen and maximizes software reuse.
@ -14,6 +15,7 @@ Signals inside the simulator can be read and written using VPI as well. This is
Installing the VPI module Installing the VPI module
************************* *************************
To communicate with the external simulator, Migen uses a UNIX domain socket and a custom protocol which is handled by a VPI plug-in (written in C) on the simulator side. To communicate with the external simulator, Migen uses a UNIX domain socket and a custom protocol which is handled by a VPI plug-in (written in C) on the simulator side.
To build and install this plug-in, run the following commands from the ``vpi`` directory: :: To build and install this plug-in, run the following commands from the ``vpi`` directory: ::
@ -29,49 +31,85 @@ This plug-in is designed for Icarus Verilog, but can probably be used with most
The generic simulator object The generic simulator object
**************************** ****************************
The generic simulator object (``migen.sim.generic.Simulator``) is the central component of the simulation. The generic simulator object (``migen.sim.generic.Simulator``) is the central component of the simulation.
Creating a simulator object Creating a simulator object
=========================== ===========================
The constructor of the ``Simulator`` object takes the following parameters: The constructor of the ``Simulator`` object takes the following parameters:
#. The fragment to simulate. The fragment can (and generally does) contain both synthesizable code and a non-synthesizable list of simulation functions. #. The module to simulate.
#. A top-level object (see :ref:`toplevel`). With the default value of ``None``, the simulator creates a default top-level object itself. #. A top-level object (see :ref:`toplevel`). With the default value of ``None``, the simulator creates a default top-level object itself.
#. A simulator runner object (see :ref:`simrunner`). With the default value of ``None``, Icarus Verilog is used with the default parameters. #. A simulator runner object (see :ref:`simrunner`). With the default value of ``None``, Icarus Verilog is used with the default parameters.
#. The name of the UNIX domain socket used to communicate with the external simulator through the VPI plug-in (default: "simsocket"). #. The name of the UNIX domain socket used to communicate with the external simulator through the VPI plug-in (default: "simsocket").
#. Additional keyword arguments (if any) are passed to the Verilog conversion function. #. Additional keyword arguments (if any) are passed to the Verilog conversion function.
For proper initialization and clean-up, the simulator object should be used as a context manager, e.g. ::
with Simulator(tb) as s:
s.run()
Running the simulation Running the simulation
====================== ======================
Running the simulation is achieved by calling the ``run`` method of the ``Simulator`` object. Running the simulation is achieved by calling the ``run`` method of the ``Simulator`` object.
It takes an optional parameter that defines the maximum number of clock cycles that this call simulates. The default value of -1 sets no cycle limit. It takes an optional parameter that defines the maximum number of clock cycles that this call simulates. The default value of ``None`` sets no cycle limit.
The simulation runs until the maximum number of cycles is reached, or a simulation function sets the property ``interrupt`` to ``True`` in the ``Simulator`` object. The cycle counter
=================
At each clock cycle, the ``Simulator`` object runs in turn all simulation functions listed in the fragment. Simulation functions must take exactly one parameter which is used by the instance of the ``Simulator`` object to pass a reference to itself.
Simulation functions can read the current simulator cycle by reading the ``cycle_counter`` property of the ``Simulator``. The cycle counter's value is 0 for the cycle immediately following the reset cycle. Simulation functions can read the current simulator cycle by reading the ``cycle_counter`` property of the ``Simulator``. The cycle counter's value is 0 for the cycle immediately following the reset cycle.
Reading and writing signals Simplified simulation set-up
============================
Most simulations are run in the same way and do not need the slightly heavy syntax needed to create and run a Simulator object. There is a function that exposes the most common features with a simpler syntax: ::
run_simulation(module, ncycles=None, vcd_name=None, keep_files=False)
Module-level simulation API
***************************
Simulation functions and generators
===================================
Whenever a ``Module`` declares a ``do_simulation`` method, it is executed at each cycle and can manipulate values from signal and memories (as explained in the next section).
Instead of defining such a method, ``Modules`` can declare a ``gen_simulation`` generator that is initialized at the beginning of the simulation, and yields (usually multiple times) to proceed to the next simulation cycle.
Simulation generators can yield an integer in order to wait for that number of cycles, or yield nothing (``None``) to wait for 1 cycle.
Reading and writing values
=========================== ===========================
Reading and writing signals is done by calling the ``Simulator`` object's methods ``rd`` and ``wr`` (respectively) from simulation functions.
Simulation functions and generators take as parameter a special object that gives access to the values of the signals of the current module using the regular Python read/write syntax. Nested objects, lists and dictionaries containing signals are supported, as well as Migen memories, for reading and writing.
Here are some examples: ::
def do_simulation(self, selfp):
selfp.foo = 42
self.last_foo_value = selfp.foo
selfp.dut.banks[2].bar["foo"] = 1
self.last_memory_data = selfp.dut.mem[self.memory_index]
The semantics of reads and writes (respectively immediately before and after the clock edge) match those of the non-blocking assignment in Verilog. Note that because of Verilog's design, reading "variable" signals (i.e. written to using blocking assignment) directly may give unexpected and non-deterministic results and is not supported. You should instead read the values of variables after they have gone through a non-blocking assignment in the same ``always`` block.
Those constructs are syntactic sugar for calling the ``Simulator`` object's methods ``rd`` and ``wr``, that respectively read and write data from and to the simulated design. The simulator object can be accessed as ``selfp.simulator``, and for special cases it is sometimes desirable to call the lower-level methods directly.
The ``rd`` method takes the FHDL ``Signal`` object to read and returns its value as a Python integer. The returned integer is the value of the signal immediately before the clock edge. The ``rd`` method takes the FHDL ``Signal`` object to read and returns its value as a Python integer. The returned integer is the value of the signal immediately before the clock edge.
The ``wr`` method takes a ``Signal`` object and the value to write as a Python integer. The signal takes the new value immediately after the clock edge. The ``wr`` method takes a ``Signal`` object and the value to write as a Python integer. The signal takes the new value immediately after the clock edge.
The semantics of reads and writes (respectively immediately before and after the clock edge) match those of the non-blocking assignment in Verilog. Note that because of Verilog's design, reading "variable" signals (i.e. written to using blocking assignment) directly may give unexpected and non-deterministic results and is not supported. You should instead read the values of variables after they have gone through a non-blocking assignment in the same ``always`` block.
Reading and writing memories
============================
References to FHDL ``Memory`` objects can also be passed to the ``rd`` and ``wr`` methods. In this case, they take an additional parameter for the memory address. References to FHDL ``Memory`` objects can also be passed to the ``rd`` and ``wr`` methods. In this case, they take an additional parameter for the memory address.
Initializing signals and memories Simulation termination management
================================= =================================
A simulation function can access (and typically initialize) signals and memories during the reset cycle if it has its property ``initialize`` set to ``True``.
In this case, it will be run once at the beginning of the simulation with a cycle counter value of -1 indicating the reset cycle. Simulation functions and generators can raise the ``StopSimulation`` exception. It is automatically raised when a simulation generator is exhausted. This exception disables the current simulation function, i.e. it is no longer run by the simulator. The simulation is over when all simulation functions are disabled (or the specified maximum number of cycles, if any, has been reached - whichever comes first).
Some simulation modules only respond to external stimuli - e.g. the ``bus.wishbone.Tap`` that snoops on bus transactions and prints them on the console - and have simulation functions that never end. To deal with those, the new API introduces "passive" simulation functions that are not taken into account when deciding to continue to run the simulation. A simulation function is declared passive by setting a "passive" attribute on it that evaluates to True. Raising ``StopSimulation`` in such a function still makes the simulator stop running it for the rest of the simulation.
.. _simrunner: .. _simrunner:
@ -80,12 +118,14 @@ The external simulator runner
Role Role
==== ====
The runner object is responsible for starting the external simulator, loading the VPI module, and feeding the generated Verilog into the simulator. The runner object is responsible for starting the external simulator, loading the VPI module, and feeding the generated Verilog into the simulator.
It must implement a ``start`` method, called by the ``Simulator``, which takes two strings as parameters. They contain respectively the Verilog source of the top-level design and the converted fragment. It must implement a ``start`` method, called by the ``Simulator``, which takes two strings as parameters. They contain respectively the Verilog source of the top-level design and the converted module.
Icarus Verilog support Icarus Verilog support
====================== ======================
Migen comes with a ``migen.sim.icarus.Runner`` object that supports Icarus Verilog. Migen comes with a ``migen.sim.icarus.Runner`` object that supports Icarus Verilog.
Its constructor has the following optional parameters: Its constructor has the following optional parameters:
@ -103,6 +143,7 @@ The top-level object
Role of the top-level object Role of the top-level object
============================ ============================
The top-level object is responsible for generating the Verilog source for the top-level test bench. The top-level object is responsible for generating the Verilog source for the top-level test bench.
It must implement a method ``get`` that takes as parameter the name of the UNIX socket the VPI plugin should connect to, and returns the full Verilog source as a string. It must implement a method ``get`` that takes as parameter the name of the UNIX socket the VPI plugin should connect to, and returns the full Verilog source as a string.
@ -117,6 +158,7 @@ It must have the following attributes (which are read by the ``Simulator`` objec
Role of the generated Verilog Role of the generated Verilog
============================= =============================
The generated Verilog must: The generated Verilog must:
#. instantiate the converted fragment and connect its clock and reset ports. #. instantiate the converted fragment and connect its clock and reset ports.
@ -128,6 +170,7 @@ The generated Verilog must:
The generic top-level object The generic top-level object
============================ ============================
Migen comes with a ``migen.sim.generic.TopLevel`` object that implements the above behaviour. It should be usable in the majority of cases. Migen comes with a ``migen.sim.generic.TopLevel`` object that implements the above behaviour. It should be usable in the majority of cases.
The main parameters of its constructor are the output VCD file (default: ``None``) and the levels of hierarchy that must be present in the VCD (default: 1). The main parameters of its constructor are the output VCD file (default: ``None``) and the levels of hierarchy that must be present in the VCD (default: 1).

View File

@ -18,8 +18,8 @@ setup(
description="Python toolbox for building complex digital hardware", description="Python toolbox for building complex digital hardware",
long_description=README, long_description=README,
author="Sebastien Bourdeauducq", author="Sebastien Bourdeauducq",
author_email="sebastien@milkymist.org", author_email="sb@m-labs.hk",
url="http://www.milkymist.org", url="http://m-labs.hk",
download_url="https://github.com/m-labs/migen", download_url="https://github.com/m-labs/migen",
packages=find_packages(here), packages=find_packages(here),
test_suite="migen.test", test_suite="migen.test",