mirror of
https://github.com/myhdl/myhdl.git
synced 2025-01-24 21:52:56 +08:00
partial checkin
This commit is contained in:
parent
4c78b0821c
commit
f1a73b4923
@ -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|)}
|
|
||||||
|
|
||||||
|
@ -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}}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user