In [14]:
from myhdl import *
from myhdlpeek import Peeker
def adder_bit(a, b, c_in, sum_, c_out):
'''Single bit adder.'''
@always_comb
def adder_logic():
sum_.next = a ^ b ^ c_in
c_out.next = (a & b) | (a & c_in) | (b & c_in)
# Add some peekers to monitor the inputs and outputs.
Peeker(a, 'a')
Peeker(b, 'b')
Peeker(c_in, 'c_in')
Peeker(sum_, 'sum')
Peeker(c_out, 'c_out')
return adder_logic
def adder(a, b, sum_):
'''Connect single-bit adders to create a complete adder.'''
c = [Signal(bool(0)) for _ in range(len(a)+1)] # Carry signals between stages.
s = [Signal(bool(0)) for _ in range(len(a))] # Sum bit for each stage.
stages = [] # Storage for adder bit instances.
# Create the adder bits and connect them together.
for i in range(len(a)):
stages.append( adder_bit(a=a(i), b=b(i), sum_=s[i], c_in=c[i], c_out=c[i+1]) )
# Concatenate the sum bits and send them out on the sum_ output.
@always_comb
def make_sum():
sum_.next = ConcatSignal(*reversed(s))
return instances() # Return all the adder stage instances.
# Create signals for interfacing to the adder.
a, b, sum_ = [Signal(intbv(0,0,8)) for _ in range(3)]
# Clear-out any existing peeker stuff before instantiating the adder.
Peeker.clear()
# Instantiate the adder.
add_1 = adder(a=a, b=b, sum_=sum_)
# Create some more peekers to monitor the top-level buses.
Peeker(a, 'a_bus')
Peeker(b, 'b_bus')
Peeker(sum_, 'sum_bus')
# Create a testbench generator that applies random inputs to the adder.
from random import randrange
def test(duration):
for _ in range(duration):
a.next, b.next = randrange(0, a.max), randrange(0, a.max)
yield delay(1)
# Simulate the adder, testbench and peekers.
Simulation(add_1, test(8), *Peeker.instances()).run()
Out[14]:
In [15]:
Peeker.to_wavedrom('a_bus', 'b_bus', 'sum_bus', 'sum[2]', 'sum[1]', 'sum[0]')
If you don't like typing all those quotation marks, you can place multiple, space-separated peeker names inside a string:
In [16]:
Peeker.to_wavedrom('a_bus b_bus sum_bus sum[2] sum[1] sum[0]')
In [17]:
Peeker.to_wavedrom('a_bus b_bus | sum_bus sum[2] sum[1] sum[0]')
In [18]:
signals = 'a_bus b_bus | sum_bus sum[2] sum[1] sum[0]'
Peeker.to_wavedrom(signals, start_time=5, stop_time=15)
In [19]:
Peeker.to_wavedrom(signals, start_time=5, stop_time=15, tock=True)
In [20]:
Peeker.to_wavedrom(signals, start_time=5, stop_time=15, tock=True,
title='Multi-Bit, Hierarchical Adder', caption='It really works!')
In [21]:
Peeker.to_wavedrom(signals, start_time=5, stop_time=15, tock=True,
title='Multi-Bit, Hierarchical Adder', caption='It reall works!', width=400)
Sometimes you'll have a long simulation that creates an unreadable display because it's squeezed
into the width of the page. You can restore legibility by setting width
wider than the page
and then using the scroll bars to view the waveforms:
In [22]:
Peeker.clear_traces()
Simulation(add_1, test(100), *Peeker.instances()).run()
Peeker.to_wavedrom(signals, width=4000)
Peeker.clear_traces()
The skin
option lets you choose the set of graphic elements that are used to draw the waveforms.
Currently, the only allowed values are default
and narrow
.
In [23]:
Simulation(add_1, test(8), *Peeker.instances()).run()
Peeker.to_wavedrom(signals, skin='narrow')
In [24]:
wavejson = Peeker.to_wavejson(signals)
wavejson
Out[24]:
After you manipulate the WaveJSON data, you can display it using the wavejson_to_wavedrom()
function:
In [25]:
from myhdlpeek import wavejson_to_wavedrom
wavejson_to_wavedrom(wavejson)