Create Springbok Vector Unit Test

Step 0: Repo Sync and Build Prequisites

repo sync
m renode_clean renode
m qemu_clean qemu

Step 1: Select Instruction and Update Tracker

Go to the following spreadsheet and write or select one's name under the DRI - Unit Test.

Select Instructions Here

Now you've signed up to develop a unit test for this vector instruction :)

Side Note: The following pivot table is very useful for quickly scanning through the instructions available: DRI Pivot Table

Step 2: Create operation definition in ${ROOTDIR}/sw/vec/softrvv/include

Add definition of the operation as a file softrvv_<op>h.h in the following folder, where <op> is your operation (e.g. vadd, vor, vmerge, etc...):

${ROOTDIR}/sw/vec/softrvv/include

This test will contain the definition of the operation (e.g. vadd operation below):

template <typename T>
void vadd_vi(T *dest, T *src1, T src2, int32_t avl) {
  for (int32_t idx = 0; idx < avl; idx++) {
    dest[idx] = src1[idx] + src2;
  }
}

See softrvv_vadd.h for a reference.

Step 3: Add the header to softrvv.h

Add the header file as an includes in the softrvv.h:

#include "softrvv_vadd.h"

softrvv.h is in the ${ROOTDIR}/sw/vec/softrvv/include directory.

Step 4: Add main test entry within the CMakeLists.txt

cd into the following folder, and edit the CMakeLists.txt file there

${ROOTDIR}/sw/vec/tests/CMakeLists.txt

Add an entry there with the opcode formats relavant to the operation:

vec_cc_generated_test(
  NAME
    vadd
  OPFMT
    OPIVV
    OPIVX
    OPIVI
  LINKOPTS
   -Xlinker --defsym=__itcm_length__=200K
)

Note: this operation uses OPIVV, OPIVX, and OPIVI formats.

A range of tests will be be autogenerated for each one of the OPFMT's added.

The Mako templates for each OPFMT test can be found at ${ROOTDIR}/sw/vec/tests/templates.

Note on __itcm_length__: keeping this number low for each test helps our overall performance, most tests are good with 128K, some might need a little more memory (ctest will let you know if you need to add more here).

Step 5: Create subtest

Please also add a small manual test the new softvv instruction. Steps delineated as follows:

Add brief softrvv test

cd ${ROOTDIR}/sw/vec/softrvv/tests

Then add a test-file named softrvv_<op>_test.cpp.

See other files in the same folder as references.

In this test-file you'll define a few simple test cases to run on the defined functions:

See for example this VV test from softrvv_vadd_test.cpp:

uint32_t src1[] = {1, 2, 3, 4, 5};
uint32_t src2[] = {1, 2, 3, 4, 5};

uint32_t ref_vv[] = {2, 4, 6, 8, 10};

TEST_F(SoftRvvVaddTest, VV) {
  softrvv::vadd_vv<uint32_t>(dest, src1, src2, AVL_CONST);
  ASSERT_EQ(memcmp(dest, ref_vv, sizeof(dest)), 0);
}

Add this smaller test to a 2nd Cmake file

Edit another CMakeLists.txt file (path below):

${ROOTDIR}/sw/vec/softrvv/tests/CMakeLists.txt

Add the subtest just created:

vec_cc_test(
  NAME
    softrvv_vadd
  SRCS
    softrvv_vadd_test.cpp
  DEPS
    softrvv
  LINKOPTS
   -Xlinker --defsym=__itcm_length__=128K

Step 6.1: Build and Run Elf with Renode/Qemu

cd into the root directory (cd $ROOTDIR), and build the elf with:

m springbok

Run Elf with Renode

From the root directory, run sim_springbok

sim_springbok ./out/springbok/rvv/tests/vadd_test.elf

This will run the single elf, and if there is an error, can give useful information, such as the PC and MTVAL associated with any illegal instruction.

Run Elf with Qemu

From the root directory, run qemu_sim_springbok

qemu_sim_springbok ./out/springbok/rvv/tests/vadd_test.elf

Step 6.2 (Optional): Debug Elf with Renode/Qemu and gdb

To debug an elf, open two console sessions in the $ROOTDIR, in one run start a simulator (either sim_springbok or qemu_sim_springbok):

Start Renode simulation:

sim_springbok ./out/springbok/rvv/tests/vadd_test.elf debug

Alternatively, start Qemu simulation:

qemu_sim_springbok ./out/springbok/rvv/tests/vadd_test.elf -s -S

Now, in the other console session run the following command to start a gdb session:

cache/toolchain/bin/riscv32-unknown-elf-gdb -ex "target remote :3333" out/springbok/rvv/tests/vadd_test.elf

Note: To run GDB with the Qemu simulation, use

cache/toolchain/bin/riscv32-unknown-elf-gdb -ex "target remote :1234" out/springbok/rvv/tests/vadd_test.elf

First, in the Renode session, type start.

Then, in the gdb session, type the following,

layout split
b main

and step through as usual with GDB.

Step 6.3 (Optional): Object dump with binutils

Sadly, gdb cannot presently decode RVV machine code into assembly instructions.

However, the objdump is able to decode the RVV machine code into assembly. To do this, obtain the program counter for the RVV machine code in question, then perform an objdump.

Run this on the elf (while in the $ROOTDIR):

cache/toolchain_iree_rv32imf/bin/riscv32-unknown-elf-objdump -d out/springbok/rvv/tests/vadd_test.elf | less

Then search for the PC for any instruction of interest.

Step 7: Build and Run CTests

CTests must be run from the ${ROOTDIR}/out/springbok directory.

cd ${ROOTDIR}/out/springbok

Next, using Regex in the quoted section, select Qemu, Renode, and/or other operations to include in a test run:

m springbok && ctest --verbose -R ".*vadd.*"  --gtest_color=yes

Step 8 (optional): view generated code

Code for the main test was autogenerated, however by cd'ing into the following directory, one can inspect the generated code.

${ROOTDIR}/out/springbok/rvv/tests/generated/

Step 9: Mark Tests as Passing

Note: at minimum, one's test should be expected to pass in Qemu. Since Renode vec support is WIP, a unit test failing may indicate problem in the Renode implementation.

On the unit test tracker:

  1. Mark whether the unit test passes in Qemu
  2. Mark whether the unit test passes in Renode
  3. Mark the instruction “Springbok Unit Test” as “implemented”

Step 10: Git Commit

At this point there are two commitable chunks:

  1. operation definition, softrvv.h change, and CMakeLists.txt entry.
  2. the manual test and its CMakeLists.txt entry

These may be added as either one CL, or two CL's separating these two contributions.