1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00

Rewrote chapter completely, example code snippets only

This commit is contained in:
Jan Decaluwe 2016-05-18 14:17:25 +02:00
parent 18d0fe0989
commit 095eb040e7

View File

@ -29,14 +29,13 @@ representation for bitwise operations. However, unlike :class:`int`, it is
a mutable type. This means that its value can be changed after object a mutable type. This means that its value can be changed after object
creation, through methods and operators such as slice assignment. creation, through methods and operators such as slice assignment.
:class:`intbv` supports the same operators as :class:`int` for arithmetic. :class:`intbv` supports the same operators as :class:`int` for arithmetic. In
In addition, it provides a number of features to make it addition, it provides a number of features to make it suitable for hardware
suitable for hardware design. First, the range of allowed values can design. First, the range of allowed values can be constrained. This makes it
be constrained. This makes it possible to check the value at run time possible to check the value at run time during simulation. Moreover, back end
during simulation. Moreover, back end tools can determine the smallest tools can determine the smallest possible bit width for representing the object.
possible bit width for representing the object. Secondly, it supports bit level operations by providing an indexing and slicing
Secondly, it supports bit level operations by providing an indexing interface.
and slicing interface.
:class:`intbv` objects are constructed in general as follows:: :class:`intbv` objects are constructed in general as follows::
@ -46,12 +45,12 @@ and slicing interface.
the value. Following the Python conventions, *min* is inclusive, and the value. Following the Python conventions, *min* is inclusive, and
*max* is exclusive. Therefore, the allowed value range is *min* .. *max*-1. *max* is exclusive. Therefore, the allowed value range is *min* .. *max*-1.
Let's us look at some examples. First, an unconstrained :class:`intbv` Let's look at some examples. An unconstrained :class:`intbv` object is created
object is created as follows: as follows::
>>> a = intbv(24) >>> a = intbv(24)
.. index:: .. index::
single: intbv; min single: intbv; min
single: intbv; max single: intbv; max
single: intbv; bit width single: intbv; bit width
@ -60,12 +59,14 @@ After object creation, *min* and *max* are available as attributes for
inspection. Also, the standard Python function :func:`len` can be used inspection. Also, the standard Python function :func:`len` can be used
to determine the bit width. If we inspect the previously created to determine the bit width. If we inspect the previously created
object, we get:: object, we get::
>>> print a.min >>> a
intbv(24)
>>> print(a.min)
None None
>>> print a.max >>> print(a.max)
None None
>>> print len(a) >>> len(a)
0 0
As the instantiation was unconstrained, the *min* and *max* attributes As the instantiation was unconstrained, the *min* and *max* attributes
@ -76,9 +77,10 @@ A constrained :class:`intbv` object is created as follows:
>>> a = intbv(24, min=0, max=25) >>> a = intbv(24, min=0, max=25)
Inspecting the object now gives:: Inspecting the object now gives::
>>> a
intbv(24)
>>> a.min >>> a.min
0 0
>>> a.max >>> a.max
@ -89,55 +91,21 @@ Inspecting the object now gives::
We see that the allowed value range is 0 .. 24, and that 5 bits are We see that the allowed value range is 0 .. 24, and that 5 bits are
required to represent the object. required to represent the object.
Sometimes hardware engineers prefer to constrain an object by defining The *min* and *max* bound attributes enable fine-grained control and error
its bit width directly, instead of the range of allowed values. checking of the value range. In particular, the bound values do not have to be
The following example shows how to do that:: symmetric or powers of 2. In all cases, the bit width is set appropriately to
represent the values in the range. For example::
>>> a = intbv(24)[5:] >>> a = intbv(6, min=0, max=7)
>>> len(a)
What actually happens here is that first an unconstrained :class:`intbv` 3
is created, which is then sliced. Slicing an :class:`intbv` returns a new >>> a = intbv(6, min=-3, max=7)
:class:`intbv` with the constraints set up appropriately. >>> len(a)
Inspecting the object now shows:: 4
>>> a = intbv(6, min=-13, max=7)
>>> a.min
0
>>> a.max
32
>>> len(a) >>> len(a)
5 5
Note that the *max* attribute is 32, as with 5 bits it is possible to represent
the range 0 .. 31. Creating an :class:`intbv` this way has the disadvantage
that only positive value ranges can be specified. Slicing is described in more
detail in :ref:`hwtypes-slicing`.
To summarize, there are two ways to constrain an :class:`intbv` object: by
defining its bit width, or by defining its value range. The bit
width method is more traditional in hardware design. However, there
are two reasons to use the range method instead: to represent
negative values as observed above, and for fine-grained control over the
value range.
Fine-grained control over the value range permits better error
checking, as there is no need for the *min* and *max* bounds
to be symmetric or powers of 2. In all cases, the bit width
is set appropriately to represent all values in
the range. For example::
>>> a = intbv(6, min=0, max=7)
>>> len(a)
3
>>> a = intbv(6, min=-3, max=7)
>>> len(a)
4
>>> a = intbv(6, min=-13, max=7)
>>> len(a)
5
.. _hwtypes-indexing: .. _hwtypes-indexing:
Bit indexing Bit indexing
@ -145,135 +113,102 @@ Bit indexing
.. index:: single: bit indexing .. index:: single: bit indexing
As an example, we will consider the design of a Gray encoder. The following code A common requirement in hardware design is access to the individual bits. The
is a Gray encoder modeled in MyHDL:: :class:`intbv` class implements an indexing interface that provides access to
the bits of the underlying two's complement representation. The following
illustrates bit index read access::
from myhdl import Signal, delay, Simulation, always_comb, instance, intbv, bin >>> from myhdl import bin
>>> a = intbv(24)
>>> bin(a)
'11000'
>>> int(a[0])
0
>>> int(a[3])
1
>>> b = intbv(-23)
>>> bin(b)
'101001'
>>> int(b[0])
1
>>> int(b[3])
1
>>> int(b[4])
0
def bin2gray(B, G, width): We use the :func:`bin` function provide by MyHDL because it shows the two's
""" Gray encoder. complement representation for negative values, unlike Python's builtin with the
same name. Note that lower indices correspond to less significant bits. The
B -- input intbv signal, binary encoded following code illustrates bit index assignment::
G -- output intbv signal, gray encoded
width -- bit width
"""
@always_comb
def logic():
for i in range(width):
G.next[i] = B[i+1] ^ B[i]
return logic
This code introduces a few new concepts. The string in triple quotes at the
start of the function is a :dfn:`doc string`. This is standard Python practice
for structured documentation of code.
.. index::
single: decorator; always_comb
single: wait; for a signal value change
single: combinatorial logic
Furthermore, we introduce a third decorator: :func:`always_comb`. It is used
with a classic function and specifies that the resulting generator should wait
for a value change on any input signal. This is typically used to describe
combinatorial logic. The :func:`always_comb` decorator automatically infers
which signals are used as inputs.
Finally, the code contains bit indexing operations and an exclusive-or operator
as required for a Gray encoder. By convention, the lsb of an :class:`intbv`
object has index ``0``.
To verify the Gray encoder, we write a test bench that prints input and output
for all possible input values::
def testBench(width):
B = Signal(intbv(0))
G = Signal(intbv(0))
dut = bin2gray(B, G, width)
@instance
def stimulus():
for i in range(2**width):
B.next = intbv(i)
yield delay(10)
print "B: " + bin(B, width) + "| G: " + bin(G, width)
return dut, stimulus
We use the conversion function :func:`bin` to get a binary string representation of
the signal values. This function is exported by the :mod:`myhdl` package and
supplements the standard Python :func:`hex` and :func:`oct` conversion functions.
As a demonstration, we set up a simulation for a small width::
sim = Simulation(testBench(width=3))
sim.run()
The simulation produces the following output::
% python bin2gray.py
B: 000 | G: 000
B: 001 | G: 001
B: 010 | G: 011
B: 011 | G: 010
B: 100 | G: 110
B: 101 | G: 111
B: 110 | G: 101
B: 111 | G: 100
StopSimulation: No more events
>>> bin(a)
'11000'
>>> a[3] = 0
>>> bin(a)
'10000'
>>> a
intbv(16)
>>> b
intbv(-23)
>>> bin(b)
'101001'
>>> b[3] = 0
>>> bin(b)
'100001'
>>> b
intbv(-31)
.. _hwtypes-slicing: .. _hwtypes-slicing:
Bit slicing Bit slicing
=========== ===========
.. index:: .. index::
single: bit slicing single: bit slicing
single: concat(); example usage
For a change, we will use a traditional function as an example to illustrate The :class:`intbv` type also supports bit slicing, for both read access
slicing. The following function calculates the HEC byte of an ATM header. :: assignment. For example::
from myhdl import intbv, concat >>> a = intbv(24)
>>> bin(a)
'11000'
>>> a[4:1]
intbv(4)
>>> bin(a[4:1])
'100'
>>> a[4:1] = 0b001
>>> bin(a)
'10010'
>>> a
intbv(18)
COSET = 0x55 In accordance with the most common hardware convention, and unlike standard
Python, slicing ranges are downward. As in standard Python, the slicing range
is half-open: the highest index bit is not included. Unlike standard Python
however, this index corresponds to the *leftmost* item.
def calculateHec(header): Both indices can be omitted from the slice. If the rightmost index is omitted,
""" Return hec for an ATM header, represented as an intbv. it is ``0`` by default. If the leftmost index is omitted, the meaning is to
access "all" higher order bits. For example::
The hec polynomial is 1 + x + x**2 + x**8. >>> bin(a)
""" '11000'
hec = intbv(0) >>> bin(a[4:])
for bit in header[32:]: '1000'
hec[8:] = concat(hec[7:2], >>> a[4:] = '0001'
bit ^ hec[1] ^ hec[7], >>> bin(a)
bit ^ hec[0] ^ hec[7], '10001'
bit ^ hec[7] >>> a[:] = 0b10101
) >>> bin(a)
return hec ^ COSET '10101'
The code shows how slicing access and assignment is supported on the
:class:`intbv` data type. In accordance with the most common hardware
convention, and unlike standard Python, slicing ranges are downward. The code
also demonstrates concatenation of :class:`intbv` objects.
As in standard Python, the slicing range is half-open: the highest index bit is
not included. Unlike standard Python however, this index corresponds to the
*leftmost* item. Both indices can be omitted from the slice. If the leftmost
index is omitted, the meaning is to access "all" higher order bits. If the
rightmost index is omitted, it is ``0`` by default.
The half-openness of a slice may seem awkward at first, but it helps to avoid The half-openness of a slice may seem awkward at first, but it helps to avoid
one-off count issues in practice. For example, the slice ``hex[8:]`` has exactly one-off count issues in practice. For example, the slice ``a[8:]`` has exactly
``8`` bits. Likewise, the slice ``hex[7:2]`` has ``7-2=5`` bits. You can think ``8`` bits. Likewise, the slice ``a[7:2]`` has ``7-2=5`` bits. You can think
about it as follows: for a slice ``[i:j]``, only bits below index ``i`` are about it as follows: for a slice ``[i:j]``, only bits below index ``i`` are
included, and the bit with index ``j`` is the last bit included. included, and the bit with index ``j`` is the last bit included.
When an :class:`intbv` object is sliced, a new :class:`intbv` object is returned. When an :class:`intbv` object is sliced, a new :class:`intbv` object is returned.
This new :class:`intbv` object is always positive, and the value bounds are This new :class:`intbv` object is always positive, and the value bounds are
set up in accordance with the bit width specified by the slice. For example:: set up in accordance with the bit width specified by the slice. For example::
@ -281,7 +216,7 @@ set up in accordance with the bit width specified by the slice. For example::
>>> len(a) >>> len(a)
4 4
>>> b = a[4:] >>> b = a[4:]
>>> b >>> b
intbv(6L) intbv(6L)
>>> len(b) >>> len(b)
4 4
@ -295,8 +230,8 @@ The returned object has the same value and bit width, but its value
range consists of all positive values that can be represented by range consists of all positive values that can be represented by
the bit width. the bit width.
The object returned by a slice is positive, even when the The object returned by a slice is positive, even when the original object is
original object is negative:: negative::
>>> a = intbv(-3) >>> a = intbv(-3)
>>> bin(a, width=5) >>> bin(a, width=5)
@ -307,8 +242,31 @@ original object is negative::
>>> bin(b) >>> bin(b)
'11101' '11101'
The bit pattern of the two objects is identical within the bit width, In this example, the bit pattern of the two objects is identical within the bit
but their values have opposite sign. width, but their values have opposite sign.
Sometimes hardware engineers prefer to constrain an object by defining its bit
width directly, instead of the range of allowed values. Using the slicing
properties of the :class:`intbv` class one can do that as follows::
>>> a = intbv(24)[5:]
What actually happens here is that first an unconstrained :class:`intbv`
is created, which is then sliced. Slicing an :class:`intbv` returns a new
:class:`intbv` with the constraints set up appropriately.
Inspecting the object now shows::
>>> a.min
0
>>> a.max
32
>>> len(a)
5
Note that the *max* attribute is 32, as with 5 bits it is possible to represent
the range 0 .. 31. Creating an :class:`intbv` this way is convenient but has
the disadvantage that only positive value ranges between 0 and a power of 2 can
be specified.
.. _hwtypes-modbv: .. _hwtypes-modbv:
@ -363,7 +321,7 @@ In a typical case when ``min==0``, this reduces to::
Unsigned and signed representation Unsigned and signed representation
================================== ==================================
.. index:: .. index::
single: intbv; intbv.signed single: intbv; intbv.signed
:class:`intbv` is designed to be as high level as possible. The underlying :class:`intbv` is designed to be as high level as possible. The underlying
@ -402,7 +360,7 @@ bit width. For this purpose, :class:`intbv` provides the
>>> bin(b, width=4) >>> bin(b, width=4)
'1100' '1100'
:meth:`intbv.signed` extends the msb bit into the higher-order bits of the :meth:`intbv.signed` extends the msb bit into the higher-order bits of the
underlying object value, and returns the result as an integer. underlying object value, and returns the result as an integer.
Naturally, for a "signed" the return value will always be identical Naturally, for a "signed" the return value will always be identical
to the original value, as it has the sign bit already. to the original value, as it has the sign bit already.
@ -420,5 +378,3 @@ the data bus and convert them as follows::
real.next = data_bus[8:4].signed() real.next = data_bus[8:4].signed()
imag.next = data_bus[4:].signed() imag.next = data_bus[4:].signed()