mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
partial checkin
This commit is contained in:
parent
fc137e5049
commit
eee364fd65
@ -26,7 +26,7 @@ DOCFILES= $(HOWTOSTYLES) \
|
||||
MANUALFILES= $(MANSTYLES) $(INDEXSTYLES) $(COMMONTEX) \
|
||||
manual/MyHDL.tex \
|
||||
manual/background.tex \
|
||||
manual/informal.tex \
|
||||
manual/intro.tex \
|
||||
manual/modeling.tex \
|
||||
manual/unittest.tex \
|
||||
manual/cosimulation.tex \
|
||||
|
@ -376,7 +376,7 @@ def testBench(width):
|
||||
B = Signal(intbv(0))
|
||||
G = Signal(intbv(0))
|
||||
|
||||
dut = traceSignals(bin2gray, B, G, width)
|
||||
dut = bin2gray(B, G, width)
|
||||
|
||||
@instance
|
||||
def stimulus():
|
||||
|
@ -95,11 +95,9 @@ def top(..., n=8):
|
||||
\subsection{Inferring the list of instances \label{model-infer-instlist}}
|
||||
|
||||
In \myhdl{}, instances have to be returned explicitly by
|
||||
a top level function. This procedural approach has important
|
||||
advantages, as shown earlier. However, if we just want to
|
||||
return all defined instances, it may be convenient to assemble
|
||||
a top level function. It may be convenient to assemble
|
||||
the list of instances automatically. For this purpose,
|
||||
\myhdl{}~0.3 provides the function \function{instances()}.
|
||||
\myhdl provides the function \function{instances()}.
|
||||
Using the first example in this section, it is used as follows:
|
||||
|
||||
\begin{verbatim}
|
||||
@ -131,40 +129,28 @@ as is typically used for synthesizable models in Verilog or VHDL.
|
||||
|
||||
\subsubsection{Template \label{model-comb-templ}}
|
||||
|
||||
Combinatorial logic is described with a generator function code template as
|
||||
Combinatorial logic is described with a code pattern as
|
||||
follows:
|
||||
|
||||
\begin{verbatim}
|
||||
def combinatorialLogic(<arguments>)
|
||||
while 1:
|
||||
yield <input signals>
|
||||
def top(<parameters>)
|
||||
...
|
||||
@always_comb
|
||||
def combLogic():
|
||||
<functional code>
|
||||
...
|
||||
return combLogic, ...
|
||||
\end{verbatim}
|
||||
|
||||
The overall code is wrapped in a \code{while 1} statement to keep the
|
||||
generator alive. All input signals are clauses in the \code{yield}
|
||||
statement, so that the generator resumes whenever one of the inputs
|
||||
changes.
|
||||
|
||||
Note that the input signals are listed explicitly in the
|
||||
template. Alternatively, \myhdl\ provides the \function{always_comb()}
|
||||
function to infer the input signals automatically.
|
||||
\footnote{The name \function{always_comb()} refers to
|
||||
a construct with similar semantics in SystemVerilog.}.
|
||||
The argument of
|
||||
\function{always_comb()} is a local function that specifies
|
||||
what happens when one of the input signals
|
||||
changes. It returns a generator that is
|
||||
sensitive to all inputs, and that will run the function argument
|
||||
whenever an input changes. Using \function{always_comb}, the template
|
||||
can be rewritten as follows:
|
||||
|
||||
\begin{verbatim}
|
||||
def combinatorialLogic(<arguments>)
|
||||
def logicFunction():
|
||||
<functional code>
|
||||
return always_comb(logicFunction)
|
||||
\end{verbatim}
|
||||
The \function{@always_comb} decorator is used to describe
|
||||
combinatorial logic.
|
||||
\footnote{The name \function{always_comb} refers to a construct with
|
||||
similar semantics in SystemVerilog.}.
|
||||
The decorated function is a local function that specifies what
|
||||
happens when one of the input signals of the logic changes. The
|
||||
\function{@always_comb} decorator infers the input signals
|
||||
automatically. It returns a generator that is sensitive to all inputs,
|
||||
and that will run the function whenever an input changes.
|
||||
|
||||
|
||||
\subsubsection{Example \label{model-comb-ex}}
|
||||
@ -172,7 +158,10 @@ def combinatorialLogic(<arguments>)
|
||||
The following is an example of a combinatorial multiplexer:
|
||||
|
||||
\begin{verbatim}
|
||||
def mux(z, a, b, sel):
|
||||
from myhdl import Signal, Simulation, delay, always_comb
|
||||
|
||||
def Mux(z, a, b, sel):
|
||||
|
||||
""" Multiplexer.
|
||||
|
||||
z -- mux output
|
||||
@ -180,30 +169,19 @@ def mux(z, a, b, sel):
|
||||
sel -- control input: select a if asserted, otherwise b
|
||||
|
||||
"""
|
||||
while 1:
|
||||
yield a, b, sel
|
||||
if sel == 1:
|
||||
z.next = a
|
||||
else:
|
||||
z.next = b
|
||||
\end{verbatim}
|
||||
|
||||
Alternatively, it could be written as follows, using
|
||||
\function{always_comb()}:
|
||||
|
||||
\begin{verbatim}
|
||||
def mux(z, a, b, sel):
|
||||
|
||||
def muxlogic():
|
||||
@always_comb
|
||||
def muxLogic():
|
||||
if sel == 1:
|
||||
z.next = a
|
||||
else:
|
||||
z.next = b
|
||||
|
||||
return always_comb(muxlogic)
|
||||
return muxLogic
|
||||
\end{verbatim}
|
||||
|
||||
To verify, let's simulate this logic with some random patterns. The
|
||||
|
||||
To verify it, we will simulate the logic with some random patterns. The
|
||||
\code{random} module in Python's standard library comes in handy for
|
||||
such purposes. The function \code{randrange(\var{n})} returns a random
|
||||
natural integer smaller than \var{n}. It is used in the test bench
|
||||
@ -212,9 +190,9 @@ code to produce random input values:
|
||||
\begin{verbatim}
|
||||
from random import randrange
|
||||
|
||||
(z, a, b, sel) = [Signal(0) for i in range(4)]
|
||||
z, a, b, sel = [Signal(0) for i in range(4)]
|
||||
|
||||
MUX_1 = mux(z, a, b, sel)
|
||||
mux_1 = Mux(z, a, b, sel)
|
||||
|
||||
def test():
|
||||
print "z a b sel"
|
||||
@ -222,8 +200,11 @@ def test():
|
||||
a.next, b.next, sel.next = randrange(8), randrange(8), randrange(2)
|
||||
yield delay(10)
|
||||
print "%s %s %s %s" % (z, a, b, sel)
|
||||
|
||||
Simulation(MUX_1, test()).run()
|
||||
|
||||
test_1 = test()
|
||||
|
||||
sim = Simulation(mux_1, test_1)
|
||||
sim.run()
|
||||
\end{verbatim}
|
||||
|
||||
Because of the randomness, the simulation output varies between runs
|
||||
@ -257,13 +238,16 @@ common patterns: a template with a rising clock edge and an
|
||||
asynchronous reset signal. Other templates are similar.
|
||||
|
||||
\begin{verbatim}
|
||||
def sequentialLogic(<arguments>, clock, ..., reset, ...)
|
||||
while 1:
|
||||
yield posedge(clock), negedge(reset)
|
||||
def top(<parameters>, clock, ..., reset, ...)
|
||||
...
|
||||
@always(clock.posedge, reset.negedge)
|
||||
def seqLogic():
|
||||
if reset == <active level>:
|
||||
<reset code>
|
||||
else:
|
||||
<functional code>
|
||||
...
|
||||
return seqLogic, ...
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
@ -272,9 +256,13 @@ The following code is a description of an incrementer with enable, and
|
||||
an asynchronous power-up reset.
|
||||
|
||||
\begin{verbatim}
|
||||
from random import randrange
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
||||
|
||||
def Inc(count, enable, clock, reset, n):
|
||||
|
||||
""" Incrementer with enable.
|
||||
|
||||
count -- output
|
||||
@ -284,13 +272,16 @@ def Inc(count, enable, clock, reset, n):
|
||||
n -- counter max value
|
||||
|
||||
"""
|
||||
while 1:
|
||||
yield posedge(clock), negedge(reset)
|
||||
|
||||
@always(clock.posedge, reset.negedge)
|
||||
def incLogic():
|
||||
if reset == ACTIVE_LOW:
|
||||
count.next = 0
|
||||
else:
|
||||
if enable:
|
||||
count.next = (count + 1) % n
|
||||
|
||||
return incLogic
|
||||
\end{verbatim}
|
||||
|
||||
For the test bench, we will use an independent clock generator, stimulus
|
||||
@ -300,33 +291,42 @@ simulation run. The test bench for a small incrementer and a small
|
||||
number of patterns is a follows:
|
||||
|
||||
\begin{verbatim}
|
||||
count, enable, clock, reset = [Signal(intbv(0)) for i in range(4)]
|
||||
def testbench():
|
||||
count, enable, clock, reset = [Signal(intbv(0)) for i in range(4)]
|
||||
|
||||
INC_1 = Inc(count, enable, clock, reset, n=4)
|
||||
inc_1 = Inc(count, enable, clock, reset, n=4)
|
||||
|
||||
def clockGen():
|
||||
while 1:
|
||||
yield delay(10)
|
||||
HALF_PERIOD = delay(10)
|
||||
|
||||
@always(HALF_PERIOD)
|
||||
def clockGen():
|
||||
clock.next = not clock
|
||||
|
||||
def stimulus():
|
||||
reset.next = ACTIVE_LOW
|
||||
yield negedge(clock)
|
||||
reset.next = INACTIVE_HIGH
|
||||
for i in range(12):
|
||||
enable.next = min(1, randrange(3))
|
||||
@instance
|
||||
def stimulus():
|
||||
reset.next = ACTIVE_LOW
|
||||
yield negedge(clock)
|
||||
raise StopSimulation
|
||||
reset.next = INACTIVE_HIGH
|
||||
for i in range(12):
|
||||
enable.next = min(1, randrange(3))
|
||||
yield negedge(clock)
|
||||
raise StopSimulation
|
||||
|
||||
def monitor():
|
||||
print "enable count"
|
||||
yield posedge(reset)
|
||||
while 1:
|
||||
yield posedge(clock)
|
||||
yield delay(1)
|
||||
print " %s %s" % (enable, count)
|
||||
|
||||
Simulation(clockGen(), stimulus(), monitor(), INC_1).run()
|
||||
@instance
|
||||
def monitor():
|
||||
print "enable count"
|
||||
yield posedge(reset)
|
||||
while 1:
|
||||
yield posedge(clock)
|
||||
yield delay(1)
|
||||
print " %s %s" % (enable, count)
|
||||
|
||||
return clockGen, stimulus, inc_1, monitor
|
||||
|
||||
tb = testbench()
|
||||
|
||||
def main():
|
||||
Simulation(tb).run()
|
||||
\end{verbatim}
|
||||
|
||||
The simulation produces the following output:
|
||||
|
Loading…
x
Reference in New Issue
Block a user