There are two options for setting up the simulation environment:
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
You will need to fullfil these dependecies:
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)
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.
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.
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
The directory includes two tests for the user-project example:
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.
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.