From b89adb31bdfd0458ac5a243c4b905dc9a6564d96 Mon Sep 17 00:00:00 2001 From: Jeremy Ralph Date: Tue, 10 Jul 2018 14:33:56 -0400 Subject: [PATCH] doc update for v0.1.3 --- doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.html b/doc/index.html index 07341d9..e4791fa 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1 +1 @@ -

[riscv-vip]  Users’ Guide

Overview        1

License        1

Community        2

Files and directories        2

Instruction Decode Model        3

Running riscv-vip unit tests        4

Instruction unit tests        4

HEX file analyzer unit tests        6

View the functional coverage of scanning the HEX files        6

Generating the HEX files from source, for the hex_file_analyzer        8

Adding riscv-vip to an existing RISC-V core        9

Update your build process to compile and include riscv-vip files        9

Update your testbench        9

Simulator flags        10

Locating the trace file        11

Overview

For pre-silicon developers of RISC-V systems, the riscv-vip project:

License

The riscv-vip project is licensed under the Apache Version 2.0 license.  

The hex files committed in the riscv-vip/riscv_tests_hexgen/build/ directory are generated from assembly *.S files from the riscv-test project, available at https://github.com/riscv/riscv-tests and licensed under its own license.

Community

Files and directories

The main files and directories are shown in the following table.

riscv-vip/

Root of repo

riscv-vip/LICENSE.txt

Apache License

riscv-vip/README.md

Readme file

riscv-vip/RELEASE.txt

Release notes

riscv-vip/doc/

Documentation dir

riscv-vip/doc/index.html

Open in your web browser for documentation.  Also available at https://jerralph.github.io/riscv-vip/doc/index.html 

riscv-vip/src/

Source folder

riscv-vip/src/decoder.svh

Decoder class

riscv-vip/src/hex_file_analyzer.svh

Hex file Analyzer class

riscv-vip/src/hex_file_analyzer_unit_test.sv

Hex file Analyzer unit tests

riscv-vip/src/instruction.svh

Instruction Classes

riscv-vip/src/instruction_unit_test.sv

Instruction unit tests

riscv-vip/src/Makefile

Makefile for running unit tests

riscv-vip/src/riscv_vip_class_pkg.sv

Package of Classes

riscv-vip/src/risc_vip.do

Mentor do file

riscv-vip/src/riscv_vip.f

File list

riscv-vip/src/riscv_vip_if.svh

Interface file

riscv-vip/src/riscv_vip_pkg.sv

Package of parameters, types, structures, constants

riscv-vip/src/uvm/

Folder containing UVM related files

riscv-vip/src/uvm/i32_agent.svh

Passive RV32I UVM Agent

riscv-vip/src/uvm/i32_agent_unit_test.sv

Unit test for RV32I UVM agent

riscv-vip/src/uvm/i32_cov_subscriber.svh

RV32I Coverage subscriber

riscv-vip/src/uvm/i32_item.svh

RV32I Transaction item

riscv-vip/src/uvm/i32_monitor.svh

RV32I Passive monitor

riscv-vip/src/uvm/Makefile

Makefile for running tests

riscv-vip/src/uvm/riscv_vip_uvc.f

UVC file list

riscv-vip/src/uvm/riscv_vip_uvc_pkg.sv

UVC package

riscv-vip/src/uvm/uvc_env.svh

UVC environment

riscv-vip/src/uvm/uvc_env_unit_test.sv

UVC environment unit test

riscv-vip/riscv_tests_hexgen/

Dir for building HEX files from riscv-test source.

riscv-vip/riscv_tests_hexgen/build/

Build dir populated by running make

riscv-vip/riscv_tests_hexgen/build/hex_files.txt

List of HEX files for reading in by the hex_file_analyzer class.

riscv-vip/riscv_tests_hexgen/build/*.hex

Pre-committed HEX files for RV32UI tests generated from the riscv-tests project assembly files from https://github.com/riscv/riscv-tests 

riscv-vip/riscv_tests_hexgen/link.ld

Linker script for generating HEX files from riscv-tests assembly.

riscv-vip/riscv_tests_hexgen/Makefile

Makefile for generated HEX files from riscv-tests assembly

Instruction Decode Model

The decoder class decodes raw bits into the riscv-vip instruction decode model.  The instruction class hierarchy is as follows where the specific formats are derived from the general inst32 class.  For simplicity, many methods are omitted from this diagram.

For example, consider the following code:

       decoder decoder0 = new();

       bit[31:0] inst_bits = 32'hfff08193;    

       inst32 i32 = decoder0.decode_inst32(inst_bits);

       $display("decode of 0x%0H is [ %s ]", inst_bits, i32.to_string());

This will display the following output:

 decode of 0xfff08193 is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

This is an I format add immediate, addi, instruction with an immediate value of -1, using x1 as the source and x3 for the destination register.  For more details on instruction formats and how this is encoded/decoded, refer to the RISC-V specification.

In the inst32_iformat class, there is a coverage bin for non-special I instructions with immediates of -1 (or all 1s in binary), as shown below:

    i32i_imm_cp : coverpoint imm iff ((inst inside {I_NONSPECIAL_INSTS})) {

      bins basics[] = {0,1,2,4};

      bins max_pos =  {`IMM_MAX_POS(imm)};

      bins all_ones = {`IMM_ALL_ONES(imm)};

      bins min_neg =  {`IMM_MIN_NEG(imm)};

    }

Non-special refers to standard I format instructions like ADDI and ANDI.  Non-special I instructions include all I instructions except {SLLI, SRLI, SRAI, FENCE, FENCE.I, ECALL, EBREAK, CSRR*}, which are special -- they have something special/different about them and need to be covered a bit differently.

The following illustrates how coverage is sampled and a generic inst32 is cast to a specific inst32_iformat class:

        //Cast the general inst32 into the more specific inst32_iformat once we're sure it

        //really is an I format.  The coverage should be 0 before sampling then

        //have one bin hit after sampling

        inst32_iformat i32i;        

        assert(i32.is_i_format());

        $cast(i32i,i32);

        cov = i32i.get_nonspecial_imm_cov();

        assert(cov == 0);        

        i32i.sample_cov();

        cov = i32i.get_nonspecial_imm_cov();

        $display("after sample_cov of 0x%0H get_nonspecial_imm_cov() yields %0f", inst_bits, cov);

The resulting output is:

after sample_cov of 0xfff08193 get_nonspecial_imm_cov() yields 14.285714

This is the coverage we expect since 1/7 coverage bins are hit. Such coverage will also show up in the simulator’s coverage database and analysis interfaces.

Running riscv-vip unit tests

During development, unit testing of riscv-vip is done to improve quality and capture usage examples.  Running and examining the unit tests is a great way to better understand the riscv-vip.  Users can easily create their own unit tests to verify their understanding and the workings of the code.

The unit tests will have names of the form *_unit_test.sv.  SVUnit is used for the unit testing framework, this can be obtained from https://github.com/nosnhojn/svunit-code.  Follow the instructions posted there to install.

Instruction unit tests

The instruction unit tests in the instruction_unit_test.sv file exercise and test the decoder and instruction use- cases and functional coverage.

With SVUnit is installed, the tests are run as follows, assuming you are in the riscv-vip/src directory:

% make inst_ut

By default, this will run using Modelsim.  To run in Cadence ius, append SIMR=ius to the above command.

The output looks like this:

runSVUnit -t instruction_unit_test.sv -s modelsim   -f riscv_vip.f

SVUNIT: Output File: ./.__testsuite.sv

SVUNIT: Creating class __testsuite:

SVUNIT: Creating instances for:

...

-- Compiling module testrunner

Top level modules:

        testrunner

End time: 17:08:06 on Jun 08,2018, Elapsed time: 0:00:00

Errors: 0, Warnings: 2

Reading pref.tcl

# 10.6c

# vsim -c -lib work -do "run -all; quit" -l run.log testrunner

# Start time: 17:08:07 on Jun 08,2018

# ** Note: (vsim-3813) Design is being optimized due to module recompilation...

# ** Warning: hex_file_analyzer.sv(54): (vopt-2252) Missing incrementer in "FOR" statement.

# //  Questa Sim

# //  Version 10.6c linux Jul 25 2017

...

# run -all

# INFO:  [0][__ts]: Registering Unit Test Case inst32_ut

# INFO:  [0][testrunner]: Registering Test Suite __ts

# INFO:  [0][__ts]: RUNNING

# INFO:  [0][inst32_ut]: RUNNING

# INFO:  [0][inst32_ut]: ug_example1::RUNNING

# My addi from code is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

# INFO:  [0][inst32_ut]: ug_example1::PASSED

# INFO:  [0][inst32_ut]: ug_example2::RUNNING

# decode of 0xfff08193 is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

# INFO:  [0][inst32_ut]: ug_example2::PASSED

# INFO:  [0][inst32_ut]: test1::RUNNING

# 0ff0a2f3 I CSRRS X5_T0, X1_RA, 255

# 0010a133 R SLT X2_SP, X1_RA, X1_RA

# INFO:  [0][inst32_ut]: test1::PASSED

# INFO:  [0][inst32_ut]: inst32_sformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_sformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_uformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_uformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_jformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_jformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_bformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_bformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_iformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_iformat_cov::PASSED

# INFO:  [0][inst32_ut]: store_to_string::RUNNING

# INFO:  [0][inst32_ut]: store_to_string::PASSED

# INFO:  [0][inst32_ut]: PASSED (9 of 9 tests passing)

#

# INFO:  [0][__ts]: PASSED (1 of 1 testcases passing)

#

# INFO:  [0][testrunner]: PASSED (1 of 1 suites passing) [SVUnit v3.26]

# ** Note: $finish    : .testrunner.sv(40)

#    Time: 0 ns  Iteration: 9  Instance: /testrunner

# End time: 17:08:08 on Jun 08,2018, Elapsed time: 0:00:01

# Errors: 0, Warnings: 1

Have a look into the instruction_unit_test.sv file to better understand what is going on here.  

HEX file analyzer unit tests

The unit test for hex_file_analyzer.sv reads in a list of RV32UI HEX files from the riscv-tests project.  It then dumps out the associated riscv-vip trace and also sampled coverage of every instruction in the HEX files.  

The HEX files for RV32UI generated from the riscv-test project are committed to the riscv-vip repository.  These files were generated from the riscv-test assembly files, as described by the Generating the HEX files from source section, below.  These files have been included for convenience so the user doesn’t need to install the riscv-tools project.

Run the test as follows,  assuming you are in the riscv-vip/src directory:

% make hex_ut

Observe a trace output scroll by, like shown below.  

...

# INFO:  [0][hex_file_analyzer_ut]: analyze_hex_files::RUNNING

# 00000000 04c0006f J JAL X0_ZERO, 76

# 00000004 34202f73 I CSRRS X30_T5, X0_ZERO, 834

# 00000008 00800f93 I ADDI X31_T6, X0_ZERO, 8

# 0000000c 03ff0a63 B BEQ X30_T5, X31_T6 52

# 00000010 00900f93 I ADDI X31_T6, X0_ZERO, 9

# 00000014 03ff0663 B BEQ X30_T5, X31_T6 44

# 00000018 00b00f93 I ADDI X31_T6, X0_ZERO, 11

# 0000001c 03ff0263 B BEQ X30_T5, X31_T6 36

# 00000020 00000f17 U AUIPC X30_T5, 0

# 00000024 fe0f0f13 I ADDI X30_T5, X30_T5, -32

# 00000028 000f0463 B BEQ X30_T5, X0_ZERO 8

...

# 000005c8 0011e193 I ORI X3_GP, X3_GP, 1

# 000005cc 00000073 I ECALL X0_ZERO, X0_ZERO, 0

# 000005d0 0ff0000f I FENCE X0_ZERO, X0_ZERO, 255

# 000005d4 00100193 I ADDI X3_GP, X0_ZERO, 1

# 000005d8 00000073 I ECALL X0_ZERO, X0_ZERO, 0

# 000005dc c0001073 I CSRRW X0_ZERO, X0_ZERO, -1024

# INFO:  [0][hex_file_analyzer_ut]: analyze_hex_files::PASSED

# INFO:  [0][hex_file_analyzer_ut]: PASSED (1 of 1 tests passing)

#

# INFO:  [0][__ts]: PASSED (1 of 1 testcases passing)

#

# INFO:  [0][testrunner]: PASSED (1 of 1 suites passing) [SVUnit v3.26]

# ** Note: $finish    : .testrunner.sv(40)

#    Time: 0 ns  Iteration: 1  Instance: /testrunner

# Saving coverage database on exit...

# End time: 18:49:58 on Jun 11,2018, Elapsed time: 0:00:12

# Errors: 0, Warnings: 0

This is essentially the disassembly of each HEX file. These outputs can be cross referenced / checked against the related disassembly *.DUMP file produced the toolchain.  

View the functional coverage of scanning the HEX files

The coverage scored by sampling HEX file instructions can be analyzed.  It’s important to note that this is not the way coverage is typically done in a verif env, yet it is an interesting experiment none-the-less.  Any execution of these HEX programs would cover a subset of all instructions in the file as scored by the file analyzer.  

The most interesting part is what is missing from the HEX file coverage -- this indicates things that cannot possibly be covered by running the program and potential areas where there could be bugs.

Run the following command, assuming you are in the riscv-vip/src directory and using QuestaSim:

% make cov

The Questa GUI should open.  Goto Window > Covergroups to browse the coverage of the different covergroups.   For example, the following shows what instructions were observed.

Generating the HEX files from source, for the hex_file_analyzer

To generate the RV32UI HEX files from the riscv-test project you must have the riscv-tools project installed from https://github.com/riscv/riscv-tools, this contains the needed gcc compiler toolchain.  The RISCV_TEST environment variable needs to point to your https://github.com/riscv/riscv-tests installation. This can be done by running the following in the riscv-tests install directory:

% export RISCV_TESTS=`pwd`

Now, from the root of your riscv-vip clone:

% cd riscv_tests_hexgen/

% make clean

% make

This hex_file_list target will:

The new HEX files can be run through the hex_file_analyzer class as described in the HEX file analyzer unit tests section.

Adding riscv-vip to an existing RISC-V core

This section is written assuming you have no existing UVM environment and that you want to passively add the riscv-vip to monitor and score coverage for your test.  For those with existing UVM environments, the integration is similar.

Update your build process to compile and include riscv-vip files

Include the following files in your simulation build process, where riscv-vip is your clone of the riscv-vip repo.  

riscv-vip/src/riscv_vip_pkg.sv

riscv-vip/src/riscv_vip_class_pkg.sv

riscv-vip/src/uvm/riscv_vip_uvc_pkg.sv

riscv-vip/src/uvm/test/riscv_vip_test_pkg.sv

Add the following paths to the incdir so the *.svh files included by the pkg files can be located by the simulator.

riscv-vip/src

riscv-vip/src/uvm

riscv-vip/src/uvm/test

Update your testbench

In the module where you instantiate the DUT for testing (generally the testbench or _tb file), tap into instruction and address of the instructions executed on the RISC-V core you are using.  Where and how this interface is connected depends on the implementation of the DUT and what the user wants to accomplish.

The interface to connect is in from riscv_vip_if.svh, and contains the following:

interface riscv_vip_if (input clk, input rstn);

   logic[31:0] curr_pc;

   logic [31:0] curr_inst;  

endinterface

Update the testbench to import and include the needed items.

import uvm_pkg::*;

import riscv_vip_uvc_pkg::*;

import riscv_vip_test_pkg::*;

`include "uvm_macros.svh"

Instantiate the riscv_vip_if interface in the testbench and pass this as a virtual interface into the UVM world using the UVM configuration database.  After this, run the UVM portion of the test.  This will run alongside your pre-existing tests.  Note that uvm_test_top.m_uvc_env is the hierarchical path to the reusable riscv-vip Universal Verification Component (UVC).

//riscv-vip virtual if instantiation

riscv_vip_if rv_vip_if(

  `SOME_XMR_TO_CORE.clk,

  `SOME_XMR_TO_CORE.rstn

);

//use xmrs to connect up the interface

assign rv_vip_if.curr_pc = `SOME_XMR_TO_CORE.pc;      

assign rv_vip_if.curr_inst = `SOME_XMR_TO_CORE.instr;

genvar cores;

generate

  for (cores = 0; cores < `NUM_CORES; cores++) begin : gen_cores

    initial begin : set_riscv_vip_vif_to_db

                     

      uvm_config_db#(virtual riscv_vip_if)::set(

        null,

        $psprintf("uvm_test_top.m_uvc_env.m_i32_agent[%0d]",cores),

        "m_vi",

        rv_vip_if

        );

     

      uvm_config_db#(int)::set(

        null,

        $psprintf("uvm_test_top.m_uvc_env.m_i32_agent[%0d]",cores),

        "m_core_id",

        cores

        );

     

    end      

  end : gen_cores

endgenerate

//Run UVM test

initial begin

  run_test();

end

Simulator flags

For Cadence ius the flags used are

-uvm -sv -exit +licq +nowarn+CUVWSP +nowarn+LIBNOU +nowarn+SPDUSD -linedebug -uvmlinedebug -coverage all -covoverwrite +define+DUMP+TRN +access+rc +UVM_TESTNAME=riscv_vip_base_test

Note that the +UVM_TEST_NAME is passed to the simulator at runtime, as a SystemVerilog plus argument.  

For Mentor Questasim the flags are

-mfcu -incr -sv "+nowarn8233" -warning vlog-2997 "+acc" -R -voptargs="+cover=bcefst" -coverage -do "coverage save -onexit coverage.ucdb" UVM_TESTNAME=riscv_vip_base_test

Locating the trace file

After running a simulation with the riscv_vip_base_test, if things are working correctly, you should find a trace file named riscv_tracker_<core_id>.log in the directory where the simulation is run.

\ No newline at end of file +

[riscv-vip]  Users’ Guide

Overview        1

License        1

Community        2

Files and directories        2

Instruction Decode Model        3

Running riscv-vip unit tests        4

Instruction unit tests        4

HEX file analyzer unit tests        6

View the functional coverage of scanning the HEX files        6

Generating the HEX files from source, for the hex_file_analyzer        8

Adding riscv-vip to an existing RISC-V core        9

Update your build process to compile and include riscv-vip files        9

Update your testbench        9

Simulator flags        10

Locating the trace file        11

Overview

For pre-silicon developers of RISC-V systems, the riscv-vip project:

License

The riscv-vip project is licensed under the Apache Version 2.0 license.  

The hex files committed in the riscv-vip/riscv_tests_hexgen/build/ directory are generated from assembly *.S files from the riscv-test project, available at https://github.com/riscv/riscv-tests and licensed under its own license.

Community

Files and directories

The main files and directories are shown in the following table.

riscv-vip/

Root of repo

riscv-vip/LICENSE.txt

Apache License

riscv-vip/README.md

Readme file

riscv-vip/RELEASE.txt

Release notes

riscv-vip/doc/

Documentation dir

riscv-vip/doc/index.html

Open in your web browser for documentation.  Also available at https://jerralph.github.io/riscv-vip/doc/index.html 

riscv-vip/src/

Source folder

riscv-vip/src/decoder.svh

Decoder class

riscv-vip/src/hex_file_analyzer.svh

Hex file Analyzer class

riscv-vip/src/hex_file_analyzer_unit_test.sv

Hex file Analyzer unit tests

riscv-vip/src/instruction.svh

Instruction Classes

riscv-vip/src/instruction_unit_test.sv

Instruction unit tests

riscv-vip/src/Makefile

Makefile for running unit tests

riscv-vip/src/riscv_vip_class_pkg.sv

Package of Classes

riscv-vip/src/risc_vip.do

Mentor do file

riscv-vip/src/riscv_vip.f

File list

riscv-vip/src/riscv_vip_if.svh

Interface file

riscv-vip/src/riscv_vip_pkg.sv

Package of parameters, types, structures, constants

riscv-vip/src/uvm/

Folder containing UVM related files

riscv-vip/src/uvm/i32_agent.svh

Passive RV32I UVM Agent

riscv-vip/src/uvm/i32_agent_unit_test.sv

Unit test for RV32I UVM agent

riscv-vip/src/uvm/i32_cov_subscriber.svh

RV32I Coverage subscriber

riscv-vip/src/uvm/i32_item.svh

RV32I Transaction item

riscv-vip/src/uvm/i32_monitor.svh

RV32I Passive monitor

riscv-vip/src/uvm/Makefile

Makefile for running tests

riscv-vip/src/uvm/riscv_vip_uvc.f

UVC file list

riscv-vip/src/uvm/riscv_vip_uvc_pkg.sv

UVC package

riscv-vip/src/uvm/uvc_env.svh

UVC environment

riscv-vip/src/uvm/uvc_env_unit_test.sv

UVC environment unit test

riscv-vip/riscv_tests_hexgen/

Dir for building HEX files from riscv-test source.

riscv-vip/riscv_tests_hexgen/build/

Build dir populated by running make

riscv-vip/riscv_tests_hexgen/build/hex_files.txt

List of HEX files for reading in by the hex_file_analyzer class.

riscv-vip/riscv_tests_hexgen/build/*.hex

Pre-committed HEX files for RV32UI tests generated from the riscv-tests project assembly files from https://github.com/riscv/riscv-tests 

riscv-vip/riscv_tests_hexgen/link.ld

Linker script for generating HEX files from riscv-tests assembly.

riscv-vip/riscv_tests_hexgen/Makefile

Makefile for generated HEX files from riscv-tests assembly

Instruction Decode Model

The decoder class decodes raw bits into the riscv-vip instruction decode model.  The instruction class hierarchy is as follows where the specific formats are derived from the general inst32 class.  For simplicity, many methods are omitted from this diagram.

For example, consider the following code:

       decoder decoder0 = new();

       bit[31:0] inst_bits = 32'hfff08193;    

       inst32 i32 = decoder0.decode_inst32(inst_bits);

       $display("decode of 0x%0H is [ %s ]", inst_bits, i32.to_string());

This will display the following output:

 decode of 0xfff08193 is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

This is an I format add immediate, addi, instruction with an immediate value of -1, using x1 as the source and x3 for the destination register.  For more details on instruction formats and how this is encoded/decoded, refer to the RISC-V specification.

In the inst32_iformat class, there is a coverage bin for non-special I instructions with immediates of -1 (or all 1s in binary), as shown below:

    i32i_imm_cp : coverpoint imm iff ((inst inside {I_NONSPECIAL_INSTS})) {

      bins basics[] = {0,1,2,4};

      bins max_pos =  {`IMM_MAX_POS(imm)};

      bins all_ones = {`IMM_ALL_ONES(imm)};

      bins min_neg =  {`IMM_MIN_NEG(imm)};

    }

Non-special refers to standard I format instructions like ADDI and ANDI.  Non-special I instructions include all I instructions except {SLLI, SRLI, SRAI, FENCE, FENCE.I, ECALL, EBREAK, CSRR*}, which are special -- they have something special/different about them and need to be covered a bit differently.

The following illustrates how coverage is sampled and a generic inst32 is cast to a specific inst32_iformat class:

        //Cast the general inst32 into the more specific inst32_iformat once we're sure it

        //really is an I format.  The coverage should be 0 before sampling then

        //have one bin hit after sampling

        inst32_iformat i32i;        

        assert(i32.is_i_format());

        $cast(i32i,i32);

        cov = i32i.get_nonspecial_imm_cov();

        assert(cov == 0);        

        i32i.sample_cov();

        cov = i32i.get_nonspecial_imm_cov();

        $display("after sample_cov of 0x%0H get_nonspecial_imm_cov() yields %0f", inst_bits, cov);

The resulting output is:

after sample_cov of 0xfff08193 get_nonspecial_imm_cov() yields 14.285714

This is the coverage we expect since 1/7 coverage bins are hit. Such coverage will also show up in the simulator’s coverage database and analysis interfaces.

Running riscv-vip unit tests

During development, unit testing of riscv-vip is done to improve quality and capture usage examples.  Running and examining the unit tests is a great way to better understand the riscv-vip.  Users can easily create their own unit tests to verify their understanding and the workings of the code.

The unit tests will have names of the form *_unit_test.sv.  SVUnit is used for the unit testing framework, this can be obtained from https://github.com/nosnhojn/svunit-code.  Follow the instructions posted there to install.

Instruction unit tests

The instruction unit tests in the instruction_unit_test.sv file exercise and test the decoder and instruction use- cases and functional coverage.

With SVUnit is installed, the tests are run as follows, assuming you are in the riscv-vip/src directory:

% make inst_ut

By default, this will run using Modelsim.  To run in Cadence ius, append SIMR=ius to the above command.

The output looks like this:

runSVUnit -t instruction_unit_test.sv -s modelsim   -f riscv_vip.f

SVUNIT: Output File: ./.__testsuite.sv

SVUNIT: Creating class __testsuite:

SVUNIT: Creating instances for:

...

-- Compiling module testrunner

Top level modules:

        testrunner

End time: 17:08:06 on Jun 08,2018, Elapsed time: 0:00:00

Errors: 0, Warnings: 2

Reading pref.tcl

# 10.6c

# vsim -c -lib work -do "run -all; quit" -l run.log testrunner

# Start time: 17:08:07 on Jun 08,2018

# ** Note: (vsim-3813) Design is being optimized due to module recompilation...

# ** Warning: hex_file_analyzer.sv(54): (vopt-2252) Missing incrementer in "FOR" statement.

# //  Questa Sim

# //  Version 10.6c linux Jul 25 2017

...

# run -all

# INFO:  [0][__ts]: Registering Unit Test Case inst32_ut

# INFO:  [0][testrunner]: Registering Test Suite __ts

# INFO:  [0][__ts]: RUNNING

# INFO:  [0][inst32_ut]: RUNNING

# INFO:  [0][inst32_ut]: ug_example1::RUNNING

# My addi from code is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

# INFO:  [0][inst32_ut]: ug_example1::PASSED

# INFO:  [0][inst32_ut]: ug_example2::RUNNING

# decode of 0xfff08193 is [ fff08193 I ADDI X3_GP, X1_RA, -1 ]

# INFO:  [0][inst32_ut]: ug_example2::PASSED

# INFO:  [0][inst32_ut]: test1::RUNNING

# 0ff0a2f3 I CSRRS X5_T0, X1_RA, 255

# 0010a133 R SLT X2_SP, X1_RA, X1_RA

# INFO:  [0][inst32_ut]: test1::PASSED

# INFO:  [0][inst32_ut]: inst32_sformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_sformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_uformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_uformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_jformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_jformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_bformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_bformat_cov::PASSED

# INFO:  [0][inst32_ut]: inst32_iformat_cov::RUNNING

# INFO:  [0][inst32_ut]: inst32_iformat_cov::PASSED

# INFO:  [0][inst32_ut]: store_to_string::RUNNING

# INFO:  [0][inst32_ut]: store_to_string::PASSED

# INFO:  [0][inst32_ut]: PASSED (9 of 9 tests passing)

#

# INFO:  [0][__ts]: PASSED (1 of 1 testcases passing)

#

# INFO:  [0][testrunner]: PASSED (1 of 1 suites passing) [SVUnit v3.26]

# ** Note: $finish    : .testrunner.sv(40)

#    Time: 0 ns  Iteration: 9  Instance: /testrunner

# End time: 17:08:08 on Jun 08,2018, Elapsed time: 0:00:01

# Errors: 0, Warnings: 1

Have a look into the instruction_unit_test.sv file to better understand what is going on here.  

HEX file analyzer unit tests

The unit test for hex_file_analyzer.sv reads in a list of RV32UI HEX files from the riscv-tests project.  It then dumps out the associated riscv-vip trace and also sampled coverage of every instruction in the HEX files.  

The HEX files for RV32UI generated from the riscv-test project are committed to the riscv-vip repository.  These files were generated from the riscv-test assembly files, as described by the Generating the HEX files from source section, below.  These files have been included for convenience so the user doesn’t need to install the riscv-tools project.

Run the test as follows,  assuming you are in the riscv-vip/src directory:

% make hex_ut

Observe a trace output scroll by, like shown below.  

...

# INFO:  [0][hex_file_analyzer_ut]: analyze_hex_files::RUNNING

# 00000000 04c0006f J JAL X0_ZERO, 76

# 00000004 34202f73 I CSRRS X30_T5, X0_ZERO, 834

# 00000008 00800f93 I ADDI X31_T6, X0_ZERO, 8

# 0000000c 03ff0a63 B BEQ X30_T5, X31_T6 52

# 00000010 00900f93 I ADDI X31_T6, X0_ZERO, 9

# 00000014 03ff0663 B BEQ X30_T5, X31_T6 44

# 00000018 00b00f93 I ADDI X31_T6, X0_ZERO, 11

# 0000001c 03ff0263 B BEQ X30_T5, X31_T6 36

# 00000020 00000f17 U AUIPC X30_T5, 0

# 00000024 fe0f0f13 I ADDI X30_T5, X30_T5, -32

# 00000028 000f0463 B BEQ X30_T5, X0_ZERO 8

...

# 000005c8 0011e193 I ORI X3_GP, X3_GP, 1

# 000005cc 00000073 I ECALL X0_ZERO, X0_ZERO, 0

# 000005d0 0ff0000f I FENCE X0_ZERO, X0_ZERO, 255

# 000005d4 00100193 I ADDI X3_GP, X0_ZERO, 1

# 000005d8 00000073 I ECALL X0_ZERO, X0_ZERO, 0

# 000005dc c0001073 I CSRRW X0_ZERO, X0_ZERO, -1024

# INFO:  [0][hex_file_analyzer_ut]: analyze_hex_files::PASSED

# INFO:  [0][hex_file_analyzer_ut]: PASSED (1 of 1 tests passing)

#

# INFO:  [0][__ts]: PASSED (1 of 1 testcases passing)

#

# INFO:  [0][testrunner]: PASSED (1 of 1 suites passing) [SVUnit v3.26]

# ** Note: $finish    : .testrunner.sv(40)

#    Time: 0 ns  Iteration: 1  Instance: /testrunner

# Saving coverage database on exit...

# End time: 18:49:58 on Jun 11,2018, Elapsed time: 0:00:12

# Errors: 0, Warnings: 0

This is essentially the disassembly of each HEX file. These outputs can be cross referenced / checked against the related disassembly *.DUMP file produced the toolchain.  

View the functional coverage of scanning the HEX files

The coverage scored by sampling HEX file instructions can be analyzed.  It’s important to note that this is not the way coverage is typically done in a verif env, yet it is an interesting experiment none-the-less.  Any execution of these HEX programs would cover a subset of all instructions in the file as scored by the file analyzer.  

The most interesting part is what is missing from the HEX file coverage -- this indicates things that cannot possibly be covered by running the program and potential areas where there could be bugs.

Run the following command, assuming you are in the riscv-vip/src directory and using QuestaSim:

% make cov

The Questa GUI should open.  Goto Window > Covergroups to browse the coverage of the different covergroups.   For example, the following shows what instructions were observed.

Generating the HEX files from source, for the hex_file_analyzer

To generate the RV32UI HEX files from the riscv-test project you must have the riscv-tools project installed from https://github.com/riscv/riscv-tools, this contains the needed gcc compiler toolchain and also contains the riscv-tests as a submodule.  The RISCV_TEST environment variable needs to point to your https://github.com/riscv/riscv-tests installation. If you are installing riscv-tests be sure to follow the instructions in the riscv-tests README.  The RISCV_TEST environment variable can be set by running the following in the riscv-tests install directory:

% export RISCV_TESTS=`pwd`

Now, from the root of your riscv-vip clone:

% cd riscv_tests_hexgen/

% make clean

% make

This hex_file_list target will:

The new HEX files can be run through the hex_file_analyzer class as described in the HEX file analyzer unit tests section.

Adding riscv-vip to an existing RISC-V core

This section is written assuming you have no existing UVM environment and that you want to passively add the riscv-vip to monitor and score coverage for your test.  For those with existing UVM environments, the integration is similar.

Update your build process to compile and include riscv-vip files

Include the following files in your simulation build process, where riscv-vip is your clone of the riscv-vip repo.  

riscv-vip/src/riscv_vip_pkg.sv

riscv-vip/src/riscv_vip_class_pkg.sv

riscv-vip/src/uvm/riscv_vip_uvc_pkg.sv

riscv-vip/src/uvm/test/riscv_vip_test_pkg.sv

Add the following paths to the incdir so the *.svh files included by the pkg files can be located by the simulator.

riscv-vip/src

riscv-vip/src/uvm

riscv-vip/src/uvm/test

Update your testbench

In the module where you instantiate the DUT for testing (generally the testbench or _tb file), tap into instruction and address of the instructions executed on the RISC-V core you are using.  Where and how this interface is connected depends on the implementation of the DUT and what the user wants to accomplish.

The interface to connect is in from riscv_vip_if.svh, and contains the following:

interface riscv_vip_if (input clk, input rstn);

   logic[31:0] curr_pc;

   logic [31:0] curr_inst;  

endinterface

Update the testbench to import and include the needed items.

import uvm_pkg::*;

import riscv_vip_uvc_pkg::*;

import riscv_vip_test_pkg::*;

`include "uvm_macros.svh"

Instantiate the riscv_vip_if interface in the testbench and pass this as a virtual interface into the UVM world using the UVM configuration database.  After this, run the UVM portion of the test.  This will run alongside your pre-existing tests.  Note that uvm_test_top.m_uvc_env is the hierarchical path to the reusable riscv-vip Universal Verification Component (UVC).

//riscv-vip virtual if instantiation

riscv_vip_if rv_vip_if(

  `SOME_XMR_TO_CORE.clk,

  `SOME_XMR_TO_CORE.rstn

);

//use xmrs to connect up the interface

assign rv_vip_if.curr_pc = `SOME_XMR_TO_CORE.pc;      

assign rv_vip_if.curr_inst = `SOME_XMR_TO_CORE.instr;

genvar cores;

generate

  for (core = 0; core < `NUM_CORES; core++) begin : gen_cores

    initial begin : set_riscv_vip_vif_to_db

                     

      uvm_config_db#(virtual riscv_vip_if)::set(

        null,

        $psprintf("uvm_test_top.m_uvc_env.m_i32_agent[%0d]",core),

        "m_vi",

        rv_vip_if

        );

     

      uvm_config_db#(int)::set(

        null,

        $psprintf("uvm_test_top.m_uvc_env.m_i32_agent[%0d]",core),

        "m_core_id",

        core

        );

     

    end      

  end : gen_cores

endgenerate

//Run UVM test

initial begin

  run_test();

end

Simulator flags

For Cadence ius the flags used are

-uvm -sv -exit +licq +nowarn+CUVWSP +nowarn+LIBNOU +nowarn+SPDUSD -linedebug -uvmlinedebug -coverage all -covoverwrite +define+DUMP+TRN +access+rc +UVM_TESTNAME=riscv_vip_base_test

Note that the +UVM_TEST_NAME is passed to the simulator at runtime, as a SystemVerilog plus argument.  

For Mentor Questasim the flags are

-mfcu -incr -sv "+nowarn8233" -warning vlog-2997 "+acc" -R -voptargs="+cover=bcefst" -coverage -do "coverage save -onexit coverage.ucdb" UVM_TESTNAME=riscv_vip_base_test

Locating the trace file

After running a simulation with the riscv_vip_base_test, if things are working correctly, you should find a trace file named riscv_tracker_<core_id>.log in the directory where the simulation is run.

\ No newline at end of file