mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
1513a24e18
Updated the MyHDL manual to include the 0.9 what's new in the index and additional verbage in the conversion section on interfaces. This commit is also being used as a test vehicle for the new development flow using git.
821 lines
31 KiB
ReStructuredText
821 lines
31 KiB
ReStructuredText
.. currentmodule:: myhdl
|
|
|
|
.. _conv:
|
|
|
|
******************************
|
|
Conversion to Verilog and VHDL
|
|
******************************
|
|
|
|
|
|
.. _conv-intro:
|
|
|
|
Introduction
|
|
============
|
|
|
|
Subject to some limitations,
|
|
MyHDL supports the automatic conversion of MyHDL code to
|
|
Verilog or VHDL code. This feature provides a path from MyHDL into a
|
|
standard Verilog or VHDL based design environment.
|
|
|
|
This chapter describes the concepts of conversion. Concrete
|
|
examples can be found in the companion chapter :ref:`conv-usage`.
|
|
|
|
.. _conv-solution:
|
|
|
|
Solution description
|
|
====================
|
|
|
|
To be convertible, the hardware description should satisfy certain restrictions,
|
|
defined as the :dfn:`convertible subset`. This is described
|
|
in detail in :ref:`conv-subset`.
|
|
|
|
A convertible design can be converted to an equivalent model in Verilog
|
|
or VHDL, using the function :func:`toVerilog` or :func:`toVHDL` from the MyHDL
|
|
library.
|
|
|
|
When the design is intended for implementation
|
|
a third-party :dfn:`synthesis tool` is used to compile the Verilog or VHDL
|
|
model into an implementation for an ASIC or FPGA. With this step, there is
|
|
an automated path from a hardware description in Python to an FPGA or ASIC implementation.
|
|
|
|
The conversion does not start from source files, but from an instantiated design
|
|
that has been *elaborated* by the Python interpreter. The converter uses the
|
|
Python profiler to track the interpreter's operation and to infer the design
|
|
structure and name spaces. It then selectively compiles pieces of source code
|
|
for additional analysis and for conversion.
|
|
|
|
.. _conv-features:
|
|
|
|
Features
|
|
========
|
|
|
|
|
|
Conversion after elaboration
|
|
*Elaboration* refers to the initial processing of a hardware description to
|
|
achieve a representation of a design instance that is ready for simulation or
|
|
synthesis. In particular, structural parameters and constructs are processed in
|
|
this step. In MyHDL, the Python interpreter itself is used for elaboration. A
|
|
:class:`Simulation` object is constructed with elaborated design instances as
|
|
arguments. Likewise, conversion works on an elaborated design
|
|
instance. The Python interpreter is thus used as much as possible.
|
|
|
|
Arbitrarily complex structure
|
|
As the conversion works on an elaborated design instance, any modeling
|
|
constraints only apply to the leaf elements of the design structure, that is,
|
|
the co-operating generators. In other words, there are no restrictions on the
|
|
description of the design structure: Python's full power can be used for that
|
|
purpose. Also, the design hierarchy can be arbitrarily deep.
|
|
|
|
Generator are mapped to Verilog or VHDL constructs
|
|
The converter analyzes the code of each generator and maps it to equivalent
|
|
constructs in the target HDL. For Verilog, it will map generators to
|
|
``always`` blocks, continuous assignments or ``initial`` blocks. For VHDL,
|
|
it will map them to ``process`` statements or concurrent signal assignments.
|
|
|
|
The module ports are inferred from signal usage
|
|
In MyHDL, the input or output direction of interface signals is not explicitly
|
|
declared. The converter investigates signal usage in the design hierarchy to
|
|
infer whether a signal is used as input, output, or as an internal signal.
|
|
|
|
Interfaces are expanded
|
|
MyHDL provides a power mechanism to define complex module interfaces.
|
|
These interfaces are name extended to individual signals in the target
|
|
HDL (Verilog and VHDL). This enables MyHDL to support higher-level
|
|
abstractions that are not available in the target HDL.
|
|
|
|
Function calls are mapped to Verilog or VHDL subprograms
|
|
The converter analyzes function calls and function code. Each function is
|
|
mapped to an appropriate subprogram in the target HDL: a function or task in Verilog,
|
|
and a function or procedure in VHDL.
|
|
In order to support the full power of Python functions,
|
|
a unique subprogram is generated per Python function call.
|
|
|
|
If-then-else structures may be mapped to case statements
|
|
Python does not provide a case statement. However, the converter recognizes if-then-else
|
|
structures in which a variable is sequentially compared to items of an
|
|
enumeration type, and maps such a structure to a Verilog or VHDL case statement with the
|
|
appropriate synthesis attributes.
|
|
|
|
Choice of encoding schemes for enumeration types
|
|
The :func:`enum` function in MyHDL returns an enumeration type. This function
|
|
takes an additional parameter *encoding* that specifies the desired encoding in
|
|
the implementation: binary, one hot, or one cold. The converter
|
|
generates the appropriate code for the specified encoding.
|
|
|
|
RAM memory
|
|
Certain synthesis tools can map Verilog memories or VHDL arrays to RAM structures. To support
|
|
this interesting feature, the converter maps lists of signals to Verilog
|
|
memories or VHDL arrays.
|
|
|
|
ROM memory
|
|
Some synthesis tools can infer a ROM from a case statement. The
|
|
converter does the expansion into a case statement automatically, based on a
|
|
higher level description. The ROM access is described in a single line, by
|
|
indexing into a tuple of integers.
|
|
|
|
Signed arithmetic
|
|
In MyHDL, working with negative numbers is trivial: one just uses an
|
|
``intbv`` object with an appropriate constraint on its values. In
|
|
contrast, both Verilog and VHDL make a difference between an
|
|
unsigned and a signed representation. To work with negative values,
|
|
the user has to declare a signed variable explicitly. But when
|
|
signed and unsigned operands are mixed in an expression, things may
|
|
become tricky.
|
|
|
|
In Verilog, when signed and unsigned operands are mixed, all
|
|
operands are interpreted as *unsigned*. Obviously, this leads to
|
|
unexpected results. The designer will have to add sign extensions
|
|
and type casts to solve this.
|
|
|
|
In VHDL, mixing signed and unsigned will generally not work. The
|
|
designer will have to match the operands manually by adding
|
|
resizings and type casts.
|
|
|
|
In MyHDL, these issues don't exist because ``intbv`` objects simply
|
|
work as (constrained) integers. Moreover, the convertor automates
|
|
the cumbersome tasks that are required in Verilog and
|
|
VHDL. It uses signed or unsigned types based on the value
|
|
constraints of the intbv objects, and automatically performs the
|
|
required sign extensions, resizings, and type casts.
|
|
|
|
|
|
User-defined code
|
|
If desired, the user can bypass the conversion process and describe
|
|
user-defined code to be inserted instead.
|
|
|
|
|
|
.. _conv-subset:
|
|
|
|
The convertible subset
|
|
======================
|
|
|
|
|
|
.. _conv-subset-intro:
|
|
|
|
Introduction
|
|
------------
|
|
|
|
Unsurprisingly, not all MyHDL code can be converted. Although the
|
|
restrictions are significant, the convertible subset is much broader
|
|
than the RTL synthesis subset which is an industry standard. In other
|
|
words, MyHDL code written according to the RTL synthesis rules, should
|
|
always be convertible. However, it is also possible to write
|
|
convertible code for non-synthesizable models or test benches.
|
|
|
|
The converter attempts to issue clear error messages when it
|
|
encounters a construct that cannot be converted.
|
|
|
|
Recall that any restrictions only apply to the design after
|
|
elaboration. In practice, this means that they apply only to the code
|
|
of the generators, that are the leaf functional blocks in a MyHDL
|
|
design.
|
|
|
|
|
|
.. _conv-subset-style:
|
|
|
|
Coding style
|
|
------------
|
|
|
|
A natural restriction on convertible code is that it should be written
|
|
in MyHDL style: cooperating generators, communicating through signals,
|
|
and with sensitivity specify resume conditions.
|
|
|
|
For pure modeling, it doesn't matter how generators are created.
|
|
However, in convertible code they should be created using one of the
|
|
MyHDL decorators: :func:`instance`, :func:`always`,
|
|
:func:`always_seq`, or :func:`always_comb`.
|
|
|
|
|
|
.. _conv-subset-types:
|
|
|
|
Supported types
|
|
---------------
|
|
|
|
The most important restriction regards object types. Only a limited
|
|
amount of types can be converted. Python :class:`int` and
|
|
:class:`long` objects are mapped to Verilog or VHDL integers. All
|
|
other supported types need to have a defined bit width. The
|
|
supported types are the Python :class:`bool` type, the MyHDL
|
|
:class:`intbv` type, and MyHDL enumeration types returned by function
|
|
:func:`enum`.
|
|
|
|
.. index:: single: intbv; conversion
|
|
|
|
:class:`intbv` objects must be constructed so that a bit width can be
|
|
inferred. This can be done by specifying minimum and maximum values,
|
|
e.g. as follows::
|
|
|
|
index = intbv(0, min=MIN, max=MAX)
|
|
|
|
The Verilog converter supports :class:`intbv` objects that can take
|
|
negative values.
|
|
|
|
Alternatively, a slice can be taken from an :class:`intbv` object as
|
|
follows::
|
|
|
|
index = intbv(0)[N:]
|
|
|
|
Such as slice returns a new :class:`intbv` object, with minimum value
|
|
``0`` , and maximum value ``2**N``.
|
|
|
|
In addition to the scalar types described above, the convertor also
|
|
supports a number of tuple and list based types. The mapping from
|
|
MyHDL types is summarized in the following table.
|
|
|
|
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| MyHDL type | VHDL type | Notes | Verilog type | Notes |
|
|
+============================================+===============================+===========+===============================+===========+
|
|
| ``int`` | ``integer`` | | ``integer`` | |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``bool`` | ``std_logic`` | \(1) | ``reg`` | |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``intbv`` with ``min >= 0`` | ``unsigned`` | \(2) | ``reg`` | |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``intbv`` with ``min < 0`` | ``signed`` | \(2) | ``reg signed`` | |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``enum`` | dedicated enumeration type | | ``reg`` | |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``tuple`` of ``int`` | mapped to case statement | \(3) | mapped to case statement | \(3) |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``list`` of ``bool`` | ``array of std_logic`` | | ``reg`` | \(5) |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``list`` of ``intbv`` with ``min >= 0`` | ``array of unsigned`` | \(4) | ``reg`` | \(4)\(5) |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
| ``list`` of ``intbv`` with ``min < 0`` | ``array of signed`` | \(4) | ``reg signed`` | \(4)\(5) |
|
|
+--------------------------------------------+-------------------------------+-----------+-------------------------------+-----------+
|
|
|
|
|
|
Notes:
|
|
|
|
(1)
|
|
The VHDL ``std_logic`` type is defined in the standard VHDL package
|
|
``IEEE.std_logic_1164``.
|
|
|
|
(2)
|
|
The VHDL ``unsigned`` and ``signed`` types used are those from the
|
|
standard VHDL packages ``IEEE.numeric_std``.
|
|
|
|
(3)
|
|
A MyHDL ``tuple`` of ``int`` is used for ROM inference, and can only be
|
|
used in a very specific way: an indexing operation into the tuple
|
|
should be the rhs of an assignment.
|
|
|
|
(4)
|
|
All list members should have identical value constraints.
|
|
|
|
|
|
(5)
|
|
Lists are mapped to Verilog memories.
|
|
|
|
|
|
The table as presented applies to MyHDL variables. The convertor also
|
|
supports MyHDL signals that use ``bool``, ``intbv`` or ``enum``
|
|
objects as their underlying type. For VHDL, these are mapped to VHDL signals
|
|
with an underlying type as specified in the table above. Verilog doesn't have
|
|
the signal concept. For Verilog, a MyHDL signal is mapped to a Verilog
|
|
``reg`` as in the table above, or to a Verilog ``wire``, depending
|
|
on the signal usage.
|
|
|
|
The convertor supports MyHDL list of signals provided the underlying
|
|
signal type is either ``bool`` or ``intbv``. They may be mapped to a
|
|
VHDL signal with a VHDL type as specified in the table, or to a
|
|
Verilog memory. However, list of signals are not always mapped to a
|
|
corresponding VHDL or Verilog object. See :ref:`conv-listofsigs` for
|
|
more info.
|
|
|
|
.. _conv-subset-statements:
|
|
|
|
Supported statements
|
|
--------------------
|
|
|
|
The following is a list of the statements that are supported by the Verilog
|
|
converter, possibly qualified with restrictions or usage notes.
|
|
|
|
:keyword:`assert`
|
|
An :keyword:`assert` statement in Python looks as follow::
|
|
|
|
assert test_expression
|
|
|
|
It can be converted provided ``test_expression`` is convertible.
|
|
|
|
:keyword:`break`
|
|
|
|
:keyword:`continue`
|
|
|
|
:keyword:`def`
|
|
|
|
:keyword:`for`
|
|
The only supported iteration scheme is iterating through sequences of integers
|
|
returned by built-in function :func:`range` or MyHDL function
|
|
:func:`downrange`. The optional :keyword:`else` clause is not supported.
|
|
|
|
:keyword:`if`
|
|
:keyword:`if`, :keyword:`elif`, and :keyword:`else` clauses are fully supported.
|
|
|
|
:keyword:`pass`
|
|
|
|
:keyword:`print`
|
|
|
|
A :keyword:`print` statement with multiple arguments::
|
|
|
|
print arg1, arg2, ...
|
|
|
|
is supported. However, there are restrictions on the arguments.
|
|
First, they should be of one of the following forms::
|
|
|
|
arg
|
|
formatstring % arg
|
|
formatstring % (arg1, arg2, ...)
|
|
|
|
where ``arg`` is a ``bool``, ``int``, ``intbv``, ``enum``, or a
|
|
``Signal`` of these types.
|
|
|
|
The ``formatstring`` contains ordinary characters and conversion
|
|
specifiers as in Python. However, the only supported conversion specifiers
|
|
are ``%s`` and ``%d``.
|
|
Justification and width specification are thus not supported.
|
|
|
|
Printing without a newline::
|
|
|
|
print arg1 ,
|
|
|
|
is not supported.
|
|
|
|
|
|
:keyword:`raise`
|
|
This statement is mapped to statements that end the simulation with an
|
|
error message.
|
|
|
|
:keyword:`return`
|
|
|
|
:keyword:`yield`
|
|
A `yield` expression is used to specify a sensitivity list.
|
|
The yielded expression can be a :class:`Signal`, a signal edge as specified by MyHDL
|
|
functions :attr:`Signal.posedge` or :attr:`Signal.negedge`, or a tuple of signals and edge
|
|
specifications. It can also be a :func:`delay` object.
|
|
|
|
:keyword:`while`
|
|
The optional :keyword:`else` clause is not supported.
|
|
|
|
|
|
.. _conv-subset-builtin:
|
|
|
|
Supported built-in functions
|
|
----------------------------
|
|
|
|
The following is a list of the built-in functions that are supported by the
|
|
converter.
|
|
|
|
:func:`bool`
|
|
This function can be used to typecast an object explicitly to its boolean
|
|
interpretation.
|
|
|
|
:func:`len`
|
|
For :class:`Signal` and :class:`intbv` objects, function :func:`len` returns the
|
|
bit width.
|
|
|
|
:func:`int`
|
|
This function can be used to typecast an object explicitly to its integer
|
|
interpretation.
|
|
|
|
|
|
Docstrings
|
|
----------
|
|
|
|
The convertor propagates comments under the form of Python
|
|
docstrings.
|
|
|
|
Docstrings are typically used in Python to document certain objects in
|
|
a standard way. Such "official" docstrings are put into the converted
|
|
output at appropriate locations. The convertor supports official
|
|
docstrings for the top level module and for generators.
|
|
|
|
Within generators, "nonofficial" docstrings are propagated also. These
|
|
are strings (triple quoted by convention) that can occur anywhere
|
|
between statements.
|
|
|
|
Regular Python comments are ignored by the Python parser, and they are
|
|
not present in the parse tree. Therefore, these are not
|
|
propagated. With docstrings, you have an elegant way to specify which
|
|
comments should be propagated and which not.
|
|
|
|
|
|
|
|
.. _conv-listofsigs:
|
|
|
|
Conversion of lists of signals
|
|
==============================
|
|
|
|
Lists of signals are useful for many purposes. For example, they make
|
|
it easy to create a repetitive structure. Another application is the
|
|
description of memory behavior.
|
|
|
|
The convertor output is non-hierarchical. That implies that all
|
|
signals are declared at the top-level in VHDL or Verilog (as VHDL
|
|
signals, or Verilog regs and wires.) However, some signals that are a
|
|
list member at some level in the MyHDL design hierarchy may be used as
|
|
a plain signal at a lower level. For such signals, a choice has to be
|
|
made whether to declare a Verilog memory or VHDL array, or a number of
|
|
plain signal names.
|
|
|
|
If possible, plain signal declarations are preferred, because Verilog
|
|
memories and arrays have some restrictions in usage and tool support.
|
|
This is possible if the list syntax is strictly used outside generator
|
|
code, for example when lists of signals are used to describe
|
|
structure.
|
|
|
|
Conversely, when list syntax is used in some generator, then a Verilog
|
|
memory or VHDL array will be declared. The typical example is the
|
|
description of RAM memories.
|
|
|
|
|
|
.. _conv-interfaces:
|
|
|
|
Conversion of Interfaces
|
|
========================
|
|
Interfaces simplify the complicated interconnect between modules.
|
|
In MyHDL the interfaces provide an intuitive approach to group
|
|
logically related ports. The grouping of ports has many benefits
|
|
such as reducing complexity and increasing modularity.
|
|
|
|
The converter will name extend the interfaces during conversion,
|
|
in the converted code each attribute will appear as a individual
|
|
signal. Because the hierarchy is flattened the name extension
|
|
may need to include information on the where in the hierarchy
|
|
the interface occurs to prevent name collisions.
|
|
|
|
.. _conv-meth-assign:
|
|
|
|
Assignment issues
|
|
=================
|
|
|
|
|
|
.. _conv-meth-assign-python:
|
|
|
|
Name assignment in Python
|
|
-------------------------
|
|
|
|
Name assignment in Python is a different concept than in many other languages.
|
|
This point is very important for effective modeling in Python, and even more so
|
|
for synthesizable MyHDL code. Therefore, the issues are discussed here
|
|
explicitly.
|
|
|
|
Consider the following name assignments::
|
|
|
|
a = 4
|
|
a = ``a string''
|
|
a = False
|
|
|
|
In many languages, the meaning would be that an existing variable *a* gets a
|
|
number of different values. In Python, such a concept of a variable doesn't
|
|
exist. Instead, assignment merely creates a new binding of a name to a certain
|
|
object, that replaces any previous binding. So in the example, the name *a* is
|
|
bound a number of different objects in sequence.
|
|
|
|
The converter has to investigate name assignment and usage in MyHDL
|
|
code, and to map names to Verilog or VHDL objects. To achieve that, it tries to infer
|
|
the type and possibly the bit width of each expression that is assigned to a
|
|
name.
|
|
|
|
Multiple assignments to the same name can be supported if it can be determined
|
|
that a consistent type and bit width is being used in the assignments. This can
|
|
be done for boolean expressions, numeric expressions, and enumeration type
|
|
literals.
|
|
|
|
In other cases, a single assignment should be used when an object is created.
|
|
Subsequent value changes are then achieved by modification of an existing
|
|
object. This technique should be used for :class:`Signal` and :class:`intbv`
|
|
objects.
|
|
|
|
|
|
.. _conv-meth-assign-signal:
|
|
|
|
Signal assignment
|
|
-----------------
|
|
|
|
Signal assignment in MyHDL is implemented using attribute assignment to
|
|
attribute ``next``. Value changes are thus modeled by modification of the
|
|
existing object. The converter investigates the :class:`Signal` object to infer
|
|
the type and bit width of the corresponding Verilog or VHDL object.
|
|
|
|
|
|
.. _conv-meth-assign-intbv:
|
|
|
|
:class:`intbv` objects
|
|
----------------------
|
|
|
|
.. index:: single: intbv; conversion
|
|
|
|
Type :class:`intbv` is likely to be the workhorse for synthesizable
|
|
modeling in MyHDL. An :class:`intbv` instance behaves like a (mutable)
|
|
integer whose individual bits can be accessed and modified. Also, it
|
|
is possible to constrain its set of values. In addition to error
|
|
checking, this makes it possible to infer a bit width, which is
|
|
required for implementation.
|
|
|
|
As noted before, it is not possible to modify value of an
|
|
:class:`intbv` object using name assignment. In the following, we will
|
|
show how it can be done instead. Consider::
|
|
|
|
a = intbv(0)[8:]
|
|
|
|
This is an :class:`intbv` object with initial value ``0`` and bit
|
|
width 8. To change its value to ``5``, we can use slice assignment::
|
|
|
|
a[8:] = 5
|
|
|
|
The same can be achieved by leaving the bit width unspecified, which
|
|
has the meaning to change "all" bits::
|
|
|
|
a[:] = 5
|
|
|
|
Often the new value will depend on the old one. For example, to
|
|
increment an :class:`intbv` with the technique above::
|
|
|
|
a[:] = a + 1
|
|
|
|
Python also provides *augmented* assignment operators, which can be
|
|
used to implement in-place operations. These are supported on
|
|
:class:`intbv` objects and by the converter, so that the increment can
|
|
also be done as follows::
|
|
|
|
a += 1
|
|
|
|
|
|
|
|
|
|
.. _conv-subset-exclude:
|
|
|
|
Excluding code from conversion
|
|
==============================
|
|
|
|
For some tasks, such as debugging, it may be useful to insert arbitrary Python
|
|
code that should not be converted.
|
|
|
|
The convertor supports this by ignoring all code that is embedded in a
|
|
``if __debug__`` test. The value of the ``__debug__`` variable is not taken into
|
|
account.
|
|
|
|
|
|
.. index:: single: user-defined code; description
|
|
|
|
.. _conv-custom:
|
|
|
|
User-defined code
|
|
=================
|
|
|
|
MyHDL provides a way to include user-defined code during the
|
|
conversion process. There are special function attributes that are understood by the
|
|
converter but ignored by the simulator. The attributes are :attr:`verilog_code`
|
|
for Verilog and :attr:`vhdl_code` for VHDL. They operate like a special
|
|
return value. When defined in a MyHDL function, the convertor will use
|
|
their value instead of the regular return value. Effectively, it will
|
|
stop converting at that point.
|
|
|
|
The value of :attr:`verilog_code` or :attr:`vhdl_code` should be a Python
|
|
template string. A template string supports ``$``-based substitutions.
|
|
The ``$name`` notation can be used to refer to the
|
|
variable names in the context of the string. The convertor will
|
|
substitute the appropriate values in the string and then insert it
|
|
instead of the regular converted output.
|
|
|
|
There is one more issue with user-defined code.
|
|
Normally, the converter infers inputs, internal signals,
|
|
and outputs. It also detects undriven and multiple driven signals. To
|
|
do this, it assumes that signals are not driven by default. It then
|
|
processes the code to find out which signals are driven from
|
|
where.
|
|
|
|
Proper signal usage inference cannot be done with user-defined code. Without
|
|
user help, this will result in warnings or errors during the
|
|
inference process, or in compilation errors from invalid
|
|
code. The user can solve this by setting the :attr:`driven` or
|
|
:attr:`read` attribute
|
|
for signals that are driven or read from the user-defined code.
|
|
These attributes are ``False`` by default.
|
|
The allowed "true" values of the :attr:`driven` attribute are
|
|
``True``, ``'wire'`` and ``'reg'``. The
|
|
latter two values specifies how the user-defined Verilog code drives the signal in
|
|
Verilog. To decide which value to use, consider how the signal should
|
|
be declared in Verilog after the user-defined code is inserted.
|
|
|
|
For an example of user-defined code, see :ref:`conv-usage-custom`.
|
|
|
|
|
|
Template transformation
|
|
=======================
|
|
|
|
.. note:: This section is only relevant for VHDL.
|
|
|
|
There is a difference between VHDL and Verilog in the way in which
|
|
sensitivity to signal edges is specified. In Verilog, edge specifiers
|
|
can be used directly in the sensitivity list. In VHDL, this is not
|
|
possible: only signals can be used in the sensitivity list. To check
|
|
for an edge, one uses the ``rising_edge()`` or ``falling_edge()``
|
|
functions in the code.
|
|
|
|
MyHDL follows the Verilog scheme to specify edges in the sensitivity
|
|
list. Consequently, when mapping such code to VHDL, it needs to be
|
|
transformed to equivalent VHDL. This is an important issue because it
|
|
affects all synthesizable templates that infer sequential logic.
|
|
|
|
We will illustrate this feature with some examples. This is the MyHDL
|
|
code for a D flip-flop::
|
|
|
|
|
|
@always(clk.posedge)
|
|
def logic():
|
|
q.next = d
|
|
|
|
|
|
It is converted to VHDL as follows::
|
|
|
|
DFF_LOGIC: process (clk) is
|
|
begin
|
|
if rising_edge(clk) then
|
|
q <= d;
|
|
end if;
|
|
end process DFF_LOGIC;
|
|
|
|
|
|
The convertor can handle the more general case. For example, this is
|
|
MyHDL code for a D flip-flop with asynchronous set, asynchronous
|
|
reset, and preference of set over reset::
|
|
|
|
|
|
@always(clk.posedge, set.negedge, rst.negedge)
|
|
def logic():
|
|
if set == 0:
|
|
q.next = 1
|
|
elif rst == 0:
|
|
q.next = 0
|
|
else:
|
|
q.next = d
|
|
|
|
|
|
This is converted to VHDL as follows::
|
|
|
|
|
|
DFFSR_LOGIC: process (clk, set, rst) is
|
|
begin
|
|
if (set = '0') then
|
|
q <= '1';
|
|
elsif (rst = '0') then
|
|
q <= '0';
|
|
elsif rising_edge(clk) then
|
|
q <= d;
|
|
end if;
|
|
end process DFFSR_LOGIC;
|
|
|
|
|
|
All cases with practical utility can be handled in this way. However,
|
|
there are other cases that cannot be transformed to equivalent
|
|
VHDL. The convertor will detect those cases and give an error.
|
|
|
|
|
|
.. _conv-meth-conv:
|
|
|
|
Conversion output verification by co-simulation
|
|
===============================================
|
|
|
|
.. note:: This section is only relevant for Verilog.
|
|
|
|
To verify the converted Verilog output, co-simulation can be used. To
|
|
make this task easier, the converter also generates a test bench that
|
|
makes it possible to simulate the Verilog design using the Verilog
|
|
co-simulation interface. This permits to verify the Verilog code with
|
|
the same test bench used for the MyHDL code.
|
|
|
|
|
|
.. _conv-testbench:
|
|
|
|
Conversion of test benches
|
|
==========================
|
|
|
|
After conversion, we obviously want to verify that the VHDL or Verilog
|
|
code works correctly. For Verilog, we can use co-simulation as
|
|
discussed earlier. However, for VHDL, co-simulation is currently
|
|
not supported.
|
|
|
|
An alternative is to convert the test bench itself, so that
|
|
both test bench and design can be run in the HDL simulator. Of course,
|
|
this is not a fully general solution, as there are important
|
|
constraints on the kind of code that can be converted.
|
|
Thus, the question is whether the conversion restrictions permit to develop
|
|
sufficiently complex test benches. In this section, we present some
|
|
insights about this.
|
|
|
|
The most important restrictions regard the types that can be used, as
|
|
discussed earlier in this chapter. However, the "convertible subset" is
|
|
wider than the "synthesis subset". We will present a number of
|
|
non-synthesizable feature that are of interest for test benches.
|
|
|
|
the :keyword:`while` loop
|
|
:keyword:`while` loops can be used for high-level control structures.
|
|
|
|
the :keyword:`raise` statement
|
|
A :keyword:`raise` statement can stop the simulation on an error condition.
|
|
|
|
:func:`delay()` objects
|
|
Delay modeling is essential for test benches.
|
|
|
|
the :keyword:`print` statement
|
|
:keyword:`print` statements can be used for simple debugging.
|
|
|
|
the :keyword:`assert` statement.
|
|
Originally, :keyword:`assert` statements were only intended to insert debugging
|
|
assertions in code. Recently, there is a tendency to use them to write
|
|
self-checking unit tests, controlled by unit test frameworks such as
|
|
``py.test``. In particular, they are a powerful way to write
|
|
self-checking test benches for MyHDL designs. As :keyword:`assert`
|
|
statements are convertible, a whole unit test suite in MyHDL can be
|
|
converted to an equivalent test suite in Verilog and VHDL.
|
|
|
|
Additionally, the same techniques as for synthesizable code can be used
|
|
to master complexity. In particular, any code outside generators
|
|
is executed during elaboration, and therefore not considered in
|
|
the conversion process. This feature can for example be used for
|
|
complex calculations that set up constants or expected results.
|
|
Furthermore, a tuple of ints can be used to hold a table of
|
|
values that will be mapped to a case statement in Verilog and VHDL.
|
|
|
|
|
|
|
|
.. _conv-meth:
|
|
|
|
Methodology notes
|
|
=================
|
|
|
|
|
|
.. _conv-meth-sim:
|
|
|
|
Simulate first
|
|
--------------
|
|
|
|
In the Python philosophy, the run-time rules. The Python compiler doesn't
|
|
attempt to detect a lot of errors beyond syntax errors, which given Python's
|
|
ultra-dynamic nature would be an almost impossible task anyway. To verify a
|
|
Python program, one should run it, preferably using unit testing to verify each
|
|
feature.
|
|
|
|
The same philosophy should be used when converting a MyHDL description to
|
|
Verilog: make sure the simulation runs fine first. Although the converter checks
|
|
many things and attempts to issue clear error messages, there is no guarantee
|
|
that it does a meaningful job unless the simulation runs fine.
|
|
|
|
|
|
.. _conv-meth-hier:
|
|
|
|
Handling hierarchy
|
|
------------------
|
|
|
|
Recall that conversion occurs after elaboration. A consequence is that
|
|
the converted output is non-hierarchical. In many cases, this is not an
|
|
issue. The purpose of conversion is to provide a path into a traditional
|
|
design flow by using Verilog and VHDL as a "back-end" format. Hierarchy
|
|
is quite relevant to humans, but much less so to tools.
|
|
|
|
However, in some cases hierarchy is desirable. For example, if you convert
|
|
a test bench you may prefer to keep its code separate from the design
|
|
under test. In other words, conversion should stop at the design under test
|
|
instance, and insert an instantiation instead.
|
|
|
|
There is a workaround to accomplish this with a small amount of additional
|
|
work. The workaround is to define user-defined code consisting of an
|
|
instantiation of the design under test. As discussed in :ref:`conv-custom`,
|
|
when the convertor sees the hook it will stop converting and insert the
|
|
instantiation instead. Of course, you will want to convert the design
|
|
under test itself also. Therefore, you should use a flag that controls
|
|
whether the hook is defined or not and set it according to the
|
|
desired conversion.
|
|
|
|
.. _conv-issues:
|
|
|
|
Known issues
|
|
============
|
|
|
|
Verilog and VHDL integers are 32 bit wide
|
|
Usually, Verilog and VHDL integers are 32 bit wide. In contrast,
|
|
Python is moving toward integers with undefined width. Python
|
|
:class:`int` and :class:`long` variables are mapped to Verilog
|
|
integers; so for values wider than 32 bit this mapping is
|
|
incorrect.
|
|
|
|
Synthesis pragmas are specified as Verilog comments.
|
|
The recommended way to specify synthesis pragmas in Verilog is
|
|
through attribute lists. However, the Icarus simulator doesn't
|
|
support them for ``case`` statements (to specify ``parallel_case``
|
|
and ``full_case`` pragmas). Therefore, the old but deprecated
|
|
method of synthesis pragmas in Verilog comments is still used.
|
|
|
|
Inconsistent place of the sensitivity list inferred from ``always_comb``.
|
|
The semantics of ``always_comb``, both in Verilog and MyHDL, is to
|
|
have an implicit sensitivity list at the end of the code. However,
|
|
this may not be synthesizable. Therefore, the inferred sensitivity
|
|
list is put at the top of the corresponding ``always`` block or
|
|
``process``. This may cause inconsistent behavior at the start of
|
|
the simulation. The workaround is to create events at time 0.
|
|
|
|
|