mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
729 lines
21 KiB
TeX
729 lines
21 KiB
TeX
\chapter{Introduction to \myhdl\ }
|
|
|
|
\section{A basic \myhdl\ simulation}
|
|
|
|
We will introduce \myhdl\ with a classical \code{Hello World} style
|
|
example. Here are the contents of a \myhdl\ simulation script called
|
|
\file{hello1.py}:
|
|
|
|
\begin{verbatim}
|
|
from myhdl import delay, now, Simulation
|
|
|
|
def sayHello():
|
|
while 1:
|
|
yield delay(10)
|
|
print "%s Hello World!" % now()
|
|
|
|
gen = sayHello()
|
|
sim = Simulation(gen)
|
|
sim.run(30)
|
|
|
|
\end{verbatim}
|
|
|
|
All example code can be found in the distribution directory under
|
|
\file{example/manual}. When we run this simulation, we get the
|
|
following output:
|
|
|
|
\begin{verbatim}
|
|
% python hello1.py
|
|
10 Hello World!
|
|
20 Hello World!
|
|
30 Hello World!
|
|
StopSimulation: Simulated for duration 30
|
|
|
|
\end{verbatim}
|
|
|
|
The first line of the script imports a
|
|
number of objects from the \code{myhdl} package. In good Python style, and
|
|
unlike most other languages, we can only use identifiers that are
|
|
\emph{literally} defined in the source file \footnote{I don't want to
|
|
explain the \samp{import *} syntax}.
|
|
|
|
Next, we define a generator function called
|
|
\code{sayHello}. This is a generator function (as opposed to
|
|
a classic Python function) because it contains a \keyword{yield}
|
|
statement (instead of \keyword{return} statement). In \myhdl{}, a
|
|
\keyword{yield} statement has a similar purpose as a \keyword{wait}
|
|
statement in VHDL: the statement suspends execution of the function,
|
|
while its clauses specify when the function should resume. In this case,
|
|
there is a \code{delay} clause, that specifies the required delay.
|
|
|
|
To make sure that the generator runs ``forever'', we wrap its behavior
|
|
in a \code{while 1} loop. This is a standard Python idiom, and it is
|
|
the \myhdl\ equivalent of the implicit looping behavior of a Verilog
|
|
\keyword{always} block and a VHDL \keyword{process}.
|
|
|
|
In \myhdl{}, the basic simulation objects are generators. Generators
|
|
are created by calling generator functions. For example, variable
|
|
\code{gen} refers to a generator. To simulate this generator, we pass
|
|
it as an argument to a \class{Simulation} object constructor. We then
|
|
run the simulation for the desired amount of time. In \myhdl{}, time
|
|
is modeled as a natural integer.
|
|
|
|
|
|
\section{Concurrent generators and signals}
|
|
|
|
In the previous section, we simulated a single generator. Of course,
|
|
real hardware descriptions are not like that: in fact, they are
|
|
typically massively concurrent. \myhdl\ supports this by allowing an
|
|
arbitrary number of concurrent generators. More specifically, a
|
|
\class{Simulation} constructor can take an arbitrary number of
|
|
arguments, each of which can be a generator or a nested sequence of
|
|
generators.
|
|
|
|
With concurrency comes the problem of deterministic
|
|
communication. Hardware languages use special objects to
|
|
support deterministic communication between concurrent code. \myhdl\
|
|
has a \class{Signal} object which is roughly modeled after VHDL
|
|
signals.
|
|
|
|
We will demonstrate these concepts by extending and modifying our
|
|
first example. We introduce a clock signal, driven by a second
|
|
generator:
|
|
|
|
\begin{verbatim}
|
|
clk = Signal(0)
|
|
|
|
def clkGen():
|
|
while 1:
|
|
yield delay(10)
|
|
clk.next = 1
|
|
yield delay(10)
|
|
clk.next = 0
|
|
|
|
\end{verbatim}
|
|
|
|
The \code{clk} signal is constructed with an initial value
|
|
\code{0}. In the clock generator function \code{clkGen}, it is
|
|
continuously assigned a new value after a certain delay. In \myhdl{},
|
|
the new value of a signal is specified by assigning to its
|
|
\code{next} attribute. This is the \myhdl\ equivalent of VHDL signal
|
|
assignments and Verilog's nonblocking assignments.
|
|
|
|
The \code{sayHello} generator function is modified to wait for a
|
|
rising edge of the clock instead of a delay:
|
|
|
|
\begin{verbatim}
|
|
def sayHello():
|
|
while 1:
|
|
yield posedge(clk)
|
|
print "%s Hello World!" % now()
|
|
|
|
\end{verbatim}
|
|
|
|
Waiting for a clock edge is achieved with a second form of the
|
|
\keyword{yield} statement: \samp{yield posedge(\var{signal})}.
|
|
A \class{Simulation} object will suspend the generator as that point,
|
|
and resume it when there is a rising edge on the signal.
|
|
|
|
The \class{Simulation} is now constructed with 2 generator arguments:
|
|
|
|
\begin{verbatim}
|
|
sim = Simulation(clkGen(), sayHello())
|
|
sim.run(50)
|
|
|
|
\end{verbatim}
|
|
|
|
When we run this simulation, we get:
|
|
|
|
\begin{verbatim}
|
|
% python hello2.py
|
|
10 Hello World!
|
|
30 Hello World!
|
|
50 Hello World!
|
|
StopSimulation: Simulated for duration 50
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
\section{Parameters, instantiations and hierarchy}
|
|
|
|
So far, the generator function examples had no parameters. For
|
|
example, the \code{clk} signal was defined in the enclosing scope of
|
|
the generator functions. To make code reusable we will
|
|
want to pass arguments through a parameter list. For example, we can
|
|
change the clock generator function to make it more general
|
|
and reusable, as follows:
|
|
|
|
\begin{verbatim}
|
|
def clkGen(clock, period=20):
|
|
lowTime = int(period / 2)
|
|
highTime = period - lowTime
|
|
while 1:
|
|
yield delay(lowTime)
|
|
clock.next = 1
|
|
yield delay(highTime)
|
|
clock.next = 0
|
|
|
|
\end{verbatim}
|
|
|
|
The clock signal is now a parameter of the function. Also, the clock
|
|
\var{period} is a parameter with a default value of \code{20}.
|
|
This makes \var{period} an \dfn{optional} parameter; if it is not
|
|
specified in a call, the default value will be used.
|
|
|
|
Similarly, the \code{sayHello} function can be made more general as follows:
|
|
|
|
\begin{verbatim}
|
|
def sayHello(clock, to="World!"):
|
|
while 1:
|
|
yield posedge(clock)
|
|
print "%s Hello %s" % (now(), to)
|
|
|
|
\end{verbatim}
|
|
|
|
We can create any number of generators by calling generator functions
|
|
with the appropriate parameters. This is very similar to the concept of
|
|
\dfn{instantiation} in hardware description languages and we will use
|
|
the same terminology in \myhdl{}. Hierarchy can be modeled by defining
|
|
the instances in a higher-level function, and returning them. For
|
|
example:
|
|
|
|
\begin{verbatim}
|
|
def greetings():
|
|
clk1 = Signal(0)
|
|
clk2 = Signal(0)
|
|
clkGen1 = clkGen(clk1)
|
|
clkGen2 = clkGen(clock=clk2, period=19)
|
|
sayHello1 = sayHello(clock=clk1)
|
|
sayHello2 = sayHello(to="MyHDL", clock=clk2)
|
|
return clkGen1, clkGen2, sayHello1, sayHello2
|
|
|
|
\end{verbatim}
|
|
As in standard Python, positional or named parameter association can
|
|
be used in instantiations, or a mix of both\footnote{All positional
|
|
parameters have to come before any named parameter.}. All these styles
|
|
are demonstrated in the example above. As in hardware description
|
|
languages, named association can be very useful if there are a lot of
|
|
parameters, as the parameter order in the call does not matter in that
|
|
case.
|
|
|
|
To support hierarchy, \class{Simulation} constructor arguments can be
|
|
sequences of generators. More specifically, the return value of a
|
|
higher-level instantiating function can be used as an argument of the
|
|
constructor. For example:
|
|
|
|
\begin{verbatim}
|
|
sim = Simulation(greetings())
|
|
sim.run(50)
|
|
|
|
\end{verbatim}
|
|
|
|
This produces the following output:
|
|
|
|
\begin{verbatim}
|
|
% python greetings.py
|
|
9 Hello MyHDL
|
|
10 Hello World!
|
|
28 Hello MyHDL
|
|
30 Hello World!
|
|
47 Hello MyHDL
|
|
50 Hello World!
|
|
StopSimulation: Simulated for duration 50
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
\section{Bit-oriented operations}
|
|
|
|
Hardware design involves dealing with bits and bit-oriented
|
|
operations. The standard Python type \class{int} has most of the
|
|
desired features, but lacks support for indexing and slicing. For this
|
|
reason, \myhdl\ provides the \class{intbv} class. The name was chosen
|
|
to suggest an integer with bit vector flavor.
|
|
|
|
Class \class{intbv} works transparently as an integer and with other
|
|
integer-like types. Like class \class{int}, it provides access to the
|
|
underlying two's complement representation for bitwise
|
|
operations. In addition, it is a mutable type that provides indexing
|
|
and slicing operations, and some additional bit-oriented support such
|
|
as concatenation.
|
|
|
|
\subsection{Indexing operations}
|
|
\label{gray}
|
|
As an example, we will consider the design of a Gray encoder. The
|
|
following code is a Gray encoder modeled in \myhdl{}:
|
|
|
|
\begin{verbatim}
|
|
def bin2gray(B, G, width):
|
|
""" Gray encoder.
|
|
|
|
B -- input intbv signal, binary encoded
|
|
G -- output intbv signal, Gray encoded
|
|
width -- bit width
|
|
|
|
"""
|
|
while 1:
|
|
yield B
|
|
for i in range(width):
|
|
G.next[i] = B[i+1] ^ B[i]
|
|
|
|
\end{verbatim}
|
|
|
|
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. Moreover, we
|
|
use a third form of the \keyword{yield} statement:
|
|
\samp{yield \var{signal}}. This specifies that the generator should
|
|
resume whenever \var{signal} changes value. This is typically used to
|
|
describe combinatorial logic.
|
|
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~\code{0}.
|
|
|
|
To verify the Gray encoder, we write a test bench that prints input
|
|
and output for all possible input values:
|
|
|
|
\begin{verbatim}
|
|
def testBench(width):
|
|
|
|
B = Signal(intbv(0))
|
|
G = Signal(intbv(0))
|
|
|
|
dut = bin2gray(B, G, width)
|
|
|
|
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())
|
|
|
|
\end{verbatim}
|
|
|
|
We use the conversion function \code{bin} to get a binary
|
|
string representation of the signal values. This function is exported
|
|
by the \code{myhdl} package and complements the standard Python
|
|
\code{hex} and \code{oct} conversion functions.
|
|
|
|
To demonstrate, we set up a simulation for a small width:
|
|
|
|
\begin{verbatim}
|
|
Simulation(testBench(width=3)).run()
|
|
|
|
\end{verbatim}
|
|
|
|
The simulation produces the following output:
|
|
|
|
\begin{verbatim}
|
|
% 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
|
|
|
|
\end{verbatim}
|
|
|
|
\subsection{Slicing operations}
|
|
|
|
For a change, we will use a plain function as an example to illustrate
|
|
slicing. The following function calculates the HEC byte of an ATM
|
|
header.
|
|
|
|
\begin{verbatim}
|
|
from myhdl import intbv
|
|
concat = intbv.concat # shorthand alias
|
|
|
|
COSET = 0x55
|
|
|
|
def calculateHec(header):
|
|
""" Return hec for an ATM header, represented as an intbv.
|
|
|
|
The hec polynomial is 1 + x + x**2 + x**8.
|
|
"""
|
|
hec = intbv(0)
|
|
for bit in header[32:]:
|
|
hec[8:] = concat(hec[7:2],
|
|
bit ^ hec[1] ^ hec[7],
|
|
bit ^ hec[0] ^ hec[7],
|
|
bit ^ hec[7]
|
|
)
|
|
return hec ^ COSET
|
|
|
|
\end{verbatim}
|
|
|
|
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 \emph{leftmost} item. The rightmost index is
|
|
\code{0} by default, and can be omitted from the slice.
|
|
|
|
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
|
|
\code{hex[8:]} has exactly \code{8} bits. Likewise, the slice
|
|
\code{hex[7:2]} has \code{7-2=5} bits. You can think about it as
|
|
follows: for a slice \code{[i:j]}, only bits below index \code{i} are
|
|
included, and the bit with index \code{j} is the last bit included.
|
|
|
|
|
|
\section{Bus-functional procedures}
|
|
|
|
A \dfn{bus-functional procedure} is a reusable encapsulation of the
|
|
low-level operations needed to implement some abstract transaction on
|
|
a physical interface. Bus-functional procedures are typically used in
|
|
flexible verification environments.
|
|
|
|
Once again, \myhdl\ supports bus-functional procedures by generator
|
|
functions. In \myhdl\, the difference between instances and
|
|
bus-functional procedure calls comes from the way in which a generator
|
|
function is used.
|
|
|
|
As an example, we will design a bus-functional procedure of a
|
|
simplified UART transmitter. We assume 8 data bits, no parity bit, and
|
|
a single stop bit, and we add print statements to follow the
|
|
simulation behavior:
|
|
|
|
\begin{verbatim}
|
|
T_9600 = int(1e9 / 9600)
|
|
|
|
def rs232_tx(tx, data, duration=T_9600):
|
|
|
|
""" Simple rs232 transmitter procedure.
|
|
|
|
tx -- serial output data
|
|
data -- input data byte to be transmitted
|
|
duration -- transmit bit duration
|
|
|
|
"""
|
|
|
|
print "-- Transmitting %s --" % hex(data)
|
|
print "TX: start bit"
|
|
tx.next = 0
|
|
yield delay(duration)
|
|
|
|
for i in range(8):
|
|
print "TX: %s" % data[i]
|
|
tx.next = data[i]
|
|
yield delay(duration)
|
|
|
|
print "TX: stop bit"
|
|
tx.next = 1
|
|
yield delay(duration)
|
|
|
|
\end{verbatim}
|
|
|
|
This looks exactly like the generator functions in previous sections. It
|
|
becomes a bus functional procedure when we use it differently. Suppose
|
|
that in a test bench, we want to generate a number of data bytes to be
|
|
transmitted. This can be modeled as follows:
|
|
|
|
|
|
\begin{verbatim}
|
|
testvals = (0xc5, 0x3a, 0x4b)
|
|
|
|
def stimulus():
|
|
tx = Signal(1)
|
|
for val in testvals:
|
|
txData = intbv(val)
|
|
yield rs232_tx(tx, txData)
|
|
|
|
\end{verbatim}
|
|
|
|
We use the bus functional procedure call as a clause in a
|
|
\code{yield} statement. This introduces a fourth form of the
|
|
\code{yield} statement: using a generator as a clause. Although this is
|
|
a more dynamic usage than in the previous cases, the meaning is
|
|
actually very similar. When the calling generator \code{stimulus()}
|
|
encounters the \code{yield} statement, it suspends execution, and the
|
|
clause specifies when it should resume. In this case, the generator
|
|
\code{rs232_tx(tx, txData)} is \dfn{forked}, and the caller resumes
|
|
when the forked generator returns.
|
|
|
|
When simulating this, we get:
|
|
|
|
\begin{verbatim}
|
|
-- Transmitting 0xc5 --
|
|
TX: start bit
|
|
TX: 1
|
|
TX: 0
|
|
TX: 1
|
|
TX: 0
|
|
TX: 0
|
|
TX: 0
|
|
TX: 1
|
|
TX: 1
|
|
TX: stop bit
|
|
-- Transmitting 0x3a --
|
|
TX: start bit
|
|
TX: 0
|
|
TX: 1
|
|
TX: 0
|
|
TX: 1
|
|
...
|
|
|
|
\end{verbatim}
|
|
|
|
We will continue with this example by designing the corresponding UART
|
|
receiver bus-functional procedure. This will allow us to introduce
|
|
further capabilities of \myhdl\ and its use of the \code{yield}
|
|
statement.
|
|
|
|
Until now, the \code{yield} statements had a single clause. However,
|
|
they can have multiple clauses as well. In that case, the calling
|
|
generator is triggered as soon as the condition corresponding to one
|
|
of the clauses is satisfied. This corresponds to the functionality of
|
|
sensitivity lists in Verilog and VHDL.
|
|
|
|
For example, suppose we want to design an UART receive procedure with
|
|
a timeout. We can specify the timeout condition while waiting for the
|
|
start bit, as in the following generator function:
|
|
|
|
\begin{verbatim}
|
|
def rs232_rx(rx, data, duration=T_9600, timeout=MAX_TIMEOUT):
|
|
|
|
""" Simple rs232 receiver procedure.
|
|
|
|
rx -- serial input data
|
|
data -- data received
|
|
duration -- receive bit duration
|
|
|
|
"""
|
|
|
|
# wait on start bit until timeout
|
|
yield negedge(rx), delay(timeout)
|
|
if rx == 1:
|
|
raise StopSimulation, "RX time out error"
|
|
|
|
# sample in the middle of the bit duration
|
|
yield delay(duration // 2)
|
|
print "RX: start bit"
|
|
|
|
for i in range(8):
|
|
yield delay(duration)
|
|
print "RX: %s" % rx
|
|
data[i] = rx
|
|
|
|
yield delay(duration)
|
|
print "RX: stop bit"
|
|
print "-- Received %s --" % hex(data)
|
|
|
|
\end{verbatim}
|
|
|
|
If the timeout condition is triggered, the receive bit \code{rx}
|
|
will still be \code{1}. In that case, we raise an exception to stop
|
|
the simulation. The \code{StopSimulation} exception is predefined in
|
|
\myhdl\ for such purposes. In the other case, we proceed by
|
|
positioning the sample point in the middle of the bit duration, and
|
|
sampling the received data bits.
|
|
|
|
When a \code{yield} statement has multiple clauses, they can be of any
|
|
type that is supported as a single clause, including generators. For
|
|
example, we can verify the transmitter and receiver generator against
|
|
each other by yielding them together, as follows:
|
|
|
|
\begin{verbatim}
|
|
def test():
|
|
tx = Signal(1)
|
|
rx = tx
|
|
rxData = intbv(0)
|
|
for val in testvals:
|
|
txData = intbv(val)
|
|
yield rs232_rx(rx, rxData), rs232_tx(tx, txData)
|
|
|
|
\end{verbatim}
|
|
|
|
Both forked generators will run concurrently, and the calling
|
|
generator will resume as soon as one of them finishes (which will be
|
|
the transmitter in this case). The simulation output shows how
|
|
the UART procedures run in lockstep:
|
|
|
|
\begin{verbatim}
|
|
-- Transmitting 0xc5 --
|
|
TX: start bit
|
|
RX: start bit
|
|
TX: 1
|
|
RX: 1
|
|
TX: 0
|
|
RX: 0
|
|
TX: 1
|
|
RX: 1
|
|
TX: 0
|
|
RX: 0
|
|
TX: 0
|
|
RX: 0
|
|
TX: 0
|
|
RX: 0
|
|
TX: 1
|
|
RX: 1
|
|
TX: 1
|
|
RX: 1
|
|
TX: stop bit
|
|
RX: stop bit
|
|
-- Received 0xc5 --
|
|
-- Transmitting 0x3a --
|
|
TX: start bit
|
|
RX: start bit
|
|
TX: 0
|
|
RX: 0
|
|
...
|
|
|
|
\end{verbatim}
|
|
|
|
For completeness, we will verify the timeout behavior with a test
|
|
bench that disconnects the \code{rx} from the \code{tx} signal, and we
|
|
specify a small timeout for the receive procedure:
|
|
|
|
\begin{verbatim}
|
|
def testTimeout():
|
|
tx = Signal(1)
|
|
rx = Signal(1)
|
|
rxData = intbv(0)
|
|
for val in testvals:
|
|
txData = intbv(val)
|
|
yield rs232_rx(rx, rxData, timeout=4*T_9600-1), rs232_tx(tx, txData)
|
|
|
|
\end{verbatim}
|
|
|
|
The simulation now stops with a timeout exception after a few
|
|
transmit cycles:
|
|
|
|
\begin{verbatim}
|
|
-- Transmitting 0xc5 --
|
|
TX: start bit
|
|
TX: 1
|
|
TX: 0
|
|
TX: 1
|
|
StopSimulation: RX time out error
|
|
|
|
\end{verbatim}
|
|
|
|
Recall that the calling generator resumes as soon as one of the
|
|
forked generators returns. In the previous cases, this is just fine,
|
|
as the transmitter and receiver generators run in lockstep. However,
|
|
it may be desirable to resume the caller only when \emph{all} of the
|
|
forked generators have finished. For example, suppose that we want to
|
|
characterize the robustness of the transmitter and receiver design to
|
|
bit duration differences. We can adapt our test bench as follows, to
|
|
run the transmitter at a faster rate:
|
|
|
|
\begin{verbatim}
|
|
T_10200 = int(1e9 / 10200)
|
|
|
|
def testNoJoin():
|
|
tx = Signal(1)
|
|
rx = tx
|
|
rxData = intbv(0)
|
|
for val in testvals:
|
|
txData = intbv(val)
|
|
yield rs232_rx(rx, rxData), rs232_tx(tx, txData, duration=T_10200)
|
|
|
|
\end{verbatim}
|
|
|
|
Simulating this shows how the transmission of the new byte starts
|
|
before the previous one is received, potentially creating additional
|
|
transmission errors:
|
|
|
|
\begin{verbatim}
|
|
-- Transmitting 0xc5 --
|
|
TX: start bit
|
|
RX: start bit
|
|
...
|
|
TX: 1
|
|
RX: 1
|
|
TX: 1
|
|
TX: stop bit
|
|
RX: 1
|
|
-- Transmitting 0x3a --
|
|
TX: start bit
|
|
RX: stop bit
|
|
-- Received 0xc5 --
|
|
RX: start bit
|
|
TX: 0
|
|
|
|
\end{verbatim}
|
|
|
|
It is more likely that we want to characterize this on a byte by byte
|
|
basis, and align the two generators before transmitting each byte. In
|
|
\myhdl{}, this can be done with the \function{join} function. By
|
|
joining clauses together in a \code{yield} statement, we create a new
|
|
clause that triggers only when all of its argument clauses have
|
|
triggered. For example, we can adapt the test bench as follows:
|
|
|
|
\begin{verbatim}
|
|
def testJoin():
|
|
tx = Signal(1)
|
|
rx = tx
|
|
rxData = intbv(0)
|
|
for val in testvals:
|
|
txData = intbv(val)
|
|
yield join(rs232_rx(rx, rxData), rs232_tx(tx, txData, duration=T_10200))
|
|
|
|
\end{verbatim}
|
|
|
|
Now, transmission of a new byte only starts when the previous one is received:
|
|
|
|
\begin{verbatim}
|
|
-- Transmitting 0xc5 --
|
|
TX: start bit
|
|
RX: start bit
|
|
...
|
|
TX: 1
|
|
RX: 1
|
|
TX: 1
|
|
TX: stop bit
|
|
RX: 1
|
|
RX: stop bit
|
|
-- Received 0xc5 --
|
|
-- Transmitting 0x3a --
|
|
TX: start bit
|
|
RX: start bit
|
|
TX: 0
|
|
RX: 0
|
|
|
|
\end{verbatim}
|
|
|
|
\section{\myhdl\ and Python}
|
|
|
|
To conclude this introductory chapter, it is useful to stress that
|
|
\myhdl\ is not a language. The language is Python, and \myhdl\ is
|
|
implemented as a Python package called \code{myhdl}. Moreover, it is
|
|
a design goal to keep the \code{myhdl} package as minimalistic as
|
|
possible, so that \myhdl\ descriptions are very much ``pure Python''.
|
|
|
|
To have Python as the underlying language is significant in several
|
|
ways:
|
|
|
|
\begin{itemize}
|
|
|
|
\item Python is a very powerful high level language. This translates
|
|
into high productivity and elegant solutions to complex problems.
|
|
|
|
\item Python is continuously improved by some very clever
|
|
minds, supported by a large and fast growing user base. Python profits
|
|
fully from the open source development model.
|
|
|
|
\item Python comes with an extensive standard library. Some
|
|
functionality is likely to be of direct interest to \myhdl\ users:
|
|
examples include string handling, regular expressions, random number
|
|
generation, unit test support, operating system interfacing and GUI
|
|
development. In addition, there are modules for mathematics, database
|
|
connections, networking programming, internet data handling, and so
|
|
on.
|
|
|
|
\item Python has a powerful C extension model. All built-in types are
|
|
written with the same C API that is available for custom
|
|
extensions. To a module user, there is no difference between a
|
|
standard Python module and a C extension module --- except
|
|
performance. The typical Python development model is to prototype
|
|
everything in Python until the application is stable, and (only) then
|
|
rewrite performance critical modules in C if necessary.
|
|
|
|
\end{itemize}
|
|
|
|
|
|
|
|
|
|
|
|
|