{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "a9eaf4f9-f131-448a-bd67-7e5faebfb042", "metadata": { "editable": false, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "# Quickstart Guide\n", "This guide is adapted from Cocotb's [README](https://github.com/cocotb/cocotb#usage)" ] }, { "cell_type": "code", "execution_count": null, "id": "9dd451c9-7925-4424-ae6e-5190ee41d197", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "import random\n", "\n", "import cocotb\n", "from cocotb.clock import Clock\n", "from cocotb.triggers import RisingEdge\n", "from cocotb.types import LogicArray\n", "from cocotb.wavedrom import trace\n", "import wavedrom\n", "import ipywidgets" ] }, { "cell_type": "markdown", "id": "ff70382f-f318-4d37-9389-1665aa83a019", "metadata": { "editable": false, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Assert that initial output is zero.\n", "\n", "**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\")`," ] }, { "cell_type": "code", "execution_count": null, "id": "11476baa-f099-4da8-af9a-9c1b59fb95ca", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "assert LogicArray(dut.q.value) == LogicArray(0)" ] }, { "cell_type": "markdown", "id": "abbca406-cf63-4fc3-a18b-7883fe6c0393", "metadata": { "editable": false, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Setup the clock\n", "\n", "Create a 10us period clock and connect it to the DUT's clk port.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3dafca29-5296-4941-9f55-1f1b60368422", "metadata": {}, "outputs": [], "source": [ "clock = Clock(dut.clk, 10, units=\"us\")\n", "cocotb.start_soon(clock.start(start_high=False));" ] }, { "cell_type": "markdown", "id": "36db8a02-cc9a-4d4e-846c-1087104d7257", "metadata": { "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Setup the waveform monitor\n", "\n", "This monitor will capture a waveform from the D flip-flop and render it to any cell that has `display(waveform_output)`." ] }, { "cell_type": "code", "execution_count": null, "id": "97a30647-982f-4b80-9b2f-7091d2423de4", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "# Create an output widget to display the waveform within this cell. This is necessary since waveform_monitor() is asynchronous. \n", "# Without it, the waveform would display within subsequent cells.\n", "waveform_output = ipywidgets.Output()\n", "async def waveform_monitor():\n", " with trace(dut.d, dut.q, clk=dut.clk) as waves:\n", " while True:\n", " await RisingEdge(dut.clk)\n", " # clear_output() doesn't work with threads\n", " # https://github.com/jupyter-widgets/ipywidgets/issues/3260#issuecomment-907715980\n", " waveform_output.outputs = ()\n", " waveform_output.append_display_data(wavedrom.render(waves.dumpj()))\n", "cocotb.start_soon(waveform_monitor()); " ] }, { "cell_type": "markdown", "id": "6d6205f1-a543-4652-869c-b5c5e91c68af", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Test the D flip-flop with random values\n", "\n", "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`." ] }, { "cell_type": "code", "execution_count": null, "id": "b77901d9-595b-4d0d-9f91-3b01a0adade6", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "await RisingEdge(dut.clk)\n", "expected_val = 0\n", "for i in range(10):\n", " val = random.randint(0, 1)\n", " dut.d.value = val\n", " await RisingEdge(dut.clk)\n", " assert dut.q.value == expected_val, f\"output q was incorrect on the {i}th cycle\"\n", " expected_val = val\n", "\n", "display(waveform_output)" ] }, { "cell_type": "markdown", "id": "04204902-462a-4a53-ada3-1e5d92e4551d", "metadata": {}, "source": [ "### Step D flip-flop with random values\n", "\n", "Interactivity can be added by using `ipywidgets`. In the code below, an async function, `step_random()` is called whenver the *Step* button is pressed. \n", "\n", "For asynchronous callbacks, be sure to use the `@cocotb.function` decorator" ] }, { "cell_type": "code", "execution_count": null, "id": "024c399b-2abf-4fb0-b2aa-6cd8b8c90f9f", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "@cocotb.function\n", "async def step_random(b):\n", " dut.d.value = random.randint(0,1)\n", " await RisingEdge(dut.clk)\n", "\n", "button = ipywidgets.Button(description=\"Step\")\n", "button.on_click(step_random)\n", "display(button, waveform_output)" ] } ], "metadata": { "kernelspec": { "display_name": "cocotb", "language": "python", "name": "cocotb" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" }, "toc": { "base_numbering": 0 } }, "nbformat": 4, "nbformat_minor": 5 }