1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00
2015-04-27 16:09:24 -04:00

399 lines
13 KiB
ReStructuredText
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

=======================
Whats New in MyHDL 0.3
=======================
:Author: Jan Decaluwe
VCD output for waveform viewing
===============================
|image|
MyHDL now has support for waveform viewing. During simulation, signal
changes can be written to a VCD output file that can be loaded into a
waveform viewer tool such as **gtkwave**.
The user interface of this feature consists of a single function,
:func:`traceSignals()`. To explain how it works, recall that in MyHDL,
an instance is created by assigning the result of a function call to an
instance name. For example:
::
tb_fsm = testbench()
To enable VCD tracing, the instance should be created as follows
instead:
::
tb_fsm = traceSignals(testbench)
All signals in the instance hierarchy will be traced in a VCD file
called . Note that first the argument of :func:`traceSignals()` consists
of the uncalled function. By calling the function under its control,
:func:`traceSignals()` gathers information about the hierarchy and the
signals to be traced. In addition to a function argument,
:func:`traceSignals()` accepts an arbitrary number of non-keyword and
keyword arguments that will be passed to the function call.
Signals are dumped in a suitable format. This format is inferred at the
:class:`Signal` construction time, from the type of the initial value.
In particular, :class:`bool` signals are dumped as single bits. (This
only works starting with Python 2.3, when :class:`bool` has become a
separate type). Likewise, :class:`intbv` signals with a defined bit
width are dumped as bit vectors. To support the general case, other
types of signals are dumped as a string representation, as returned by
the standard :func:`str()` function.
[warning] Support for literal string representations is not part of the
VCD standard. It is specific to **gtkwave**. To generate a standard VCD
file, you need to use signals with a defined bit width only.
Enumeration types
=================
It is often desirable to define a set of identifiers. A standard Python
idiom for this purpose is to assign a range of integers to a tuple of
identifiers, like so:
::
>>> SEARCH, CONFIRM, SYNC = range(3)
>>> CONFIRM
1
However, this technique has some drawbacks. Though it is clearly the
intention that the identifiers belong together, this information is lost
as soon as they are defined. Also, the identifiers evaluate to integers,
whereas a string representation of the identifiers would be preferable.
To solve these issues, we need an *enumeration type*.
MyHDL 0.3 supports enumeration types by providing a function
:func:`enum()`. The arguments to :func:`enum()` are the string
representations of the identifiers, and its return value is an
enumeration type. The identifiers are available as attributes of the
type. For example:
::
>>> from myhdl import enum
>>> t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
>>> t_State
<Enum: SEARCH, CONFIRM, SYNC>
>>> t_State.CONFIRM
CONFIRM
Enumeration types are often used for the state variable in a finite
state machine. In the waveform in
Section \ `1 <#vcd-output-for-waveform-viewing>`__, you see a
:class:`Signal` called ``state``. Note how the waveforms show the string
representation of the enumeration type identifiers The ``state`` signal
has been constructed with an enumeration type identifier as its initial
value, as follows:
::
state = Signal(t_State.SEARCH)
Inferring the sensitivity list for combinatorial logic
======================================================
In MyHDL, combinatorial logic is described by a generator function with
a sensitivity list that contains all inputs signals (the signals that
are read inside the function).
It may be easy to forget some input signals, especially it there are a
lot of them or if the code is being modified. There are various ways to
solve this. One way is to use a sophisticated editor. Another way is
direct language support. For example, recent versions of Verilog have
the ``always @*`` construct, that infers all input signals. The
SystemVerilog 3.1 standard improves on this by introducing the
``always_comb`` block with slightly enhanced semantics.
MyHDL 0.3 provides a function called :func:`always_comb()` which is
named and modeled after the SystemVerilog counterpart.
:func:`always_comb()` takes a classic local function as its argument.
This function should specify the combinatorial logic behavior.
:func:`always_comb()` returns a generator that is sensitive to all
inputs, and that will run the function whenever an input changes.
For example, suppose that we have a mux module described as follows:
::
def mux(z, a, b, sel):
""" Multiplexer.
z -- mux output
a, b -- data inputs
sel -- control input
"""
def logic()
while 1:
yield a, b, sel
if sel == 1:
z.next = a
else:
z.next = b
mux_logic = logic()
return mux_logic
Using :func:`always_comb()`, we can describe it as follows instead:
::
def mux(z, a, b, sel):
""" Multiplexer.
z -- mux output
a, b -- data inputs
sel -- control input
"""
def logic()
if sel == 1:
z.next = a
else:
z.next = b
mux_logic = always_comb(logic)
return mux_logic
Note that in the first version, the sensitivity list is at the beginning
of the generator function code. This is traditionally done in
synthesizable RTL style modeling. However, the semantics of this style
are not entirely correct: at the start of the simulation, the
combinatorial output will not reflect the initial state of the inputs.
:func:`always_comb()` solves this by putting the sensitivity list at the
end of the code.
Inferring the list of instances
===============================
In MyHDL, the instances defined in a top level function need to be
returned explicitly. The following is a schematic example:
::
def top(...):
...
instance_1 = module_1(...)
instance_2 = module_2(...)
...
instance_n = module_n(...)
...
return instance_1, instance_2, ... , instance_n
It may be convenient to assemble the list of instances automatically,
especially if there are many instances. For this purpose, MyHDL 0.3
provides the function :func:`instances()`. It is used as follows:
::
from myhdl import instances
def top(...):
...
instance_1 = module_1(...)
instance_2 = module_2(...)
...
instance_n = module_n(...)
...
return instances()
Function :func:`instances()` uses introspection to inspect the type of
the local variables defined by the calling function. All variables that
comply with the definition of an instance are assembled in a list, and
that list is returned.
Inferring the list of processes
===============================
In addition to instances, a top level function may also define local
generators functions, which I will call *processes* because of the
analogy with VHDL. Like instances, processes need to be returned
explicitly, with the qualification that they have to be called first to
turn them into generators. The following is a schematic example:
::
def top(...):
...
def process_1():
...
def process_2():
...
...
def process_n():
...
...
return process_1(), process_2(), ..., process_n()
As for instances, it may be more convenient to assemble the list of
processes automatically. One option is to turn each process into an
instance by calling it and assigning the returned generator to a local
variable. Those instances will then be found by the :func:`instances()`
function described in
Section \ `4 <#inferring-the-list-of-instances>`__.
Another option is to use the function :func:`processes()` provided by
MyHDL 0.3. This function uses introspection to find the processes, calls
each of them, and assembles the returned generators into a list. It can
be used as follows:
::
from myhdl import processes
def top(...):
...
def process_1():
...
def process_2():
...
...
def process_n():
...
...
return processes()
To conclude, a top level function with both instances and processes can
use the following idiomatic code to return all of them:
::
return instances(), processes()
Class :class:`intbv` enhancements
=================================
Class :class:`intbv` has been enhanced with new features.
It is now possible to leave the left index of a slicing operation
unspecified. The meaning is to access “all” higher order bits. For
example:
::
>>> from myhdl import intbv
>>> n = intbv()
>>> hex(n)
'0x0'
>>> n[:] = 0xde
>>> hex(n)
'0xde'
>>> n[:8] = 0xfa
>>> hex(n)
'0xfade'
>>> n[8:] = 0xb4
>>> hex(n)
'0xfab4'
:class:`intbv` objects now have ``min`` and ``max`` attributes that can
be specified at construction time. The meaning is that only values
within ``range(min, max)`` are permitted. The default value for these
attributes is ``None``, meaning “infinite”. For example (traceback
output shortened for clarity):
::
>>> n = intbv(min=-17, max=53)
>>> n
intbv(0)
>>> n.min
-17
>>> n.max
53
>>> n[:] = 28
>>> n
intbv(28)
>>> n[:] = -18
Traceback (most recent call last):
....
ValueError: intbv value -18 < minimum -17
>>> n[:] = 53
Traceback (most recent call last):
....
ValueError: intbv value 53 >= maximum 53
When a slice is taken from an :class:`intbv` object, the return value is
a new :class:`intbv` object with a defined bit width. As in Verilog, the
value of the new :class:`intbv` object is always positive, regardless of
the sign of the original value. In addition, the ``min`` and ``max``
attributes are set implicitly:
::
>>> v = intbv()[6:]
>>> v
intbv(0)
>>> v.min
0
>>> v.max
64
Lastly, a small change was implemented with regard to binary operations.
In previous versions, both numeric and bit-wise operations always
returned a new :class:`intbv` object, even in mixed-mode operations with
:class:`int` objects. This has changed: numeric operations return an
:class:`int`, and bitwise operations return a :class:`intbv`. In this
way, the return value corresponds better to the nature of the operation.
Function :func:`concat()`
==========================
In previous versions, the :class:`intbv` class provided a method. This
method is no longer available. Instead, there is now a :func:`concat()`
function that supports a much broader range of objects.
A function is more natural because MyHDL objects of various types can be
concatenated: :class:`intbv` objects with a defined bit width,
:class:`bool` objects, the corresponding signal objects, and bit
strings. All these objects have a defined bit width. Moreover, the first
argument doesnt need to have a defined bit width. It can also be an
unsized :class:`intbv`, an :class:`int`, a :class:`long`, or a
corresponding signal object. Function :func:`concat()` returns an
:class:`intbv` object.
Python 2.3 support
==================
Python 2.3 was released on July 29, 2003, and as of this writing, it is
the latest stable Python release. MyHDL 0.3 works with both Python 2.2
and Python 2.3. In good Python tradition, MyHDL code developed with
Python 2.2 should run without changes or problems in Python 2.3.
In general, I am not that keen on early upgrading. However, as it
happens, the evolution of Python enables features that are really
important or even crucial to MyHDL. Python 2.2 generators are the best
example: they are the cornerstone of MyHDL. But Python 2.3 also has
significant benefits, which I will summarize below.
First, generators and the ``yield`` statement are a default Python 2.3
feature. This means that statements are no longer required.
Second, Python 2.3 has a :class:`bool` type, which is implemented as a
subtype of :class:`int`. For general Python use, the implications are
rather limited - the main difference is that logical result values will
print as ``False`` and ``True`` instead of ``0`` and ``1``. However, in
MyHDL, I can use the :class:`bool` type to infer a bit width. If a
:class:`Signal` is constructed with a :class:`bool` value, it is a
single bit :class:`Signal`. One application is waveform viewing as in
Section \ `1 <#vcd-output-for-waveform-viewing>`__ In the waveform, note
how single bit signals are displayed as level changes. With Python 2.2,
the waveforms of these signals would only show value changes, which is
not as clear for single bits.
Finally, Python 2.3 is significantly faster. MyHDL code runs 2535%
faster in Python 2.3. This is a very nice speedup compared to the small
burden of a straightforward upgrade.
Python is a very stable language, so upgrading to Python 2.3 is
virtually risk free. Given the additional benefits, I recommend
MyHDL users to do so as soon as possible. For the next major
MyHDLrelease, the new features will become required and only Python 2.3
(and higher) will be supported.
.. |image| image:: ../manual/tbfsm.png