|
2 | 2 | Getting Started with cocotb |
3 | 3 | =========================== |
4 | 4 |
|
5 | | -In this section, you will learn how to create a basic test for a flow/storage hardware component (such as a pipe, FIFO, etc.). To get started, first create a ``cocotb`` folder in the directory where the tested component is located, and put all the scripts implemented in this tutorial into it. |
| 5 | +This guide shows how to create a basic test for flow/storage hardware components (such as pipes, FIFOs, etc.) using the cocotb framework. Cocotb allows you to write testbenches in Python, which are then used to verify VHDL/Verilog designs. |
6 | 6 |
|
| 7 | +The examples in this guide use the MVB FIFOX component test located at ``comp/mvb_tools/storage/fifox/cocotb/cocotb_test.py`` as a reference. |
7 | 8 |
|
8 | | -.. note:: For automatic generation of a test template use the ``generate_test_template`` script in ``ndk-fpga/build/scripts/cocotb``. |
9 | 9 |
|
| 10 | +Quick Start |
| 11 | +----------- |
10 | 12 |
|
11 | | -Creating a Test |
12 | | -=============== |
| 13 | +For beginners, the easiest way to get started is: |
13 | 14 |
|
14 | | -As an example, a simple test of an MVB FIFOX component will be used. |
15 | | -It can be found at ``ndk-fpga/comp/mvb_tools/storage/fifox/cocotb/cocotb_test.py``. |
| 15 | +1. **Create a ``cocotb`` folder** in the directory of the component you want to test |
| 16 | +2. **Copy template files** from an existing test (e.g., ``comp/mvb_tools/storage/fifox/cocotb/``) |
| 17 | +3. **Modify the files** for your component: |
| 18 | + - Update the ``TOPLEVEL`` in the Makefile to match your component name |
| 19 | + - Adjust signal names and bus parameters in the testbench |
| 20 | + - Update the model function to compute expected outputs for your component |
| 21 | +4. **Run the test** using the Makefile |
| 22 | + |
| 23 | +.. note:: For automatic generation of a test template, use the ``generate_test_template`` script in ``ndk-fpga/build/scripts/cocotb``. This creates a basic test structure that you can customize. |
| 24 | + |
| 25 | + |
| 26 | +Test Structure |
| 27 | +============== |
| 28 | + |
| 29 | +A cocotb test consists of two main parts: |
| 30 | + |
| 31 | +**1. Testbench Class** - Reusable setup code that encapsulates all test infrastructure: |
| 32 | + |
| 33 | + - **Drivers** - Objects that write stimulus data to the DUT (Device Under Test) input interfaces |
| 34 | + - **Monitors** - Objects that read output data from the DUT and convert it to transactions |
| 35 | + - **Scoreboard** - Compares actual outputs (from monitors) against expected outputs |
| 36 | + - **Expected outputs** - List of transactions that the DUT should produce |
| 37 | + - **Optional objects** - Probes for throughput measurement, bit drivers for backpressure testing |
| 38 | + - **Reset sequence** - Hardware reset initialization |
| 39 | + |
| 40 | + The testbench class is typically reusable across multiple tests and can be copied/adapted for similar components. |
| 41 | + |
| 42 | +**2. Test Function** - The actual test with: |
| 43 | + |
| 44 | + - ``@cocotb.test()`` decorator (required) - Marks the function as a cocotb test |
| 45 | + - ``async`` function definition (required) - Enables coroutine-based simulation |
| 46 | + - Test logic - Stimulus generation, DUT interaction, and verification |
| 47 | + |
| 48 | +Example test file structure: |
16 | 49 |
|
17 | 50 | .. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/cocotb_test.py |
18 | 51 | :language: python |
19 | 52 | :linenos: |
20 | 53 | :encoding: utf-8 |
21 | 54 |
|
22 | | -This test can be used as a template for tests of basic `flow` and `storage` components, and can be easily adapted for most other verifications. It consists of two basic parts: the testbench class and the test itself: |
23 | 55 |
|
24 | | -- The testbench is the more reusable of the two and usually looks basically the same, so it can be copied and adapted. Its purpose is to initialize and encapsulate objects that drive the test. It sets up drivers, monitors, a scoreboard, expected outputs, and other optional objects, such as a bit driver for ready signals, adds probes, and so on. It also includes a simulated reset. |
25 | | -- The second part is the test part. It can consist of one test (typical for simple components) or multiple tests (more common for larger designs, such as the whole firmware of a card). Every test must have the ``@cocotb.test()`` decorator and be ``async``. |
| 56 | +Test Flow |
| 57 | +--------- |
| 58 | + |
| 59 | +A typical test follows these steps: |
| 60 | + |
| 61 | +1. **Start clock** - Initialize the clock generator using ``cocotb.start_soon(Clock(...).start())``. The clock drives the synchronous logic of the DUT. |
| 62 | + |
| 63 | +2. **Initialize testbench** - Create the testbench object, which sets up all drivers, monitors, and the scoreboard. |
| 64 | + |
| 65 | +3. **Reset** - Run the hardware reset sequence (typically 8-16 clock cycles with RESET high). This ensures the DUT starts in a known state. |
| 66 | + |
| 67 | +4. **Configure stimulus** - Set up idle generators (to create realistic gaps in data) and backpressure drivers (to test DUT behavior when output is blocked). |
| 68 | + |
| 69 | +5. **Generate and send data** - Create random transactions using helper functions like ``random_transactions`` or custom generators. Send them to the DUT via the driver's ``append()`` method. |
| 70 | + |
| 71 | +6. **Model expected output** - For each sent transaction, compute what the DUT should output and add it to the ``expected_output`` list. This is typically done in a ``model()`` method. |
| 72 | + |
| 73 | +7. **Wait for completion** - Use a waiting loop to ensure all transactions are processed before checking results. Without this, the scoreboard might evaluate prematurely. |
| 74 | + |
| 75 | +8. **Check results** - Raise ``tb.scoreboard.result`` to display pass/fail. The scoreboard automatically compares each received transaction against the expected output. |
| 76 | + |
26 | 77 |
|
27 | | -A test begins with the clock starting, testbench initialization, and a reset. After the reset, a bit driver is started to test the component's reaction to backpressure (dst_rdy). Random data is then generated, which can either be done using ``random_transactions`` or random data that is then inserted into transaction objects (this is the case in the test above). The generated transaction is then passed to the ``model`` method of the testbench, which inserts it into the ``expected_output`` list. The generated transaction is also inserted into the driver's send queue using the ``append`` method, from where it is then written onto the bus. |
| 78 | +Required Files |
| 79 | +============== |
28 | 80 |
|
29 | | -The data is then read from the bus by a monitor, which should pack it into a transaction of the same type as was modeled and pass it to the test's scoreboard via a callback. The scoreboard pops the transaction from the front of the expected output queue that the monitor is connected to and compares this transaction with the transaction it received from the monitor. If they are not the same, a test failure is raised. |
| 81 | +To run a cocotb test, you need these files in your ``cocotb/`` folder: |
30 | 82 |
|
31 | | -A waiting loop is implemented to ensure that the test doesn't report scoreboard results prematurely before all the transactions have been received. Otherwise, the scoreboard may receive a different number of transactions than it expected, which will lead to an error. |
| 83 | +**pyproject.toml** - Python dependencies |
| 84 | + This file declares the Python packages required for the test (cocotb, cocotbext-ndk, etc.). The build system uses it to create a virtual environment with all dependencies. |
32 | 85 |
|
33 | | -After all the packets are received, ``tb.scoreboard.result`` is raised, and the test results are shown. |
| 86 | + .. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/pyproject.toml |
| 87 | + :language: toml |
| 88 | + :linenos: |
| 89 | + :encoding: utf-8 |
| 90 | + |
| 91 | +**cocotb_test_sig.fdo** - Simulator waveform signals |
| 92 | + This script defines which signals will be visible in the simulator's waveform viewer. Use it to debug failing tests by inspecting signal timing. |
| 93 | + |
| 94 | + .. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/cocotb_test_sig.fdo |
| 95 | + :language: bash |
| 96 | + :linenos: |
| 97 | + :encoding: utf-8 |
| 98 | + |
| 99 | +**Makefile** - Build and run configuration |
| 100 | + The Makefile specifies the simulator to use (Modelsim, Vivado, etc.), the top-level entity, and cocotb configuration. It handles building the simulation and running the test. |
| 101 | + |
| 102 | + .. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/Makefile |
| 103 | + :language: bash |
| 104 | + :linenos: |
| 105 | + :encoding: utf-8 |
| 106 | + |
| 107 | +.. note:: Adjust component-specific values (TOPLEVEL, generics, parameters) and relative paths in all files to match your component. |
34 | 108 |
|
35 | 109 |
|
36 | 110 | Running the Test |
37 | 111 | ================ |
38 | 112 |
|
39 | | -To successfully build and run the simulation, it's necessary to implement a couple more files. Examples of these can again be found in the ``ndk-fpga/comp/mvb_tools/storage/fifox/cocotb/`` folder. |
| 113 | +1. **Create Python virtual environment:** |
40 | 114 |
|
41 | | -First, it is necessary to implement a ``pyproject.toml`` with all test dependencies listed: |
| 115 | + .. code-block:: bash |
42 | 116 |
|
43 | | -.. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/pyproject.toml |
44 | | - :language: toml |
45 | | - :linenos: |
46 | | - :encoding: utf-8 |
| 117 | + make cocotb-venv |
47 | 118 |
|
48 | | -Use a special ``cocotb_test_sig.fdo`` file to define the signals that will be displayed in the simulator's waveform. |
| 119 | + This creates a virtual environment (typically in ``venv-<hash>/``) with all dependencies from ``pyproject.toml``. |
49 | 120 |
|
50 | | -.. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/cocotb_test_sig.fdo |
51 | | - :language: bash |
52 | | - :linenos: |
53 | | - :encoding: utf-8 |
| 121 | +2. **Activate the environment:** |
54 | 122 |
|
55 | | -Finally, create a ``Makefile`` that will run the simulation: |
| 123 | + .. code-block:: bash |
56 | 124 |
|
57 | | -.. literalinclude:: ../../comp/mvb_tools/storage/fifox/cocotb/Makefile |
58 | | - :language: bash |
59 | | - :linenos: |
60 | | - :encoding: utf-8 |
| 125 | + source venv-xxx/bin/activate |
| 126 | +
|
| 127 | + Replace ``venv-xxx`` with the actual virtual environment folder name. |
| 128 | + |
| 129 | +3. **Run the test:** |
| 130 | + |
| 131 | + .. code-block:: bash |
| 132 | +
|
| 133 | + make |
| 134 | +
|
| 135 | + This builds the simulation (if needed) and runs the cocotb test. Results are printed to the terminal, and waveforms are saved for debugging. |
| 136 | + |
| 137 | + To run the test in console-only mode (without launching the GUI waveform viewer), use: |
| 138 | + |
| 139 | + .. code-block:: bash |
| 140 | +
|
| 141 | + make SIM_FLAGS=-c |
| 142 | +
|
| 143 | + This is useful for automated testing or when running tests on remote servers. |
61 | 144 |
|
62 | | -.. note:: Don't forget to adjust the values that are component-specific and the relative paths if needed. |
| 145 | +.. tip:: Use ``export COCOTB_LOG_LEVEL=DEBUG`` before running to enable debug logging for troubleshooting. See the :ref:`Debug Logging` section for more details. |
63 | 146 |
|
64 | | -You can run the simulation by creating a python virtual environment using make cocotb-venv, entering the created virtual environment, and running the ``Makefile``: |
| 147 | +.. tip:: If a test fails, examine the waveform file to understand the timing and identify the issue. The signals defined in ``cocotb_test_sig.fdo`` will be visible. |
65 | 148 |
|
66 | | -.. code-block:: bash |
| 149 | +See Also |
| 150 | +-------- |
67 | 151 |
|
68 | | - make cocotb-venv |
69 | | - source venv-xxx/bin/activate |
70 | | - make |
| 152 | +- :doc:`cocotb_tips_and_tricks` - Tips for debug logging, random seed control, and optional signals |
| 153 | +- :doc:`cocotbext` - Overview of cocotbext-ndk extension with drivers, monitors, and utilities |
0 commit comments