1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00
2014-04-08 17:51:37 +02:00

417 lines
15 KiB
ReStructuredText

.. currentmodule:: myhdl
.. _new07:
***********************
What's new in MyHDL 0.7
***********************
Conversion to VHDL/Verilog rewritten with the ``ast`` module
============================================================
The most important code change is a change that hopefully no-one will
notice :-). The conversion code is now based on the ``ast`` package
instead of the ``compiler`` package. Since Python 2.6, the
``compiler`` package is deprecated and replaced by the new ``ast``
package in the standard library. In Python 3, the ``compiler`` package
is no longer available.
This was a considerable effort, spent on re-implementing existing
behavior instead of on new interesting features. This was
unfortunate, but it had to be done with priority. Now the conversion
code is ready for the future.
Shadow signals
==============
Background
----------
Compared to HDLs such as VHDL and Verilog, MyHDL signals are less
flexible for structural modeling. For example, slicing a signal
returns a slice of the current value. For behavioral code, this is
just fine. However, it implies that you cannot use such as slice in
structural descriptions. In other words, a signal slice cannot be used
as a signal. To solve these issues, a new concept was introduced:
shadow signals.
The whole reasoning behind shadow signals is explained in more detail in
`mep-105`_.
.. _mep-105: http://www.myhdl.org/doku.php/meps:mep-105
Introducing shadow signals
--------------------------
A shadow signal is related to another signal or signals as a shadow
to its parent object. It follows any change to its parent signal
or signals directly. However, it is not the same as the original:
in particular, the user cannot assign to a shadow signal. Also,
there may be a delta cycle delay between a change in the original
and the corresponding change in the shadow signal. Finally, to
be useful, the shadow signal performs some kind of transformation
of the values of its parent signal or signals.
A shadow signal is convenient because it is directly constructed
from its parent signals. The constructor infers everything that's needed:
the type info, the initial value, and the transformation of the
parent signal values. For simulation, the transformation is defined by
a generator which is automatically created and added to the list of
generators to be simulated. For conversion, the constructor defines
a piece of dedicated Verilog and VHDL code which is automatically
added to the convertor output.
Currently, three kinds of shadow signals have been implemented. The
original inspiration for shadow signals was to have solution for
structural slicing. This is the purpose of the :class:`_SliceSignal`
subclass. The opposite is also useful: a signal that shadows a
composition of other signals. This is the purpose of the
:class:`ConcatSignal` subclass.
As often is the case, the idea of shadow signals had some useful side
effects. In particular, I realized that the :class:`TristateSignal`
proposed in `mep-103`_ could be interpreted as a shadow signal of
its drivers. With the machinery of the shadow signal in place, it
became easier to support this for simulation and conversion.
.. _mep-103: http://www.myhdl.org/doku.php/meps:mep-103
Concrete shadow signal subclasses
---------------------------------
.. class:: _SliceSignal(sig, left[, right=None])
:noindex:
This class implements read-only structural slicing and indexing. It creates a new
signal that shadows the slice or index of the parent signal *sig*. If the
*right* parameter is omitted, you get indexing instead of slicing.
Parameters *left* and *right* have the usual meaning for slice
indices: in particular, *left* is non-inclusive but *right*
is inclusive. *sig* should be appropriate for slicing and indexing, which
means it should be based on :class:`intbv` in practice.
The class constructors is not intended to be used explicitly. Instead,
regular signals now have a call interface that returns a :class:`_SliceSignal`:
.. method:: Signal.__call__(left[, right=None])
:noindex:
Therefore, instead of::
sl = _SliceSignal(sig, left, right)
you can do::
sl = sig(left, right)
Obviously, the call interface was intended to be similar to a slicing interface. Of course,
it is not exactly the same which may seem inconvenient. On the other hand, there are Python
functions with a similar slicing functionality and a similar interface, such as the
``range`` function.
Moreover, the call interface conveys the notion that something is being constructed, which
is what really happens.
.. class:: ConcatSignal(*args)
:noindex:
This class creates a new signal that shadows the concatenation
of its parent signal values. You can pass an arbitrary number
of signals to the constructor. The signal arguments should be bit-oriented
with a defined number of bits.
.. class:: TristateSignal(val)
:noindex:
This class is used to construct a new tristate signal. The
underlying type is specified by the *val*
parameter.
It is a Signal subclass and has the usual attributes, with
one exception: it doesn't support the ``next``
attribute. Consequently, direct signal assignment to a tristate
signal is not supported.
The initial value is the tristate value ``None``.
The current value of a tristate is determined by resolving the
values from its drivers. When exactly one driver value is
different from ``None``, that is the resolved value; otherwise
it is ``None``. When more than one driver value is different
from ``None``, a contention warning is issued.
This class has the following method:
.. method:: driver()
:noindex:
Returns a new driver to the tristate signal. It is initialized
to ``None``.
A driver object is an instance of a special :class:`SignalType`
subclass. In particular, its ``next`` attribute can be used to
assign a new value to it.
Example
-------
A typical application of shadow signals is conversion of
list of signals to bit vectors and vice versa.
For example, suppose we have a system with N requesters that
need arbitration. Each requester has a ``request`` output
and a ``grant`` input. To connect them in the system, we can
use list of signals. For example, a list of request signals
can be constructed as follows::
request_list = [Signal(bool()) for i in range(M)]
Suppose that an arbiter module is available that is
instantiated as follows::
arb = arbiter(grant_vector, request_vector, clock, reset)
The ``request_vector`` input is a bit vector that can have
any of its bits asserted. The ``grant_vector`` is an output
bit vector with just a single bit asserted, or none.
Such a module is typically based on bit vectors because
they are easy to process in RTL code. In MyHDL, a bit vector
is modeled using the :class:`intbv` type.
We need a way to "connect" the list of signals to the
bit vector and vice versa. Of course, we can do this with explicit
code, but shadow signals can do this automatically. For
example, we can construct a ``request_vector`` as a
:class:`ConcatSignal` object::
request_vector = ConcatSignal(*reversed(request_list)
Note that we reverse the list first. This is done because the index range
of lists is the inverse of the range of :class:`intbv` bit vectors.
By reversing, the indices correspond to the same bit.
The inverse problem exist for the ``grant_vector``. It would be defined as follows::
grant_vector = Signal(intbv(0)[M:])
To construct a list of signals that are connected automatically to the
bit vector, we can use the :class:`Signal` call interface to construct
:class:`_SliceSignal` objects::
grant_list = [grant_vector(i) for i in range(M)]
Note the round brackets used for this type of slicing. Also, it may not be
necessary to construct this list explicitly. You can simply use
``grant_vector(i)`` in an instantiation.
To decide when to use normal or shadow signals, consider the data
flow. Use normal signals to connect to *outputs*. Use shadow signals to
transform these signals so that they can be used as *inputs*.
Using :class:`Signal` and :class:`intbv` objects as indices
===========================================================
Previously, it was necessary convert :class:`Signal` and :class:`intbv` objects
explicitly to :class:`int` when using them as indices for
indexing and slicing. This conversion is no longer required;
the objects can be used directly.
The corresponding classes now have an :func:`__index__` method
that takes care of the type conversion automatically.
This feature is fully supported by the VHDL/Verilog convertor.
New configuration attributes for conversion file headers
========================================================
New configuration attributes are available to control the file
headers of converted output files.
.. attribute:: toVerilog.no_myhdl_header
Specifies that MyHDL conversion to Verilog should not generate a
default header. Default value is *False*.
.. attribute:: toVHDL.no_myhdl_header
Specifies that MyHDL conversion to VHDL should not generate a
default header. Default value is *False*.
.. attribute:: toVerilog.header
Specifies an additional custom header for Verilog output.
.. attribute:: toVHDL.header
Specifies an additional custom header for VHDL output.
The value for the custom headers should be a string
that is suitable for the standard :class:`string.Template` constructor.
A number of variables (indicated by a ``$`` prefix)
are available for string interpolation.
For example, the standard header is defined as follows::
myhdl_header = """\
-- File: $filename
-- Generated by MyHDL $version
-- Date: $date
"""
The same interpolation variables are available in custom headers.
Conversion propagates docstrings
================================
The convertor now 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.
New method to specify user-defined code
=======================================
The current way to specify user-defined code for conversion is through
the ``__vhdl__`` and ``__verilog__`` hooks. This method has a number
of disadvantages.
First, the use of "magic" variables (whose names start and end with
double underscores) was a bad choice. According to Python
conventions, such variables should be reserved for the Python language
itself. Moreover, when new hooks would become desirable, we would
have to specify additional magic variables.
A second problem that standard Python strings were used to define
the user-defined output. These strings can contain the signal
names from the context for interpolation. Typically, these are
multiple-line strings that may be quite lengthy. When something
goes wrong with the string interpolation, the error messages may
be quite cryptic as the line and column information is not present.
For these reasons, a new way to specify user-defined code has
been implemented that avoids these problems.
The proper way to specify meta-information of a function is by using
function attributes. Suppose a function :func:`<func>` defines
a hardware module. We can now specify user-defined code for it
with the following function attributes:
.. attribute:: <func>.vhdl_code
A template string for user-defined code in the VHDL output.
.. attribute:: <func>.verilog_code
A template string for user-defined code in the Verilog output.
When such a function attribute is defined, the normal conversion
process is bypassed and the user-defined code is inserted instead.
The template strings should be suitable for the standard
:class:`string.Template` constructor. They can contain interpolation
variables (indicated by a ``$`` prefix) for all signals in the
context. Note that the function attribute can be defined anywhere where
:func:`<func>` is visible, either outside or inside the function
itself.
The old method for user-defined code is still available but
is deprecated and will be unsupported in the future.
More powerful mapping to case statements
========================================
The convertor has become more powerful to map if-then-else structures
to case statements in VHDL and Verilog. Previously, only
if-then-else structures testing enumerated types were considered.
Now, integer tests are considered also.
Small changes
=============
:class:`SignalType` as the base class of Signals
------------------------------------------------
:func:`Signal` has become a function instead of
a class. It returns different Signal subtypes
depending on parameters. This implies that you
cannot use :func:`Signal` for type checking.
The base type of all Signals is now :class:`SignalType`.
This type can be used to check whether an object
is a Signal instance.
Default value of :class:`intbv` objects
---------------------------------------
The default initial value of an :class:`intbv` object has been
changed from *None* to ``0``. Though this is backward-incompatible,
the *None* value never has been put to good use, so this is
most likely not an issue.
Combinatorial always blocks use blocking assignments
----------------------------------------------------
The convertor now uses blocking assignments for combinatorial
always blocks in Verilog. This is in line with generally
accepted Verilog coding conventions.
No synthesis pragmas in Verilog output
--------------------------------------
The convertor no longer outputs the synthesis pragmas
``full_case`` and ``parallel_case``. These pragmas do
more harm than good as they can cause simulation-synthesis
mismatches. Synthesis tools should be able to infer the
appropriate optimizations from the source code directly.
Python version
==============
MyHDL 0.7 requires Python 2.6, mainly because of its
dependency on the new ``ast`` package.
Acknowledgments
===============
Several people have contributed to MyHDL 0.7 by giving feedback,
making suggestions, fixing bugs and implementing features.
In particular, I would like to thank
Benoit Allard,
Günter Dannoritzer,
Tom Dillon,
Knut Eldhuset,
Angel Ezquerra,
Christopher Felton,
and Jian LUO.
Thanks to Francesco Balau for packaging MyHDL for Ubuntu.
I would also like to thank `Easics`_ for
the opportunity to use MyHDL in industrial projects.
.. _`Easics`: http://www.easics.com