Simulation Environment Setup

There are two options for setting up the simulation environment:

  • Pulling a pre-built docker image
  • Installing the dependecies locally

1. Docker

There is an available docker setup with the needed tools at efabless/dockerized-verification-setup

Run the following to pull the image:

docker pull efabless/dv_setup:latest

2. Local Installion (Linux)

You will need to fullfil these dependecies:

  • Icarus Verilog (10.2+)
  • RV32I Toolchain

Using apt, you can install Icarus Verilog:

sudo apt-get install iverilog

Next, you will need to build the RV32I toolchain. Firstly, export the installation path for the RV32I toolchain,

export GCC_PATH=<gcc-installation-path>

Then, run the following:

# packages needed:
sudo apt-get install autoconf automake autotools-dev curl libmpc-dev \
    libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo \
    gperf libtool patchutils bc zlib1g-dev git libexpat1-dev

sudo mkdir $GCC_PATH
sudo chown $USER $GCC_PATH

git clone https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-rv32i
cd riscv-gnu-toolchain-rv32i
git checkout 411d134
git submodule update --init --recursive

mkdir build; cd build
../configure --with-arch=rv32i --prefix=$GCC_PATH
make -j$(nproc)

Running Simulation

Docker

First, you will need to export a number of environment variables:

export PDK_PATH=<pdk-location/sky130A>
export CARAVEL_ROOT=<caravel_root>
export UPRJ_ROOT=<user_project_root>

Then, run the following command to start the docker container :

docker run -it -v $CARAVEL_ROOT:$CARAVEL_ROOT -v $PDK_PATH:$PDK_PATH -v $UPRJ_ROOT:$UPRJ_ROOT -e CARAVEL_ROOT=$CARAVEL_ROOT -e PDK_PATH=$PDK_PATH -e UPRJ_ROOT=$UPRJ_ROOT -u $(id -u $USER):$(id -g $USER) efabless/dv_setup:latest

Then, navigate to the directory where the DV tests reside :

cd $UPRJ_ROOT/verilog/dv/

Then, follow the instructions at Both to run RTL/GL simulation.

Local

You will need to export these environment variables:

export GCC_PATH=<gcc-installation-path>
export PDK_PATH=<pdk-location/sky130A>

Then, follow the instruction at Both to run RTL/GL simulation.

Both

To run RTL simulation for one of the DV tests,

cd <dv-test>
make

To run gate level simulation for one of the DV tests,

cd <dv-test>
SIM=GL make

User Project Example DV

The directory includes two tests for the user-project example:

Output test

  • This test is meant to verify that we can configure the pads as output for the user project area. The firmware configures the 0 to 28 IO pads in the user space as outputs:

    	reg_mprj_io_0 =  GPIO_MODE_USER_STD_OUTPUT;
    	reg_mprj_io_14 =  GPIO_MODE_USER_STD_OUTPUT;
    	.....
    	reg_mprj_io_23 =  GPIO_MODE_USER_STD_OUTPUT;
    
  • Then, the firmware applies the pad configuration by enabling the serial transfer on the shift register responsible for configuring the pads and waits until the transfer is done. The firmware then writes to the gpio a value of 0xaabbcc. Since the gpio is at user address space at 3000_0000 address the firmware writes the value 0xaabbcc to that address.

    	reg_mprj_xfer = 1;
    	while (reg_mprj_xfer == 1);
    	int *gpio = (char*) 0x30000000;
        *gpio = 0xffabcdef;
    
  • The testbench success criteria is that we can observe the gpio value on the 0 to 23 I/O pads. This criteria is checked by the testbench through observing the values on the I/O pads as follows:

    	wait(mprj_io_0[23:0] == 24'habcdef);
    
    
  • If the testbench fails, it will print a timeout message to the terminal.

Input test

  • This test is meant to verify that we can configure the pads as input for the user project area. The firmware configures the 29 to 32 IO pads in the user space as inputs:

    	reg_mprj_io_29 =  GPIO_MODE_USER_STD_INPUT;
    	reg_mprj_io_30 =  GPIO_MODE_USER_STD_INPUT;
    	.....
    	reg_mprj_io_32 =  GPIO_MODE_USER_STD_INPUT;
    
  • Then, the firmware applies the pad configuration by enabling the serial transfer on the shift register responsible for configuring the pads and waits until the transfer is done. The firmware then writes to the gpio a value of 16'hffaa. Since the gpio input is at user address space at 0x3000_0004 address. The code reads from the input and writes it to the output pins. By this way wishbone interface is also verified.

    	reg_mprj_xfer = 1;
    	while (reg_mprj_xfer == 1);
    	int *gpo_addr = (char*) 0x30000000;
        int *gpi_addr = (char*) 0x30000004;
        *gpo_addr = *gpi_addr;
    
  • The testbench success criteria is that we can observe value on the 13 to 28 I/O pads. This criteria is checked by the testbench through observing the values on the I/O pads as follows:


    wait(mprj_io_0 == 16'000a);
  • If the testbench fails, it will print a timeout message to the terminal.

  • Please see the expect result file for the expected result.