import random
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.types import LogicArray
from cocotb.wavedrom import trace
import wavedrom
import ipywidgets
Note: Since Verilator is a cycle-based simulator, it initializes all X
values to 0. If an event-driven simulator is used (e.g. Icarus Verilog), then change LogicArray(0)
to LogicArray("X")
,
assert LogicArray(dut.q.value) == LogicArray(0)
Create a 10us period clock and connect it to the DUT's clk port.
clock = Clock(dut.clk, 10, units="us")
cocotb.start_soon(clock.start(start_high=False));
This monitor will capture a waveform from the D flip-flop and render it to any cell that has display(waveform_output)
.
# Create an output widget to display the waveform within this cell. This is necessary since waveform_monitor() is asynchronous.
# Without it, the waveform would display within subsequent cells.
waveform_output = ipywidgets.Output()
async def waveform_monitor():
with trace(dut.d, dut.q, clk=dut.clk) as waves:
while True:
await RisingEdge(dut.clk)
# clear_output() doesn't work with threads
# https://github.com/jupyter-widgets/ipywidgets/issues/3260#issuecomment-907715980
waveform_output.outputs = ()
waveform_output.append_display_data(wavedrom.render(waves.dumpj()))
cocotb.start_soon(waveform_monitor());
Code within a cell is ran within a cocotb "test", so await
works without needing to declare an async
function. Future verisons may add the ability to declare "test" functions that will be passed to cocotb's RegressionManager
.
await RisingEdge(dut.clk)
expected_val = 0
for i in range(10):
val = random.randint(0, 1)
dut.d.value = val
await RisingEdge(dut.clk)
assert dut.q.value == expected_val, f"output q was incorrect on the {i}th cycle"
expected_val = val
display(waveform_output)
Interactivity can be added by using ipywidgets
. In the code below, an async function, step_random()
is called whenver the Step button is pressed.
For asynchronous callbacks, be sure to use the @cocotb.function
decorator
@cocotb.function
async def step_random(b):
dut.d.value = random.randint(0,1)
await RisingEdge(dut.clk)
button = ipywidgets.Button(description="Step")
button.on_click(step_random)
display(button, waveform_output)