How to write and run a testbench for functional simulation

A Step-by-Step Guide to Creating and Running Test Benches with Caravel cocotb APIs

This tutorial will guide you through using the Caravel cocotb APIs to create a test bench that sets Caravel GPIOs to specific values. You’ll learn how to write firmware that runs on the Caravel management SoC, configure GPIOs for management output, and use a Python cocotb test bench to monitor and verify these GPIO values against expected outcomes.

Steps to Create and Run a Test Bench

1. Create test directory under your project root

under verilog/dv/cocotb create a directory with the name of your test, in this case we will call it gpio_test, under that directory create a file called gpio_test.c for your firmware and gpio_test.py for your python cocotb test bench. You will also need to update the cocotb_tests.py file to add from gpio_test.gpio_test import gpio_test, the directory tree should look something like this:

├── README.md
├── cocotb_tests.py
├── design_info.yaml
└── gpio_test
  ├── gpio_test.c
  └── gpio_test.py

2. Create the Firmware Program

The firmware, written in C, will run on the Caravel management SoC. It controls GPIO configurations and sets specific values. Here’s a sample firmware program:

#include <common.h> 
void main(){
  mgmt_gpio_o_enable();
  mgmt_gpio_wr(0);
  enable_hk_spi(0); 
 configure_all_gpios(GPIO_MODE_MGMT_STD_OUTPUT);
  gpio_config_load();
  set_gpio_l(0x8F);
  mgmt_gpio_wr(1);
  return;
}
  • #include <common.h>: Includes the necessary firmware APIs.
  • mgmt_gpio_o_enable(): Sets the management GPIO to output mode.
  • mgmt_gpio_wr(0): Sets the management GPIO pin to 0, indicating that configuration is in progress.
  • enable_hk_spi(0): Disables housekeeping SPI to allow GPIO 3 to function as a regular GPIO.
  • configure_all_gpios(GPIO_MODE_MGMT_STD_OUT): Configures all 38 Caravel GPIO pins to management output mode.
  • gpio_config_load(): Loads the GPIO configuration.
  • set_gpio_l(0x8F): Sets the lower 32 GPIOs to a specific value (in this case, the first four and the eighth GPIOs are set to 1).
  • mgmt_gpio_wr(1): Indicates that the configuration is complete by setting the management GPIO to 1.

You can find a detailed description of the firmware APIs here.

3. Create the Python Test Bench

The Python test bench monitors Caravel signals and verifies the GPIO values. Here’s an example test bench:

from cocotb_includes import * 
import cocotb

@cocotb.test() 
@repot_test 
async def gpio_test(dut):
   caravelEnv = await test_configure(dut)
   await caravelEnv.release_csb()
   await caravelEnv.wait_mgmt_gpio(1)
   gpios_value_str = caravelEnv.monitor_gpio(37, 0).binstr
   cocotb.log.info(f"All gpios '{gpios_value_str}'")
   gpio_value_int = caravelEnv.monitor_gpio(37, 0).integer
  expected_gpio_value = 0x8F
   if gpio_value_int == expected_gpio_value:
      cocotb.log.info(f"[TEST] Pass: GPIO value is '{hex(gpio_value_int)}'")
   else:
      cocotb.log.error(f"[TEST] Fail: GPIO value is '{hex(gpio_value_int)}', expected '{hex(expected_gpio_value)}'")
  • from cocotb_includes import *: Includes the Caravel Python APIs.
  • import cocotb: Imports the cocotb library.
  • @cocotb.test(): Marks the function as a cocotb test.
  • @repot_test: Configures the test reporting.
  • async def gpio_test(dut): Defines the test function as a coroutine.
  • caravelEnv = await test_configure(dut): Configures the Caravel test environment.
  • await caravelEnv.release_csb(): Releases the housekeeping SPI.
  • await caravelEnv.wait_mgmt_gpio(1): Waits for the management GPIO to indicate that the firmware configuration is complete.
  • gpios_value_str = caravelEnv.monitor_gpio(37, 0).binstr: Monitors and retrieves the GPIO values as a binary string.
  • cocotb.log.info(): Logs information to the full.log file.
  • gpio_value_int = caravelEnv.monitor_gpio(37, 0).integer: Retrieves the GPIO values as an integer.
  • The final if statement compares the GPIO value with the expected value and logs the result.

4. Run the Test

  1. (Recommended) use the makefile:
    make cocotb-verify-gpio_test-rtl
  2. Run manually:
    navigate to the verilog/dv/cocotb directory and execute the caravel_cocotb command:
    caravel_cocotb -t gpio_test -sim RTL -tag first_test 

For more details on the command options, refer to the Caravel cocotb documentation.

5. Check if the Test Passed or Failed

After running the test, you will receive output indicating whether the test passed or failed. If there are errors, check the firmware.log or gpio_test.log files in the verilog/dv/cocotb/sim/first_test/RTL-gpio_test/ directory for detailed information.