mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
Use myhdldoctools instead of doctest
This commit is contained in:
parent
3b5ad3b471
commit
f272f8fba4
@ -31,27 +31,26 @@ Combinatorial logic
|
|||||||
Template
|
Template
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. testsetup:: *
|
|
||||||
|
|
||||||
from myhdl import *
|
|
||||||
|
|
||||||
|
|
||||||
Combinatorial logic is described with a code pattern as follows::
|
Combinatorial logic is described with a code pattern as follows::
|
||||||
|
|
||||||
|
from myhdl import block, always_comb
|
||||||
|
|
||||||
|
@block
|
||||||
def top(<parameters>):
|
def top(<parameters>):
|
||||||
...
|
...
|
||||||
@always_comb
|
@always_comb
|
||||||
def combLogic():
|
def comb_logic():
|
||||||
<functional code>
|
<functional code>
|
||||||
...
|
...
|
||||||
return combLogic, ...
|
return comb_logic, ...
|
||||||
|
|
||||||
The :func:`always_comb` decorator describes combinatorial logic. [#]_. The
|
|
||||||
decorated function is a local function that specifies what happens when one of
|
|
||||||
the input signals of the logic changes. The :func:`always_comb` decorator
|
|
||||||
infers the input signals automatically. It returns a generator that is sensitive
|
|
||||||
to all inputs, and that executes the function whenever an input changes.
|
|
||||||
|
|
||||||
|
The :func:`always_comb` decorator describes combinatorial logic. The name refers
|
||||||
|
to a similar construct in SystemVerilog. The decorated function is a local
|
||||||
|
function that specifies what happens when one of the input signals of the logic
|
||||||
|
changes. The :func:`always_comb` decorator infers the input signals
|
||||||
|
automatically. It returns a generator that is sensitive to all inputs, and that
|
||||||
|
executes the function whenever an input changes.
|
||||||
|
|
||||||
.. _model-comb-ex:
|
.. _model-comb-ex:
|
||||||
|
|
||||||
@ -60,76 +59,21 @@ Example
|
|||||||
|
|
||||||
The following is an example of a combinatorial multiplexer
|
The following is an example of a combinatorial multiplexer
|
||||||
|
|
||||||
|
.. include-example:: mux.py
|
||||||
|
|
||||||
.. testcode:: comb1
|
|
||||||
|
|
||||||
from myhdl import Signal, Simulation, delay, always_comb
|
|
||||||
|
|
||||||
def Mux(z, a, b, sel):
|
|
||||||
""" Multiplexer.
|
|
||||||
|
|
||||||
z -- mux output
|
|
||||||
a, b -- data inputs
|
|
||||||
sel -- control input: select a if asserted, otherwise b
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@always_comb
|
|
||||||
def muxLogic():
|
|
||||||
if sel == 1:
|
|
||||||
z.next = a
|
|
||||||
else:
|
|
||||||
z.next = b
|
|
||||||
|
|
||||||
return muxLogic
|
|
||||||
|
|
||||||
# Once we've created some signals...
|
|
||||||
z, a, b, sel = [Signal(intbv(0)) for i in range(4)]
|
|
||||||
|
|
||||||
# ...it can be instantiated as follows
|
|
||||||
mux_1 = Mux(z, a, b, sel)
|
|
||||||
|
|
||||||
To verify it, we will simulate the logic with some random patterns. The
|
To verify it, we will simulate the logic with some random patterns. The
|
||||||
``random`` module in Python's standard library comes in handy for such purposes.
|
``random`` module in Python's standard library comes in handy for such purposes.
|
||||||
The function ``randrange(n)`` returns a random natural integer smaller than *n*.
|
The function ``randrange(n)`` returns a random natural integer smaller than *n*.
|
||||||
It is used in the test bench code to produce random input values
|
It is used in the test bench code to produce random input values.
|
||||||
|
|
||||||
.. testcode:: comb1
|
.. include-example:: test_mux.py
|
||||||
:hide:
|
|
||||||
|
|
||||||
import random
|
It is often useful to keep the random values reproducible. This can be
|
||||||
random.seed(0xDECAFBAD)
|
accomplished by providing a seed value as in the code. The run produces the
|
||||||
|
following output:
|
||||||
|
|
||||||
.. testcode:: comb1
|
.. run-example:: test_mux.py
|
||||||
|
|
||||||
from random import randrange
|
|
||||||
|
|
||||||
def test():
|
|
||||||
|
|
||||||
print "z a b sel"
|
|
||||||
for i in range(8):
|
|
||||||
a.next, b.next, sel.next = randrange(8), randrange(8), randrange(2)
|
|
||||||
yield delay(10)
|
|
||||||
print "%s %s %s %s" % (z, a, b, sel)
|
|
||||||
|
|
||||||
|
|
||||||
test_1 = test()
|
|
||||||
sim = Simulation(mux_1, test_1).run()
|
|
||||||
|
|
||||||
Because of the randomness, the simulation output varies between runs [#]_. One
|
|
||||||
particular run produced the following output
|
|
||||||
|
|
||||||
.. testoutput:: comb1
|
|
||||||
|
|
||||||
z a b sel
|
|
||||||
6 6 0 1
|
|
||||||
7 7 2 1
|
|
||||||
7 6 7 0
|
|
||||||
0 3 0 0
|
|
||||||
1 1 1 1
|
|
||||||
1 5 1 0
|
|
||||||
2 3 2 0
|
|
||||||
1 1 0 1
|
|
||||||
|
|
||||||
.. _model-seq:
|
.. _model-seq:
|
||||||
|
|
||||||
@ -138,7 +82,6 @@ Sequential logic
|
|||||||
|
|
||||||
.. index:: single: sequential logic
|
.. index:: single: sequential logic
|
||||||
|
|
||||||
|
|
||||||
.. _model-seq-templ:
|
.. _model-seq-templ:
|
||||||
|
|
||||||
Template
|
Template
|
||||||
@ -148,13 +91,16 @@ Sequential RTL models are sensitive to a clock edge. In addition, they may be
|
|||||||
sensitive to a reset signal. The :func:`always_seq` decorator supports this
|
sensitive to a reset signal. The :func:`always_seq` decorator supports this
|
||||||
model directly::
|
model directly::
|
||||||
|
|
||||||
|
from myhdl import block, always_seq
|
||||||
|
|
||||||
|
@instance
|
||||||
def top(<parameters>, clock, ..., reset, ...):
|
def top(<parameters>, clock, ..., reset, ...):
|
||||||
...
|
...
|
||||||
@always_seq(clock.posedge, reset=reset)
|
@always_seq(clock.posedge, reset=reset)
|
||||||
def seqLogic():
|
def seq_logic():
|
||||||
<functional code>
|
<functional code>
|
||||||
...
|
...
|
||||||
return seqLogic, ...
|
return seq_logic, ...
|
||||||
|
|
||||||
The :func:`always_seq` decorator automatically infers the reset
|
The :func:`always_seq` decorator automatically infers the reset
|
||||||
functionality. It detects which signals need to be reset, and uses their
|
functionality. It detects which signals need to be reset, and uses their
|
||||||
@ -177,31 +123,7 @@ Example
|
|||||||
The following code is a description of an incrementer with enable, and an
|
The following code is a description of an incrementer with enable, and an
|
||||||
asynchronous reset.
|
asynchronous reset.
|
||||||
|
|
||||||
.. testcode:: seq1
|
.. include-example:: inc.py
|
||||||
|
|
||||||
from myhdl import *
|
|
||||||
|
|
||||||
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
|
||||||
|
|
||||||
def Inc(count, enable, clock, reset, n):
|
|
||||||
|
|
||||||
""" Incrementer with enable.
|
|
||||||
|
|
||||||
count -- output
|
|
||||||
enable -- control input, increment when 1
|
|
||||||
clock -- clock input
|
|
||||||
reset -- asynchronous reset input
|
|
||||||
n -- counter max value
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@always_seq(clock.posedge, reset=reset)
|
|
||||||
def incLogic():
|
|
||||||
if enable:
|
|
||||||
count.next = (count + 1) % n
|
|
||||||
|
|
||||||
return incLogic
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
For the test bench, we will use an independent clock generator, stimulus
|
For the test bench, we will use an independent clock generator, stimulus
|
||||||
@ -209,70 +131,11 @@ generator, and monitor. After applying enough stimulus patterns, we can raise
|
|||||||
the :func:`StopSimulation()` exception to stop the simulation run. The test bench for
|
the :func:`StopSimulation()` exception to stop the simulation run. The test bench for
|
||||||
a small incrementer and a small number of patterns is a follows
|
a small incrementer and a small number of patterns is a follows
|
||||||
|
|
||||||
.. testcode:: seq1
|
.. include-example:: test_inc.py
|
||||||
:hide:
|
|
||||||
|
|
||||||
import random
|
|
||||||
random.seed(0xDECAFBAD)
|
|
||||||
|
|
||||||
.. testcode:: seq1
|
|
||||||
|
|
||||||
from random import randrange
|
|
||||||
|
|
||||||
def testbench():
|
|
||||||
count, enable, clock = [Signal(intbv(0)) for i in range(3)]
|
|
||||||
reset = ResetSignal(0, active=ACTIVE_LOW, async=True)
|
|
||||||
|
|
||||||
inc_1 = Inc(count, enable, clock, reset, n=4)
|
|
||||||
|
|
||||||
HALF_PERIOD = delay(10)
|
|
||||||
|
|
||||||
@always(HALF_PERIOD)
|
|
||||||
def clockGen():
|
|
||||||
clock.next = not clock
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def stimulus():
|
|
||||||
reset.next = ACTIVE_LOW
|
|
||||||
yield clock.negedge
|
|
||||||
reset.next = INACTIVE_HIGH
|
|
||||||
for i in range(12):
|
|
||||||
enable.next = min(1, randrange(3))
|
|
||||||
yield clock.negedge
|
|
||||||
raise StopSimulation
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def monitor():
|
|
||||||
print "enable count"
|
|
||||||
yield reset.posedge
|
|
||||||
while 1:
|
|
||||||
yield clock.posedge
|
|
||||||
yield delay(1)
|
|
||||||
print " %s %s" % (enable, count)
|
|
||||||
|
|
||||||
return clockGen, stimulus, inc_1, monitor
|
|
||||||
|
|
||||||
|
|
||||||
tb = testbench()
|
|
||||||
Simulation(tb).run()
|
|
||||||
|
|
||||||
The simulation produces the following output
|
The simulation produces the following output
|
||||||
|
|
||||||
.. testoutput:: seq1
|
.. run-example:: test_inc.py
|
||||||
|
|
||||||
enable count
|
|
||||||
1 1
|
|
||||||
0 1
|
|
||||||
1 2
|
|
||||||
1 3
|
|
||||||
0 3
|
|
||||||
1 0
|
|
||||||
1 1
|
|
||||||
1 2
|
|
||||||
1 3
|
|
||||||
1 0
|
|
||||||
0 0
|
|
||||||
1 1
|
|
||||||
|
|
||||||
.. _mode-seq-templ-alt:
|
.. _mode-seq-templ-alt:
|
||||||
|
|
||||||
@ -283,15 +146,20 @@ The template with the :func:`always_seq` decorator is convenient
|
|||||||
as it infers the reset functionality automatically. Alternatively,
|
as it infers the reset functionality automatically. Alternatively,
|
||||||
you can use a more explicit template as follows::
|
you can use a more explicit template as follows::
|
||||||
|
|
||||||
|
from myhdl import block, always
|
||||||
|
|
||||||
|
@block
|
||||||
def top(<parameters>, clock, ..., reset, ...):
|
def top(<parameters>, clock, ..., reset, ...):
|
||||||
...
|
...
|
||||||
@always(clock.posedge, reset.negedge)
|
@always(clock.posedge, reset.negedge)
|
||||||
def seqLogic():
|
def seq_logic():
|
||||||
if not reset:
|
if not reset:
|
||||||
<reset code>
|
<reset code>
|
||||||
else:
|
else:
|
||||||
<functional code>
|
<functional code>
|
||||||
|
|
||||||
|
return seq_logic,...
|
||||||
|
|
||||||
With this template, the reset values have to be specified
|
With this template, the reset values have to be specified
|
||||||
explicitly.
|
explicitly.
|
||||||
|
|
||||||
@ -353,55 +221,7 @@ When the ``syncFlag`` is confirmed on the expected position, the FSM declares
|
|||||||
``SYNC``, otherwise it falls back to the ``SEARCH`` state. This FSM can be
|
``SYNC``, otherwise it falls back to the ``SEARCH`` state. This FSM can be
|
||||||
coded as follows
|
coded as follows
|
||||||
|
|
||||||
.. testcode:: sm1
|
.. include-example:: fsm.py
|
||||||
|
|
||||||
from myhdl import *
|
|
||||||
|
|
||||||
ACTIVE_LOW = 0
|
|
||||||
FRAME_SIZE = 8
|
|
||||||
t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
|
|
||||||
|
|
||||||
def FramerCtrl(SOF, state, syncFlag, clk, reset):
|
|
||||||
|
|
||||||
""" Framing control FSM.
|
|
||||||
|
|
||||||
SOF -- start-of-frame output bit
|
|
||||||
state -- FramerState output
|
|
||||||
syncFlag -- sync pattern found indication input
|
|
||||||
clk -- clock input
|
|
||||||
reset_n -- active low reset
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
index = Signal(0) # position in frame
|
|
||||||
|
|
||||||
@always_seq(clk.posedge, reset=reset)
|
|
||||||
def FSM():
|
|
||||||
index.next = (index + 1) % FRAME_SIZE
|
|
||||||
SOF.next = 0
|
|
||||||
|
|
||||||
if state == t_State.SEARCH:
|
|
||||||
index.next = 1
|
|
||||||
if syncFlag:
|
|
||||||
state.next = t_State.CONFIRM
|
|
||||||
|
|
||||||
elif state == t_State.CONFIRM:
|
|
||||||
if index == 0:
|
|
||||||
if syncFlag:
|
|
||||||
state.next = t_State.SYNC
|
|
||||||
else:
|
|
||||||
state.next = t_State.SEARCH
|
|
||||||
|
|
||||||
elif state == t_State.SYNC:
|
|
||||||
if index == 0:
|
|
||||||
if not syncFlag:
|
|
||||||
state.next = t_State.SEARCH
|
|
||||||
SOF.next = (index == FRAME_SIZE-1)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise ValueError("Undefined state")
|
|
||||||
|
|
||||||
return FSM
|
|
||||||
|
|
||||||
.. index:: single: waveform viewing
|
.. index:: single: waveform viewing
|
||||||
|
|
||||||
@ -433,86 +253,7 @@ call.
|
|||||||
A small test bench for our framing controller example, with signal tracing
|
A small test bench for our framing controller example, with signal tracing
|
||||||
enabled, is shown below:
|
enabled, is shown below:
|
||||||
|
|
||||||
.. testcode:: sm1
|
.. include-example:: test_fsm.py
|
||||||
|
|
||||||
def testbench():
|
|
||||||
|
|
||||||
SOF = Signal(bool(0))
|
|
||||||
syncFlag = Signal(bool(0))
|
|
||||||
clk = Signal(bool(0))
|
|
||||||
reset = ResetSignal(1, active=ACTIVE_LOW, async=True)
|
|
||||||
state = Signal(t_State.SEARCH)
|
|
||||||
|
|
||||||
framectrl = FramerCtrl(SOF, state, syncFlag, clk, reset)
|
|
||||||
|
|
||||||
@always(delay(10))
|
|
||||||
def clkgen():
|
|
||||||
clk.next = not clk
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def stimulus():
|
|
||||||
for i in range(3):
|
|
||||||
yield clk.posedge
|
|
||||||
for n in (12, 8, 8, 4):
|
|
||||||
syncFlag.next = 1
|
|
||||||
yield clk.posedge
|
|
||||||
syncFlag.next = 0
|
|
||||||
for i in range(n-1):
|
|
||||||
yield clk.posedge
|
|
||||||
raise StopSimulation
|
|
||||||
|
|
||||||
@always_seq(clk.posedge, reset=reset)
|
|
||||||
def output_printer():
|
|
||||||
print syncFlag, SOF, state
|
|
||||||
|
|
||||||
return framectrl, clkgen, stimulus, output_printer
|
|
||||||
|
|
||||||
tb_fsm = traceSignals(testbench)
|
|
||||||
sim = Simulation(tb_fsm)
|
|
||||||
sim.run()
|
|
||||||
|
|
||||||
.. testoutput:: sm1
|
|
||||||
:hide:
|
|
||||||
|
|
||||||
False False SEARCH
|
|
||||||
False False SEARCH
|
|
||||||
False False SEARCH
|
|
||||||
1 False SEARCH
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False SEARCH
|
|
||||||
0 False SEARCH
|
|
||||||
0 False SEARCH
|
|
||||||
1 False SEARCH
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
0 False CONFIRM
|
|
||||||
1 False CONFIRM
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
1 True SYNC
|
|
||||||
0 False SYNC
|
|
||||||
0 False SYNC
|
|
||||||
|
|
||||||
.. testcleanup:: sm1
|
|
||||||
|
|
||||||
import os
|
|
||||||
os.remove('testbench.vcd')
|
|
||||||
|
|
||||||
When we run the test bench, it generates a VCD file called
|
When we run the test bench, it generates a VCD file called
|
||||||
:file:`testbench.vcd`. When we load this file into :program:`gtkwave`, we can
|
:file:`testbench.vcd`. When we load this file into :program:`gtkwave`, we can
|
||||||
@ -533,14 +274,3 @@ string representation, as returned by the standard :func:`str` function.
|
|||||||
Support for literal string representations is not part of the VCD standard. It
|
Support for literal string representations is not part of the VCD standard. It
|
||||||
is specific to :program:`gtkwave`. To generate a standard VCD file, you need to
|
is specific to :program:`gtkwave`. To generate a standard VCD file, you need to
|
||||||
use signals with a defined bit width only.
|
use signals with a defined bit width only.
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
|
||||||
|
|
||||||
.. [#] The name :func:`always_comb` refers to a construct with similar semantics in
|
|
||||||
SystemVerilog.
|
|
||||||
|
|
||||||
.. [#] It also possible to have a reproducible random output, by explicitly providing a
|
|
||||||
seed value. See the documentation of the ``random`` module.
|
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 14 KiB |
@ -22,7 +22,7 @@ class RunExample(Directive):
|
|||||||
env = document.settings.env
|
env = document.settings.env
|
||||||
_ , wd = env.relfn2path(example_dir)
|
_ , wd = env.relfn2path(example_dir)
|
||||||
prog = self.arguments[0]
|
prog = self.arguments[0]
|
||||||
out = subprocess.check_output(['python', '-u', prog], cwd=wd,
|
out = subprocess.check_output(['python3', '-u', prog], cwd=wd,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
universal_newlines=True)
|
universal_newlines=True)
|
||||||
out = '$ python {}\n{}'.format(prog, out)
|
out = '$ python {}\n{}'.format(prog, out)
|
||||||
|
@ -6,6 +6,6 @@ def Hello(clk, to="World!"):
|
|||||||
|
|
||||||
@always(clk.posedge)
|
@always(clk.posedge)
|
||||||
def say_hello():
|
def say_hello():
|
||||||
print "%s Hello %s" % (now(), to)
|
print("%s Hello %s" % (now(), to))
|
||||||
|
|
||||||
return say_hello
|
return say_hello
|
||||||
|
17
example/manual/conv_inc.py
Normal file
17
example/manual/conv_inc.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from myhdl import toVerilog, toVHDL, Signal, ResetSignal, modbv
|
||||||
|
from inc import inc
|
||||||
|
|
||||||
|
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
||||||
|
|
||||||
|
|
||||||
|
# conversion
|
||||||
|
m = 8
|
||||||
|
|
||||||
|
count = Signal(modbv(0)[m:])
|
||||||
|
enable = Signal(bool(0))
|
||||||
|
clock = Signal(bool(0))
|
||||||
|
reset = ResetSignal(0, active=0, async=True)
|
||||||
|
|
||||||
|
inc_inst = inc(count, enable, clock, reset)
|
||||||
|
inc_inst = toVerilog(inc, count, enable, clock, reset)
|
||||||
|
inc_inst = toVHDL(inc, count, enable, clock, reset)
|
@ -1,95 +1,54 @@
|
|||||||
import myhdl
|
from myhdl import block, always_seq, Signal, intbv, enum
|
||||||
from myhdl import *
|
|
||||||
|
|
||||||
ACTIVE_LOW = 0
|
ACTIVE_LOW = 0
|
||||||
FRAME_SIZE = 8
|
FRAME_SIZE = 8
|
||||||
t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
|
t_state = enum('SEARCH', 'CONFIRM', 'SYNC')
|
||||||
|
|
||||||
@block
|
@block
|
||||||
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
|
def framer_ctrl(sof, state, sync_flag, clk, reset_n):
|
||||||
|
|
||||||
""" Framing control FSM.
|
""" Framing control FSM.
|
||||||
|
|
||||||
SOF -- start-of-frame output bit
|
sof -- start-of-frame output bit
|
||||||
state -- FramerState output
|
state -- FramerState output
|
||||||
syncFlag -- sync pattern found indication input
|
sync_flag -- sync pattern found indication input
|
||||||
clk -- clock input
|
clk -- clock input
|
||||||
reset_n -- active low reset
|
reset_n -- active low reset
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
index = Signal(0) # position in frame
|
index = Signal(intbv(0, min=0, max=FRAME_SIZE)) # position in frame
|
||||||
|
|
||||||
@always(clk.posedge, reset_n.negedge)
|
@always_seq(clk.posedge, reset=reset_n)
|
||||||
def FSM():
|
def FSM():
|
||||||
if reset_n == ACTIVE_LOW:
|
if reset_n == ACTIVE_LOW:
|
||||||
SOF.next = 0
|
sof.next = 0
|
||||||
index.next = 0
|
index.next = 0
|
||||||
state.next = t_State.SEARCH
|
state.next = t_state.SEARCH
|
||||||
|
|
||||||
else:
|
else:
|
||||||
index.next = (index + 1) % FRAME_SIZE
|
index.next = (index + 1) % FRAME_SIZE
|
||||||
SOF.next = 0
|
sof.next = 0
|
||||||
|
|
||||||
if state == t_State.SEARCH:
|
if state == t_state.SEARCH:
|
||||||
index.next = 1
|
index.next = 1
|
||||||
if syncFlag:
|
if sync_flag:
|
||||||
state.next = t_State.CONFIRM
|
state.next = t_state.CONFIRM
|
||||||
|
|
||||||
elif state == t_State.CONFIRM:
|
elif state == t_state.CONFIRM:
|
||||||
if index == 0:
|
if index == 0:
|
||||||
if syncFlag:
|
if sync_flag:
|
||||||
state.next = t_State.SYNC
|
state.next = t_state.SYNC
|
||||||
else:
|
else:
|
||||||
state.next = t_State.SEARCH
|
state.next = t_state.SEARCH
|
||||||
|
|
||||||
elif state == t_State.SYNC:
|
elif state == t_state.SYNC:
|
||||||
if index == 0:
|
if index == 0:
|
||||||
if not syncFlag:
|
if not sync_flag:
|
||||||
state.next = t_State.SEARCH
|
state.next = t_state.SEARCH
|
||||||
SOF.next = (index == FRAME_SIZE-1)
|
sof.next = (index == FRAME_SIZE-1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("Undefined state")
|
raise ValueError("Undefined state")
|
||||||
|
|
||||||
return FSM
|
return FSM
|
||||||
|
|
||||||
|
|
||||||
@block
|
|
||||||
def testbench():
|
|
||||||
|
|
||||||
SOF = Signal(bool(0))
|
|
||||||
syncFlag = Signal(bool(0))
|
|
||||||
clk = Signal(bool(0))
|
|
||||||
reset_n = Signal(bool(1))
|
|
||||||
state = Signal(t_State.SEARCH)
|
|
||||||
|
|
||||||
framectrl = FramerCtrl(SOF, state, syncFlag, clk, reset_n)
|
|
||||||
|
|
||||||
@always(delay(10))
|
|
||||||
def clkgen():
|
|
||||||
clk.next = not clk
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def stimulus():
|
|
||||||
for i in range(3):
|
|
||||||
yield clk.posedge
|
|
||||||
for n in (12, 8, 8, 4):
|
|
||||||
syncFlag.next = 1
|
|
||||||
yield clk.posedge
|
|
||||||
syncFlag.next = 0
|
|
||||||
for i in range(n-1):
|
|
||||||
yield clk.posedge
|
|
||||||
raise StopSimulation
|
|
||||||
|
|
||||||
return framectrl, clkgen, stimulus
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
tb = testbench()
|
|
||||||
tb.config_sim(trace=True)
|
|
||||||
tb.run_sim()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
@ -11,7 +11,7 @@ def HelloWorld():
|
|||||||
|
|
||||||
@always(clk.posedge)
|
@always(clk.posedge)
|
||||||
def say_hello():
|
def say_hello():
|
||||||
print "%s Hello World!" % now()
|
print("%s Hello World!" % now())
|
||||||
|
|
||||||
return drive_clk, say_hello
|
return drive_clk, say_hello
|
||||||
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
from random import randrange
|
from myhdl import block, always_seq
|
||||||
import myhdl
|
|
||||||
from myhdl import *
|
|
||||||
|
|
||||||
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
@block
|
||||||
|
def inc(count, enable, clock, reset):
|
||||||
def Inc(count, enable, clock, reset):
|
|
||||||
|
|
||||||
""" Incrementer with enable.
|
""" Incrementer with enable.
|
||||||
|
|
||||||
@ -17,76 +14,8 @@ def Inc(count, enable, clock, reset):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@always_seq(clock.posedge, reset=reset)
|
@always_seq(clock.posedge, reset=reset)
|
||||||
def incLogic():
|
def seq():
|
||||||
if enable:
|
if enable:
|
||||||
count.next = count + 1
|
count.next = count + 1
|
||||||
|
|
||||||
return incLogic
|
return seq
|
||||||
|
|
||||||
|
|
||||||
def testbench():
|
|
||||||
m = 3
|
|
||||||
count = Signal(modbv(0)[m:])
|
|
||||||
enable = Signal(bool(0))
|
|
||||||
clock = Signal(bool(0))
|
|
||||||
reset = ResetSignal(0, active=0, async=True)
|
|
||||||
|
|
||||||
inc_1 = Inc(count, enable, clock, reset)
|
|
||||||
|
|
||||||
HALF_PERIOD = delay(10)
|
|
||||||
|
|
||||||
@always(HALF_PERIOD)
|
|
||||||
def clockGen():
|
|
||||||
clock.next = not clock
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def stimulus():
|
|
||||||
reset.next = ACTIVE_LOW
|
|
||||||
yield clock.negedge
|
|
||||||
reset.next = INACTIVE_HIGH
|
|
||||||
for i in range(20):
|
|
||||||
enable.next = min(1, randrange(3))
|
|
||||||
yield clock.negedge
|
|
||||||
raise StopSimulation
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def monitor():
|
|
||||||
print "enable count"
|
|
||||||
yield reset.posedge
|
|
||||||
while 1:
|
|
||||||
yield clock.posedge
|
|
||||||
yield delay(1)
|
|
||||||
print " %s %s" % (enable, count)
|
|
||||||
|
|
||||||
return clockGen, stimulus, inc_1, monitor
|
|
||||||
|
|
||||||
tb = testbench()
|
|
||||||
|
|
||||||
def main():
|
|
||||||
Simulation(tb).run()
|
|
||||||
|
|
||||||
|
|
||||||
# conversion
|
|
||||||
m = 8
|
|
||||||
|
|
||||||
count = Signal(modbv(0)[m:])
|
|
||||||
enable = Signal(bool(0))
|
|
||||||
clock = Signal(bool(0))
|
|
||||||
reset = ResetSignal(0, active=0, async=True)
|
|
||||||
|
|
||||||
inc_inst = Inc(count, enable, clock, reset)
|
|
||||||
inc_inst = toVerilog(Inc, count, enable, clock, reset)
|
|
||||||
inc_inst = toVHDL(Inc, count, enable, clock, reset)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,34 +1,21 @@
|
|||||||
from myhdl import Signal, Simulation, delay
|
from myhdl import block, always_comb, Signal
|
||||||
|
|
||||||
|
@block
|
||||||
def mux(z, a, b, sel):
|
def mux(z, a, b, sel):
|
||||||
|
|
||||||
""" Multiplexer.
|
""" Multiplexer.
|
||||||
|
|
||||||
z -- mux output
|
z -- mux output
|
||||||
a, b -- data inputs
|
a, b -- data inputs
|
||||||
sel -- control input: select a if asserted, otherwise b
|
sel -- control input: select a if asserted, otherwise b
|
||||||
|
|
||||||
"""
|
"""
|
||||||
while 1:
|
|
||||||
yield a, b, sel
|
@always_comb
|
||||||
|
def comb():
|
||||||
if sel == 1:
|
if sel == 1:
|
||||||
z.next = a
|
z.next = a
|
||||||
else:
|
else:
|
||||||
z.next = b
|
z.next = b
|
||||||
|
|
||||||
from random import randrange
|
return comb
|
||||||
|
|
||||||
(z, a, b, sel) = [Signal(0) for i in range(4)]
|
|
||||||
|
|
||||||
MUX_1 = mux(z, a, b, sel)
|
|
||||||
|
|
||||||
def test():
|
|
||||||
print "z a b sel"
|
|
||||||
for i in range(8):
|
|
||||||
a.next, b.next, sel.next = randrange(8), randrange(8), randrange(2)
|
|
||||||
yield delay(10)
|
|
||||||
print "%s %s %s %s" % (z, a, b, sel)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
Simulation(MUX_1, test()).run()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
38
example/manual/test_fsm.py
Normal file
38
example/manual/test_fsm.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import myhdl
|
||||||
|
from myhdl import block, always, instance, Signal, ResetSignal, delay, StopSimulation
|
||||||
|
from fsm import framer_ctrl, t_state
|
||||||
|
|
||||||
|
ACTIVE_LOW = 0
|
||||||
|
|
||||||
|
@block
|
||||||
|
def testbench():
|
||||||
|
|
||||||
|
sof = Signal(bool(0))
|
||||||
|
sync_flag = Signal(bool(0))
|
||||||
|
clk = Signal(bool(0))
|
||||||
|
reset_n = ResetSignal(1, active=ACTIVE_LOW, async=True)
|
||||||
|
state = Signal(t_state.SEARCH)
|
||||||
|
|
||||||
|
frame_ctrl_0 = framer_ctrl(sof, state, sync_flag, clk, reset_n)
|
||||||
|
|
||||||
|
@always(delay(10))
|
||||||
|
def clkgen():
|
||||||
|
clk.next = not clk
|
||||||
|
|
||||||
|
@instance
|
||||||
|
def stimulus():
|
||||||
|
for i in range(3):
|
||||||
|
yield clk.negedge
|
||||||
|
for n in (12, 8, 8, 4):
|
||||||
|
sync_flag.next = 1
|
||||||
|
yield clk.negedge
|
||||||
|
sync_flag.next = 0
|
||||||
|
for i in range(n-1):
|
||||||
|
yield clk.negedge
|
||||||
|
raise StopSimulation()
|
||||||
|
|
||||||
|
return frame_ctrl_0, clkgen, stimulus
|
||||||
|
|
||||||
|
tb = testbench()
|
||||||
|
tb.config_sim(trace=True)
|
||||||
|
tb.run_sim()
|
49
example/manual/test_inc.py
Normal file
49
example/manual/test_inc.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import random
|
||||||
|
from myhdl import block, always, instance, Signal, modbv, \
|
||||||
|
ResetSignal, delay, StopSimulation
|
||||||
|
from inc import inc
|
||||||
|
|
||||||
|
random.seed(1)
|
||||||
|
randrange = random.randrange
|
||||||
|
|
||||||
|
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
||||||
|
|
||||||
|
@block
|
||||||
|
def testbench():
|
||||||
|
m = 3
|
||||||
|
count = Signal(modbv(0)[m:])
|
||||||
|
enable = Signal(bool(0))
|
||||||
|
clock = Signal(bool(0))
|
||||||
|
reset = ResetSignal(0, active=0, async=True)
|
||||||
|
|
||||||
|
inc_1 = inc(count, enable, clock, reset)
|
||||||
|
|
||||||
|
HALF_PERIOD = delay(10)
|
||||||
|
|
||||||
|
@always(HALF_PERIOD)
|
||||||
|
def clockGen():
|
||||||
|
clock.next = not clock
|
||||||
|
|
||||||
|
@instance
|
||||||
|
def stimulus():
|
||||||
|
reset.next = ACTIVE_LOW
|
||||||
|
yield clock.negedge
|
||||||
|
reset.next = INACTIVE_HIGH
|
||||||
|
for i in range(16):
|
||||||
|
enable.next = min(1, randrange(3))
|
||||||
|
yield clock.negedge
|
||||||
|
raise StopSimulation()
|
||||||
|
|
||||||
|
@instance
|
||||||
|
def monitor():
|
||||||
|
print("enable count")
|
||||||
|
yield reset.posedge
|
||||||
|
while 1:
|
||||||
|
yield clock.posedge
|
||||||
|
yield delay(1)
|
||||||
|
print(" %s %s" % (int(enable), count))
|
||||||
|
|
||||||
|
return clockGen, stimulus, inc_1, monitor
|
||||||
|
|
||||||
|
tb = testbench()
|
||||||
|
tb.run_sim()
|
26
example/manual/test_mux.py
Normal file
26
example/manual/test_mux.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import random
|
||||||
|
from myhdl import block, instance, Signal, intbv, delay
|
||||||
|
from mux import mux
|
||||||
|
|
||||||
|
random.seed(5)
|
||||||
|
randrange = random.randrange
|
||||||
|
|
||||||
|
@block
|
||||||
|
def test_mux():
|
||||||
|
|
||||||
|
z, a, b, sel = [Signal(intbv(0)) for i in range(4)]
|
||||||
|
|
||||||
|
mux_1 = mux(z, a, b, sel)
|
||||||
|
|
||||||
|
@instance
|
||||||
|
def stimulus():
|
||||||
|
print("z a b sel")
|
||||||
|
for i in range(12):
|
||||||
|
a.next, b.next, sel.next = randrange(8), randrange(8), randrange(2)
|
||||||
|
yield delay(10)
|
||||||
|
print("%s %s %s %s" % (z, a, b, sel))
|
||||||
|
|
||||||
|
return mux_1, stimulus
|
||||||
|
|
||||||
|
tb = test_mux()
|
||||||
|
tb.run_sim()
|
Loading…
x
Reference in New Issue
Block a user