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

partial checkin

This commit is contained in:
jand 2005-12-09 14:58:42 +00:00
parent 4c78b0821c
commit f1a73b4923
3 changed files with 256 additions and 150 deletions

View File

@ -17,13 +17,17 @@ see \url{http://www.python.org/doc/Newbies.html}.
A working knowledge of a hardware description language such as Verilog A working knowledge of a hardware description language such as Verilog
or VHDL is helpful. or VHDL is helpful.
\section{A small tutorial on generators \label{tutorial}} Code examples in this manual are sometimes shortened for clarity.
\index{generators!tutorial on|(} Complete executable examples can be found in the distribution directory at
\file{example/manual/}.
Generators are a recent Python feature, introduced in \section{A small tutorial on generators \label{tutorial}}
Python~2.2. Therefore, there isn't a lot of tutorial material \index{generators!tutorial on}
available yet. Because generators are the key concept in
\myhdl{}, I include a small tutorial here. Generators are a relatively recent Python feature. They
were introduced in Python~2.2.
Because generators are the key concept in
\myhdl{}, a small tutorial is included a here.
Consider the following nonsensical function: Consider the following nonsensical function:
@ -113,19 +117,49 @@ statements work as generalized
\index{sensitivity list}% \index{sensitivity list}%
sensitivity lists. sensitivity lists.
If you want to know more about generators, consult the on-line Python For more info about generators, consult the on-line Python
documentation, e.g. at \url{http://www.python.org/doc/2.2.2/whatsnew}. documentation, e.g. at \url{http://www.python.org/doc/2.2.2/whatsnew}.
\section{About decorators \label{deco}}
\index{decorators!about}
Python 2.4 introduced a new feature called decorators. MyHDL 0.5 defines
a number of decorators to facilitate hardware descriptions, but many users may
not be familiar with the concept. Therefore, an introduction
is included here.
A decorator consists of special syntax in front of a function
declaration. It refers to a decorator function. The decorator
function automatically transforms the declared function into some
other callable object.
A decorator function \function{deco} is used in a decorator statement as follows:
\begin{verbatim}
@deco
def func(arg1, arg2, ...):
<body>
This code is equivalent to the following template:
def func(arg1, arg2, ...):
<body>
func = deco(func)
\end{verbatim}
Note that the decorator statement goes directly in front of the
function declaration, and that the function name func is automatically
reused.
MyHDL 0.5 uses decorators to create ready-to-simulate generators
from local (embedded) function definitions. Their functionality
and usage will be described extensively in this manual.
For more info about Python decorators, consult the on-line Python
documentation, e.g. at \url{http://www.python.org/doc/2.4/whatsnew/node6.html}.
\begin{notice}[warning] \begin{notice}[warning]
As mentioned earlier, generators were introduced in Python~2.2. In Because MyHDL 0.5 uses decorators, it requires Python 2.4 or a
that version, they were introduced as a ``future'' feature that has to later version.
be enabled explicitly. In Python~2.3, which is the latest stable
Python version at the time of this writing, generators are enabled by
default.
Besides generators, Python~2.3 has several other interesting new
features, and it runs 25--35\% faster than Python~2.2. For these
reasons, \myhdl\ requires Python~2.3.
\end{notice} \end{notice}
\index{generators!tutorial on|)}

View File

@ -3,177 +3,229 @@
\section{A basic \myhdl\ simulation \label{intro-basic}} \section{A basic \myhdl\ simulation \label{intro-basic}}
We will introduce \myhdl\ with a classic \code{Hello World} style We will introduce \myhdl\ with a classic \code{Hello World} style
example. Here are the contents of a \myhdl\ simulation script called example. All example code can be found in the distribution directory
\file{hello1.py}: under \file{example/manual}. Here are the contents of a \myhdl\
simulation script called \file{hello1.py}:
\begin{verbatim} \begin{verbatim}
from myhdl import delay, now, Simulation from myhdl import Signal, delay, always, now, Simulation
def sayHello(): def HelloWorld():
while 1:
yield delay(10) @always(delay(10))
def sayHello():
print "%s Hello World!" % now() print "%s Hello World!" % now()
gen = sayHello() return sayHello
sim = Simulation(gen)
inst = HelloWorld()
sim = Simulation(inst)
sim.run(30) sim.run(30)
\end{verbatim} \end{verbatim}
All example code can be found in the distribution directory under When we run this simulation, we get the following output:
\file{example/manual}. When we run this simulation, we get the
following output:
\begin{verbatim} \begin{verbatim}
% python hello1.py % python hello1.py
10 Hello World! 10 Hello World!
20 Hello World! 20 Hello World!
30 Hello World! 30 Hello World!
StopSimulation: Simulated for duration 30 _SuspendSimulation: Simulated 30 timesteps
\end{verbatim} \end{verbatim}
The first line of the script imports a number of objects from the The first line of the script imports a number of objects from the
\code{myhdl} package. In good Python style, and unlike most other \code{myhdl} package. In Python we can only use identifiers that are
languages, we can only use identifiers that are literally defined in the source file
\emph{literally} defined in the source file
\footnote{The exception is the \samp{from module import *} syntax, \footnote{The exception is the \samp{from module import *} syntax,
that imports all the symbols from a module. Although this is generally that imports all the symbols from a module. Although this is generally
considered bad practice, it can be tolerated for large modules that considered bad practice, it can be tolerated for large modules that
export a lot of symbols. One may argue that export a lot of symbols. One may argue that
\code{myhdl} falls into that category.}. \code{myhdl} falls into that category.}.
Next, we define a generator function called Then, we define a function called \function{HelloWorld}. In MyHDL,
\code{sayHello}. This is a generator function (as opposed to classic functions are used to model hardware modules. In particular,
a classic Python function) because it contains a \keyword{yield} the parameter list is used to define the interface. In this first
statement (instead of \keyword{return} statement). example, the interface is empty.
When called, a generator function returns a \dfn{generator},
which is the basic simulation object in \myhdl{}.
The \keyword{yield} statement in \myhdl{} has a similar meaning as Inside the top level function we declared a local function called
the \keyword{wait} statement in VHDL: the statement suspends execution \function{sayHello} that defines the desired behavior. This function
of a generator, and its clauses specify the conditions on which the is decorated with an \function{@always} decorator that has a delay
generator should wait before resuming. In this case, it should object as its parameter. The meaning is that the function will be
\index{wait!for a delay}% executed whenever the specified delay has expired.
wait for a delay.
To make sure that a generator runs ``forever'', we wrap its behavior Behind the curtains, the \function{@always} decorator creates a Python
in a \code{while 1} loop. This is a standard Python idiom, and it is \emph{generator} and reuses the name of the decorated function for
the \myhdl\ equivalent of the implicit looping behavior of a it. Generators are the fundamental objects in MyHDL, and we will say
\index{Verilog!always block}% much more about them further on.
Verilog \keyword{always} block
\index{VHDL!process}%
and a VHDL \keyword{process}.
In the example, variable Finally, the top level function returns the local generator. This code
\code{gen} refers to a generator. To simulate it, we pass pattern is the simplest incarnation of the basic MyHDL code pattern
it as an argument to a \class{Simulation} object constructor. We then to define the contents of a hardware module. We will describe the
run the simulation for the desired amount of time. In \myhdl{}, time general case further on.
is modeled as a natural integer.
In MyHDL, we create an \emph{instance} of a hardware module by calling
the corresponding function. In the example, variable \code{inst} refers
to an instance of \function{HelloWorld}. To simulate the instance, we
pass it as an argument to a \class{Simulation} object constructor. We
then run the simulation for the desired amount of timesteps.
\section{Concurrent generators and signals \label{intro-conc}} \section{Signals, ports, and concurrency \label{intro-conc}}
In the previous section, we simulated a single generator. Of course, In the previous section, we simulated a design that consisted
real hardware descriptions are not like that: in fact, they are of a single generator. Of course,
real hardware descriptions are not like that: they are
typically massively concurrent. \myhdl\ supports this by allowing an typically massively concurrent. \myhdl\ supports this by allowing an
arbitrary number of concurrent generators. arbitrary number of concurrent generators.
With concurrency comes the problem of deterministic With concurrency comes the problem of deterministic
communication. Hardware languages use special objects to communication. Hardware languages use special objects to
support deterministic communication between concurrent code. \myhdl\ support deterministic communication between concurrent code.
For this purpose \myhdl\
has a \class{Signal} object which is roughly modeled after VHDL has a \class{Signal} object which is roughly modeled after VHDL
signals. signals.
We will demonstrate these concepts by extending and modifying our We will demonstrate the use of signals and the concept of concurrency
first example. We introduce a clock signal, driven by a second by extending and modifying our first example. We define two hardware
generator: modules, one that drives a clock signal, and one that is sensitive
to a positive edge on a clock signal:
\begin{verbatim} \begin{verbatim}
clk = Signal(0) from myhdl import Signal, delay, always, now, Simulation
def clkGen():
while 1: def ClkDriver(clk):
yield delay(10)
clk.next = 1 @always(delay(10))
yield delay(10) def driveClk():
clk.next = 0 clk.next = not clk
return driveClk
def HelloWorld(clk):
@always(clk.posedge)
def sayHello():
print "%s Hello World!" % now()
return sayHello
clk = Signal(0)
clkdriver_inst = ClkDriver(clk)
hello_inst = HelloWorld(clk)
sim = Simulation(clkdriver_inst, hello_inst)
sim.run(50)
\end{verbatim} \end{verbatim}
The \code{clk} signal is constructed with an initial value The clock driver function \function{ClkDriver} has a
\code{0}. In the clock generator function \code{clkGen}, it is clock signal as its parameter. This is how a
continuously assigned a new value after a certain delay. In \myhdl{}, \emph{port} is modelled in MyHDL. The function
the new value of a signal is specified by assigning to its defines a generator
that continuously toggles a clock signal after a certain delay.
A new value of a signal is specified by assigning to its
\code{next} attribute. This is the \myhdl\ equivalent of \code{next} attribute. This is the \myhdl\ equivalent of
\index{VHDL!signal assignment}% \index{VHDL!signal assignment}%
the VHDL signal assignment and the the VHDL signal assignment and the
\index{Verilog!non-blocking assignment}% \index{Verilog!non-blocking assignment}%
Verilog non-blocking assignment. Verilog non-blocking assignment.
The \code{sayHello} generator function is modified to wait for a The \function{HelloWorld} function is modified from the
rising edge of the clock instead of a delay: first example. It now also takes a clock signal as parameter.
Its generator is made sensitive to a rising
\begin{verbatim}
def sayHello():
while 1:
yield posedge(clk)
print "%s Hello World!" % now()
\end{verbatim}
Waiting for the clock edge is achieved with a second form of the
\keyword{yield} statement: \samp{yield posedge(\var{signal})}.
At that point, the generator will
\index{wait!for a rising edge}% \index{wait!for a rising edge}%
wait for a rising edge on the signal. edge of the clock signal. This is specified by the
\code{posedge} attribute of a signal. The edge
specifier is the argument of the \code{@always}
decorator. As a result, the decorated function
will be executed on every rising clock edge.
The \class{Simulation} is now constructed with 2 generator arguments: The \code{clk} signal is constructed with an initial value
\code{0}. When creating an instance of each to the two
hardware modules, the same clock signal is passed as
the argument. The result is that the two instances
are now connected through the clock signal.
The \class{Simulation} object is constructed with the
two instances.
\begin{verbatim} When we run the simulation, we get:
sim = Simulation(clkGen(), sayHello())
sim.run(50)
\end{verbatim}
When we run this simulation, we get:
\begin{verbatim} \begin{verbatim}
% python hello2.py % python hello2.py
10 Hello World! 10 Hello World!
30 Hello World! 30 Hello World!
50 Hello World! 50 Hello World!
StopSimulation: Simulated for duration 50 _SuspendSimulation: Simulated 50 timesteps
\end{verbatim} \end{verbatim}
\section{Parameters, instances and hierarchy \label{intro-hier}} \section{Parameters and hierarchy \label{intro-hier}}
So far, the generator function examples had no parameters. For We have seen that MyHDL uses functions to model hardware
example, the \code{clk} signal was defined in the enclosing scope of modules. We have also seen that ports are modeled by using
the generator functions. To make code reusable we will signals as parameters. To make designs reusable we will also
want to pass arguments through a parameter list. For example, we can want to use other objects as parameters. For example, we can
change the clock generator function to make it more general change the clock generator function to make it more general
and reusable, as follows: and reusable, by making the clock period parametrizable, as
follows:
\begin{verbatim} \begin{verbatim}
def clkGen(clock, period=20): from myhdl import Signal, delay, instance, always, now, Simulation
lowTime = int(period / 2)
def ClkDriver(clk, period=20):
lowTime = int(period/2)
highTime = period - lowTime highTime = period - lowTime
while 1:
yield delay(lowTime) @instance
clock.next = 1 def driveClk():
yield delay(highTime) while True:
clock.next = 0 yield delay(lowTime)
clk.next = 1
yield delay(highTime)
clk.next = 0
return driveClk
\end{verbatim} \end{verbatim}
The clock signal is now a parameter of the function. Also, the clock In addition to the clock signal, the clock
\var{period} is a parameter with a default value of \code{20}. \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: As the low time of the clock may differ from the high time in case of
an odd period, we cannot use the \function{@always} decorator with a
single delay value anymore. Instead, the \function{driveClk} function
is now a generator function with an explicit definition of the desired
behavior. You can see that \function{driveClk} is a generator function (as
opposed to a classic function) because it contains \code{yield}
statements.
When a generator function is called, it returns a generator object. In
fact, this is mainly what the \function{@instance} decorator does. It
is less sophisticated than the \function{@always} decorator,
but it can be used to create a generator from any local generator
function.
The \code{yield} statement is a general Python construct, but MyHDL
uses it in a dedicated way. In MyHDL, it has a similar meaning as the
wait statement in VHDL: the statement suspends execution of a
generator, and its clauses specify the conditions on which the
generator should wait before resuming. In this case, the generator
waits for a certain delay.
Not that to make sure that the generator runs ``forever'', we wrap its
behavior in a \code{while True} loop.
Likewise, we can define a general \function{Hello} function as follows:
\begin{verbatim} \begin{verbatim}
def sayHello(clock, to="World!"): def Hello(clk, to="World!"):
while 1:
yield posedge(clock) @always(clk.posedge)
def sayHello():
print "%s Hello %s" % (now(), to) print "%s Hello %s" % (now(), to)
return sayHello
\end{verbatim} \end{verbatim}
We can create any number of generators by calling generator functions We can create any number of generators by calling generator functions
@ -190,15 +242,20 @@ For example:
\begin{verbatim} \begin{verbatim}
def greetings(): def greetings():
clk1 = Signal(0) clk1 = Signal(0)
clk2 = 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
sim = Simulation(greetings()) clkdriver_1 = ClkDriver(clk1) # positional and default association
clkdriver_2 = ClkDriver(clk=clk2, period=19) # named assocation
hello_1 = Hello(clk=clk1) # named and default association
hello_2 = Hello(to="MyHDL", clk=clk2) # named assocation
return clkdriver_1, clkdriver_2, hello_1, hello_2
inst = greetings()
sim = Simulation(inst)
sim.run(50) sim.run(50)
\end{verbatim} \end{verbatim}
@ -220,7 +277,7 @@ The simulation produces the following output:
30 Hello World! 30 Hello World!
47 Hello MyHDL 47 Hello MyHDL
50 Hello World! 50 Hello World!
StopSimulation: Simulated for duration 50 _SuspendSimulation: Simulated 50 timesteps
\end{verbatim} \end{verbatim}
@ -273,30 +330,38 @@ As an example, we will consider the design of a Gray encoder. The
following code is a Gray encoder modeled in \myhdl{}: following code is a Gray encoder modeled in \myhdl{}:
\begin{verbatim} \begin{verbatim}
from myhdl import Signal, delay, Simulation, always_comb, instance, intbv, bin
def bin2gray(B, G, width): def bin2gray(B, G, width):
""" Gray encoder. """ Gray encoder.
B -- input intbv signal, binary encoded B -- input intbv signal, binary encoded
G -- output intbv signal, Gray encoded G -- output intbv signal, gray encoded
width -- bit width width -- bit width
"""
"""xc @always_comb
while 1: def logic():
yield B
for i in range(width): for i in range(width):
G.next[i] = B[i+1] ^ B[i] G.next[i] = B[i+1] ^ B[i]
return logic
\end{verbatim} \end{verbatim}
This code introduces a few new concepts. The string in triple quotes 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 at the start of the function is a \dfn{doc string}. This is standard
Python practice for structured documentation of code. Moreover, we Python practice for structured documentation of code.
use a third form of the \keyword{yield} statement:
\samp{yield \var{signal}}. This specifies that the generator should Furthermore, we introduce a third decorator: \function{@always_comb}.
It is used with a classic function and specifies that the
resulting generator should
\index{wait!for a signal value change}% \index{wait!for a signal value change}%
wait for a signal value change. This is typically used to wait for a value change on any input signal. This is typically used to
describe describe
\index{combinatorial logic}% \index{combinatorial logic}%
combinatorial logic. combinatorial logic. The \function{@always_comb} decorator
automatically infers which signals are used as inputs.
Finally, the code contains bit indexing operations and an exclusive-or Finally, the code contains bit indexing operations and an exclusive-or
operator as required for a Gray encoder. By convention, the lsb of an operator as required for a Gray encoder. By convention, the lsb of an
\class{intbv} object has index~\code{0}. \class{intbv} object has index~\code{0}.
@ -310,15 +375,16 @@ def testBench(width):
B = Signal(intbv(0)) B = Signal(intbv(0))
G = Signal(intbv(0)) G = Signal(intbv(0))
dut = bin2gray(B, G, width) dut = traceSignals(bin2gray, B, G, width)
@instance
def stimulus(): def stimulus():
for i in range(2**width): for i in range(2**width):
B.next = intbv(i) B.next = intbv(i)
yield delay(10) yield delay(10)
print "B: " + bin(B, width) + "| G: " + bin(G, width) print "B: " + bin(B, width) + "| G: " + bin(G, width)
return (dut, stimulus()) return dut, stimulus
\end{verbatim} \end{verbatim}
We use the conversion function \code{bin} to get a binary We use the conversion function \code{bin} to get a binary
@ -329,7 +395,8 @@ by the \code{myhdl} package and complements the standard Python
To demonstrate, we set up a simulation for a small width: To demonstrate, we set up a simulation for a small width:
\begin{verbatim} \begin{verbatim}
Simulation(testBench(width=3)).run() sim = Simulation(testBench(width=3))
sim.run()
\end{verbatim} \end{verbatim}
The simulation produces the following output: The simulation produces the following output:
@ -355,8 +422,7 @@ slicing. The following function calculates the HEC byte of an ATM
header. header.
\begin{verbatim} \begin{verbatim}
from myhdl import intbv from myhdl import intbv, concat
concat = intbv.concat # shorthand alias
COSET = 0x55 COSET = 0x55
@ -395,6 +461,9 @@ to avoid one-off count issues in practice. For example, the slice
follows: for a slice \code{[i:j]}, only bits below index \code{i} are 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. included, and the bit with index \code{j} is the last bit included.
When an intbv object is sliced, a new intbv object is returned. This
new intbv always has a positive value, even when the original object
was negative.
\section{Bus-functional procedures \label{intro-bfm}} \section{Bus-functional procedures \label{intro-bfm}}

View File

@ -192,7 +192,7 @@ are forked, while the original generator resumes immediately.
MyHDL defines a number of decorator functions, that make it easier to MyHDL defines a number of decorator functions, that make it easier to
create generators from local generator function. create generators from local generator function.
\begin{funcdesc}{instance}{} \begin{funcdesc}{@instance}{}
The \code{@instance} decorator is the most general decorator. It The \code{@instance} decorator is the most general decorator. It
automatically creates a generator by calling the generator function, automatically creates a generator by calling the generator function,
and by reusing its name. and by reusing its name.
@ -214,10 +214,10 @@ This is equivalent to:
\begin{verbatim} \begin{verbatim}
def top(...): def top(...):
... ...
def gen_func(): def _gen_func():
<generator body> <generator body>
... ...
inst = gen_func() inst = _gen_func()
... ...
return inst, ... return inst, ...
\end{verbatim} \end{verbatim}
@ -225,10 +225,10 @@ def top(...):
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{always}{arg \optional{, *args}} \begin{funcdesc}{@always}{arg \optional{, *args}}
The \code{@always} decorator is a specialized decorator for a widely used The \code{@always} decorator is a specialized decorator that targets a widely used
pattern. It is used as follows: coding pattern. It is used as follows:
\begin{verbatim} \begin{verbatim}
def top(...): def top(...):
@ -242,16 +242,18 @@ def top(...):
This is equivalent to the following: This is equivalent to the following:
\begin{verbatim} \begin{verbatim}
def top(...): def top(...):
... ...
def gen_func() def _func():
<body>
def _gen_func()
while True: while True:
yield event1, event2, ... yield event1, event2, ...
<body> _func()
... ...
inst = gen_func() inst = _gen_func()
... ...
return inst, ... return inst, ...
\end{verbatim} \end{verbatim}
@ -259,12 +261,13 @@ def top(...):
The argument list of the decorator corresponds to the sensitivity The argument list of the decorator corresponds to the sensitivity
list. Only signals, edge specifiers, or delay objects are allowed. list. Only signals, edge specifiers, or delay objects are allowed.
The decorated function should be a classic function.
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{always_comb}{} \begin{funcdesc}{@always_comb}{}
The \code{@always_comb} decorator is used to describe combinatorial The \code{@always_comb} decorator is used to describe combinatorial