fhdl.rst 25.3 KB
Newer Older
1 2
The FHDL domain-specific language
#################################
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
3

4
The Fragmented Hardware Description Language (FHDL) is the basis of Migen. It consists of a formal system to describe signals, and combinatorial and synchronous statements operating on them. The formal system itself is low level and close to the synthesizable subset of Verilog, and we then rely on Python algorithms to build complex structures by combining FHDL elements.
5
The FHDL module also contains a back-end to produce synthesizable Verilog, and some structure analysis and manipulation functionality.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
6 7 8 9 10

FHDL differs from MyHDL [myhdl]_ in fundamental ways. MyHDL follows the event-driven paradigm of traditional HDLs (see :ref:`background`) while FHDL separates the code into combinatorial statements, synchronous statements, and reset values. In MyHDL, the logic is described directly in the Python AST. The converter to Verilog or VHDL then examines the Python AST and recognizes a subset of Python that it translates into V*HDL statements. This seriously impedes the capability of MyHDL to generate logic procedurally. With FHDL, you manipulate a custom AST from Python, and you can more easily design algorithms that operate on it.

.. [myhdl] http://www.myhdl.org

11
FHDL is made of several elements, which are briefly explained below. They all can be imported directly from the ``migen`` module.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
12 13 14 15

Expressions
***********

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
16 17
Constants
=========
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
18

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
19 20 21
The ``Constant`` object represents a constant, HDL-literal integer. It behaves like specifying integers and booleans but also supports slicing and can have a bit width or signedness different from what is implied by the value it represents.

``True`` and ``False`` are interpreted as 1 and 0, respectively.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
22

23
Negative integers are explicitly supported. As with MyHDL [countin]_, arithmetic operations return the natural results.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
24

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
25 26
To lighten the syntax, assignments and operators automatically wrap Python integers and booleans into ``Constant``. Additionally, ``Constant`` is aliased to ``C``. The following are valid Migen statements: ``a.eq(0)``, ``a.eq(a + 1)``, ``a.eq(C(42)[0:1])``.

27
.. [countin] http://www.jandecaluwe.com/hdldesign/counting.html
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
28 29 30

Signal
======
31

32
The signal object represents a value that is expected to change in the circuit. It does exactly what Verilog's "wire" and "reg" and VHDL's "signal" do.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
33 34 35 36 37

The main point of the signal object is that it is identified by its Python ID (as returned by the :py:func:`id` function), and nothing else. It is the responsibility of the V*HDL back-end to establish an injective mapping between Python IDs and the V*HDL namespace. It should perform name mangling to ensure this. The consequence of this is that signal objects can safely become members of arbitrary Python classes, or be passed as parameters to functions or methods that generate logic involving them.

The properties of a signal object are:

38
* An integer or a (integer, boolean) pair that defines the number of bits and whether the bit of higher index of the signal is a sign bit (i.e. the signal is signed). The defaults are one bit and unsigned. Alternatively, the ``min`` and ``max`` parameters can be specified to define the range of the signal and determine its bit width and signedness. As with Python ranges, ``min`` is inclusive and defaults to 0, ``max`` is exclusive and defaults to 2.
39 40
* A name, used as a hint for the V*HDL back-end name mangler.
* The signal's reset value. It must be an integer, and defaults to 0. When the signal's value is modified with a synchronous statement, the reset value is the initialization value of the associated register. When the signal is assigned to in a conditional combinatorial statement (``If`` or ``Case``), the reset value is the value that the signal has when no condition that causes the signal to be driven is verified. This enforces the absence of latches in designs. If the signal is permanently driven using a combinatorial statement, the reset value has no effect.
whitequark's avatar
whitequark committed
41

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
42 43 44 45 46 47 48 49 50 51 52
The sole purpose of the name property is to make the generated V*HDL code easier to understand and debug. From a purely functional point of view, it is perfectly OK to have several signals with the same name property. The back-end will generate a unique name for each object. If no name property is specified, Migen will analyze the code that created the signal object, and try to extract the variable or member name from there. For example, the following statements will create one or several signals named "bar": ::

  bar = Signal()
  self.bar = Signal()
  self.baz.bar = Signal()
  bar = [Signal() for x in range(42)]

In case of conflicts, Migen tries first to resolve the situation by prefixing the identifiers with names from the class and module hierarchy that created them. If the conflict persists (which can be the case if two signal objects are created with the same name in the same context), it will ultimately add number suffixes.

Operators
=========
53

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
54 55 56 57 58 59 60 61 62 63
Operators are represented by the ``_Operator`` object, which generally should not be used directly. Instead, most FHDL objects overload the usual Python logic and arithmetic operators, which allows a much lighter syntax to be used. For example, the expression: ::

  a * b + c

is equivalent to::

  _Operator("+", [_Operator("*", [a, b]), c])

Slices
======
64

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
65 66 67 68
Likewise, slices are represented by the ``_Slice`` object, which often should not be used in favor of the Python slice operation [x:y]. Implicit indices using the forms [x], [x:] and [:y] are supported. Beware! Slices work like Python slices, not like VHDL or Verilog slices. The first bound is the index of the LSB and is inclusive. The second bound is the index of MSB and is exclusive. In V*HDL, bounds are MSB:LSB and both are inclusive.

Concatenations
==============
69

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
70 71 72 73 74
Concatenations are done using the ``Cat`` object. To make the syntax lighter, its constructor takes a variable number of arguments, which are the signals to be concatenated together (you can use the Python "*" operator to pass a list instead).
To be consistent with slices, the first signal is connected to the bits with the lowest indices in the result. This is the opposite of the way the "{}" construct works in Verilog.

Replications
============
75

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
76
The ``Replicate`` object represents the equivalent of {count{expression}} in Verilog.
77 78 79 80 81 82 83
For example, the expression: ::

  Replicate(0, 4)

is equivalent to::

  Cat(0, 0, 0, 0)
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
84 85 86 87 88 89

Statements
**********

Assignment
==========
90

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
91 92 93 94 95 96 97 98 99 100 101
Assignments are represented with the ``_Assign`` object. Since using it directly would result in a cluttered syntax, the preferred technique for assignments is to use the ``eq()`` method provided by objects that can have a value assigned to them. They are signals, and their combinations with the slice and concatenation operators.
As an example, the statement: ::

  a[0].eq(b)

is equivalent to: ::

  _Assign(_Slice(a, 0, 1), b)

If
==
102

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
The ``If`` object takes a first parameter which must be an expression (combination of the ``Constant``, ``Signal``, ``_Operator``, ``_Slice``, etc. objects) representing the condition, then a variable number of parameters representing the statements (``_Assign``, ``If``, ``Case``, etc. objects) to be executed when the condition is verified.

The ``If`` object defines a ``Else()`` method, which when called defines the statements to be executed when the condition is not true. Those statements are passed as parameters to the variadic method.

For convenience, there is also a ``Elif()`` method.

Example: ::

  If(tx_count16 == 0,
      tx_bitcount.eq(tx_bitcount + 1),
      If(tx_bitcount == 8,
          self.tx.eq(1)
      ).Elif(tx_bitcount == 9,
          self.tx.eq(1),
          tx_busy.eq(0)
      ).Else(
          self.tx.eq(tx_reg[0]),
          tx_reg.eq(Cat(tx_reg[1:], 0))
      )
  )

Case
====
126

127
The ``Case`` object constructor takes as first parameter the expression to be tested, and a dictionary whose keys are the values to be matched, and values the statements to be executed in the case of a match. The special value ``"default"`` can be used as match value, which means the statements should be executed whenever there is no other match.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
128

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
129 130
Arrays
======
131

132
The ``Array`` object represents lists of other objects that can be indexed by FHDL expressions. It is explicitly possible to:
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
133 134

* nest ``Array`` objects to create multidimensional tables.
135
* list any Python object in a ``Array`` as long as every expression appearing in a module ultimately evaluates to a ``Signal`` for all possible values of the indices. This allows the creation of lists of structured data.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
* use expressions involving ``Array`` objects in both directions (assignment and reading).

For example, this creates a 4x4 matrix of 1-bit signals: ::

  my_2d_array = Array(Array(Signal() for a in range(4)) for b in range(4))

You can then read the matrix with (``x`` and ``y`` being 2-bit signals): ::

  out.eq(my_2d_array[x][y])

and write it with: ::

  my_2d_array[x][y].eq(inp)

Since they have no direct equivalent in Verilog, ``Array`` objects are lowered into multiplexers and conditional statements before the actual conversion takes place. Such lowering happens automatically without any user intervention.

152 153
Any out-of-bounds access performed on an ``Array`` object will refer to the last element.

154 155 156 157 158
Specials
********

Tri-state I/O
=============
159

160
A triplet (O, OE, I) of one-way signals defining a tri-state I/O port is represented by the ``TSTriple`` object. Such objects are only containers for signals that are intended to be later connected to a tri-state I/O buffer, and cannot be used as module specials. Such objects, however, should be kept in the design as long as possible as they allow the individual one-way signals to be manipulated in a non-ambiguous way.
161

162
The object that can be used in as a module special is ``Tristate``, and it behaves exactly like an instance of a tri-state I/O buffer that would be defined as follows: ::
163 164

  Instance("Tristate",
165 166 167 168
    io_target=target,
    i_o=o,
    i_oe=oe,
    o_i=i
169 170 171 172 173 174 175
  )

Signals ``target``, ``o`` and ``i`` can have any width, while ``oe`` is 1-bit wide. The ``target`` signal should go to a port and not be used elsewhere in the design. Like modern FPGA architectures, Migen does not support internal tri-states.

A ``Tristate`` object can be created from a ``TSTriple`` object by calling the ``get_tristate`` method.

By default, Migen emits technology-independent behavioral code for a tri-state buffer. If a specific code is needed, the tristate handler can be overriden using the appropriate parameter of the V*HDL conversion function.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
176 177 178

Instances
=========
179

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
180 181
Instance objects represent the parametrized instantiation of a V*HDL module, and the connection of its ports to FHDL signals. They are useful in a number of cases:

182 183
* Reusing legacy or third-party V*HDL code.
* Using special FPGA features (DCM, ICAP, ...).
184 185
* Implementing logic that cannot be expressed with FHDL (e.g. latches).
* Breaking down a Migen system into multiple sub-systems.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
186

187
The instance object constructor takes the type (i.e. name of the instantiated module) of the instance, then multiple parameters describing how to connect and parametrize the instance.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
188

189 190 191 192 193
These parameters can be:

* ``Instance.Input``, ``Instance.Output`` or ``Instance.InOut`` to describe signal connections with the instance. The parameters are the name of the port at the instance, and the FHDL expression it should be connected to.
* ``Instance.Parameter`` sets a parameter (with a name and value) of the instance.
* ``Instance.ClockPort`` and ``Instance.ResetPort`` are used to connect clock and reset signals to the instance. The only mandatory parameter is the name of the port at the instance. Optionally, a clock domain name can be specified, and the ``invert`` option can be used to interface to those modules that require a 180-degree clock or a active-low reset.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
194 195 196

Memories
========
197

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
198 199 200 201
Memories (on-chip SRAM) are supported using a mechanism similar to instances.

A memory object has the following parameters:

202 203 204
* The width, which is the number of bits in each word.
* The depth, which represents the number of words in the memory.
* An optional list of integers used to initialize the memory.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
205

206 207 208
To access the memory in hardware, ports can be obtained by calling the ``get_port`` method. A port always has an address signal ``a`` and a data read signal ``dat_r``. Other signals may be available depending on the port's configuration.

Options to ``get_port`` are:
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
209

210 211 212 213 214
* ``write_capable`` (default: ``False``): if the port can be used to write to the memory. This creates an additional ``we`` signal.
* ``async_read`` (default: ``False``): whether reads are asychronous (combinatorial) or synchronous (registered).
* ``has_re`` (default: ``False``): adds a read clock-enable signal ``re`` (ignored for asychronous ports).
* ``we_granularity`` (default: ``0``): if non-zero, writes of less than a memory word can occur. The width of the ``we`` signal is increased to act as a selection signal for the sub-words.
* ``mode`` (default: ``WRITE_FIRST``, ignored for aynchronous ports).  It can be:
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
215 216 217 218 219

  * ``READ_FIRST``: during a write, the previous value is read.
  * ``WRITE_FIRST``: the written value is returned.
  * ``NO_CHANGE``: the data read signal keeps its previous value on a write.

220 221
* ``clock_domain`` (default: ``"sys"``): the clock domain used for reading and writing from this port.

222
Migen generates behavioural V*HDL code that should be compatible with all simulators and, if the number of ports is <= 2, most FPGA synthesizers. If a specific code is needed, the memory handler can be overriden using the appropriate parameter of the V*HDL conversion function.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
Modules
*******

Modules play the same role as Verilog modules and VHDL entities. Similarly, they are organized in a tree structure. A FHDL module is a Python object that derives from the ``Module`` class. This class defines special attributes to be used by derived classes to describe their logic. They are explained below.

Combinatorial statements
========================

A combinatorial statement is a statement that is executed whenever one of its inputs changes.

Combinatorial statements are added to a module by using the ``comb`` special attribute. Like most module special attributes, it must be accessed using the ``+=`` incrementation operator, and either a single statement, a tuple of statements or a list of statements can appear on the right hand side.

For example, the module below implements a OR gate: ::

  class ORGate(Module):
    def __init__(self):
      self.a = Signal()
      self.b = Signal()
      self.x = Signal()

      ###

whitequark's avatar
whitequark committed
246
      self.comb += self.x.eq(self.a | self.b)
247 248 249 250 251

To improve code readability, it is recommended to place the interface of the module at the beginning of the ``__init__`` function, and separate it from the implementation using three hash signs.

Synchronous statements
======================
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
252

253
A synchronous statements is a statement that is executed at each edge of some clock signal.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
254

255
They are added to a module by using the ``sync`` special attribute, which has the same properties as the ``comb`` attribute.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
256

257
The ``sync`` special attribute also has sub-attributes that correspond to abstract clock domains. For example, to add a statement to the clock domain named ``foo``, one would write ``self.sync.foo += statement``. The default clock domain is ``sys`` and writing ``self.sync += statement`` is equivalent to writing ``self.sync.sys += statement``.
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
258

259 260
Submodules and specials
=======================
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
Submodules and specials can be added by using the ``submodules`` and ``specials`` attributes respectively. This can be done in two ways:

#. anonymously, by using the ``+=`` operator on the special attribute directly, e.g. ``self.submodules += some_other_module``. Like with the ``comb`` and ``sync`` attributes, a single module/special or a tuple or list can be specified.
#. by naming the submodule/special using a subattribute of the ``submodules`` or ``specials`` attribute, e.g. ``self.submodules.foo = module_foo``. The submodule/special is then accessible as an attribute of the object, e.g. ``self.foo`` (and not ``self.submodules.foo``). Only one submodule/special can be added at a time using this form.

Clock domains
=============

Specifying the implementation of a clock domain is done using the ``ClockDomain`` object. It contains the name of the clock domain, a clock signal that can be driven like any other signal in the design (for example, using a PLL instance), and optionally a reset signal. Clock domains without a reset signal are reset using e.g. ``initial`` statements in Verilog, which in many FPGA families initalize the registers during configuration.

The name can be omitted if it can be extracted from the variable name. When using this automatic naming feature, prefixes ``_``, ``cd_`` and ``_cd_`` are removed.

Clock domains are then added to a module using the ``clock_domains`` special attribute, which behaves exactly like ``submodules`` and ``specials``.

Summary of special attributes
=============================

279
.. table::
280

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
   +--------------------------------------------+--------------------------------------------------------------+
   | Syntax                                     | Action                                                       |
   +============================================+==============================================================+
   | self.comb += stmt                          | Add combinatorial statement to current module.               |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.comb += stmtA, stmtB                  | Add combinatorial statements A and B to current module.      |
   |                                            |                                                              |
   | self.comb += [stmtA, stmtB]                |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.sync += stmt                          | Add synchronous statement to current module, in default      |
   |                                            | clock domain sys.                                            |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.sync.foo += stmt                      | Add synchronous statement to current module, in clock domain |
   |                                            | foo.                                                         |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.sync.foo += stmtA, stmtB              | Add synchronous statements A and B to current module, in     |
   |                                            | clock domain foo.                                            |
   | self.sync.foo += [stmtA, stmtB]            |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.submodules += mod                     | Add anonymous submodule to current module.                   |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.submodules += modA, modB              | Add anonymous submodules A and B to current module.          |
   |                                            |                                                              |
   | self.submodules += [modA, modB]            |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.submodules.bar = mod                  | Add submodule named bar to current module. The submodule can |
   |                                            | then be accessed using self.bar.                             |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.specials += spe                       | Add anonymous special to current module.                     |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.specials += speA, speB                | Add anonymous specials A and B to current module.            |
   |                                            |                                                              |
   | self.specials += [speA, speB]              |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.specials.bar = spe                    | Add special named bar to current module. The special can     |
   |                                            | then be accessed using self.bar.                             |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.clock_domains += cd                   | Add clock domain to current module.                          |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.clock_domains += cdA, cdB             | Add clock domains A and B to current module.                 |
   |                                            |                                                              |
   | self.clock_domains += [cdA, cdB]           |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
   | self.clock_domains.pix = ClockDomain()     | Create and add clock domain pix to current module. The clock |
   |                                            | domain name is pix in all cases. It can be accessed using    |
   | self.clock_domains._pix = ClockDomain()    | self.pix, self._pix, self.cd_pix and self._cd_pix,           |
   |                                            | respectively.                                                |
   | self.clock_domains.cd_pix = ClockDomain()  |                                                              |
   |                                            |                                                              |
   | self.clock_domains._cd_pix = ClockDomain() |                                                              |
   +--------------------------------------------+--------------------------------------------------------------+
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

Clock domain management
=======================

When a module has named submodules that define one or several clock domains with the same name, those clock domain names are prefixed with the name of each submodule plus an underscore.

An example use case of this feature is a system with two independent video outputs. Each video output module is made of a clock generator module that defines a clock domain ``pix`` and drives the clock signal, plus a driver module that has synchronous statements and other elements in clock domain ``pix``. The designer of the video output module can simply use the clock domain name ``pix`` in that module. In the top-level system module, the video output submodules are named ``video0`` and ``video1``. Migen then automatically renames the ``pix`` clock domain of each module to ``video0_pix`` and ``video1_pix``. Note that happens only because the clock domain is defined (using ClockDomain objects), not simply referenced (using e.g. synchronous statements) in the video output modules.

Clock domain name overlap is an error condition when any of the submodules that defines the clock domains is anonymous.

Finalization mechanism
======================

Sometimes, it is desirable that some of a module logic be created only after the user has finished manipulating that module. For example, the FSM module supports that states be defined dynamically, and the width of the state signal can be known only after all states have been added. One solution is to declare the final number of states in the FSM constructor, but this is not user-friendly. A better solution is to automatically create the state signal just before the FSM module is converted to V*HDL. Migen supports this using the so-called finalization mechanism.

Modules can overload a ``do_finalize`` method that can create logic and is called using the algorithm below:

#. Finalization of the current module begins.
#. If the module has already been finalized (e.g. manually), the procedure stops here.
#. Submodules of the current module are recursively finalized.
#. ``do_finalize`` is called for the current module.
#. Any new submodules created by the current module's ``do_finalize`` are recursively finalized.

Finalization is automatically invoked at V*HDL conversion and at simulation. It can be manually invoked for any module by calling its ``finalize`` method.

The clock domain management mechanism explained above happens during finalization.

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
359 360 361
Conversion for synthesis
************************

362 363 364 365 366 367 368
Any FHDL module can be converted into synthesizable Verilog HDL. This is accomplished by using the ``convert`` function in the ``migen.fhdl.verilog`` module:

  # define FHDL module MyDesign here

  if __name__ == "__main__":
    from migen.fhdl.verilog import convert
    convert(MyDesign()).write("my_design.v")
Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
369

370
The ``migen.build`` component provides scripts to interface third-party FPGA tools (from Xilinx, Altera and Lattice) to Migen, and a database of boards for the easy deployment of designs.