OpenCores
URL https://opencores.org/ocsvn/fwrisc/fwrisc/trunk

Subversion Repositories fwrisc

[/] [fwrisc/] [trunk/] [doc/] [fwrisc_verification.md] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 mballance
# FWRISC Verification
2
 
3
FWRISC uses Verilator as the HDL simulator, and uses a [Googletest](https://github.com/abseil/googletest)-based testbench environment. The HDL top-level is written
4
in Verilog, while the testbench and tests are implemented in C++.
5
 
6
FWRISC currently has two testbench environments:
7
- Core-level testbench, which is used for unit tests, compliance tests, and Zephyr tests
8
- System-level testbench, which is used to sanity-test the FPGA top-level
9
 
10
The core-level testbench is located in the fwrisc/ve/fwrisc directory. The system-level testbench
11
is located in the fwrisc/ve/fwrisc_fpga directory.
12
 
13
## Core-level Tests
14
 
15
A diagram of the core-level testbench is shown below:
16
 
17
 
18
![alt text](imgs/unit_testbench_crop.png)
19
 
20
The _tracer_ module uses SV-DPI functions to send register-write, memory-write, and instruction trace
21
events to the testbench. These events are used to verify the result of running tests, as well
22
as implement features like function trace and the Zephyr RAM console.
23
 
24
 
25
### Unit Tests
26
 
27
The unit tests are each designed to test a single instruction of feature of the core. As such,
28
the goal is to keep each of these tests as short as possible. The test programs are captured
29
in-line as part of the test. The expected results are captured within the test as well.
30
 
31
Here is an example unit test for the add-imediate instruction:
32
 
33
```
34
TEST_F(fwrisc_instr_tests_arith, addi) {
35
        reg_val_s exp[] = {
36
                        {1, 5},
37
                        {3, 11}
38
        };
39
        const char *program = R"(
40
                entry:
41
                        li              x1, 5
42
                        add             x3, x1, 6
43
                        j               done
44
                        )";
45
 
46
        runtest(program, exp, sizeof(exp)/sizeof(reg_val_s));
47
}
48
```
49
 
50
All unit tests are expected to terminate by jumping to the 'done' symbol. The expected register-value array
51
specifies expected values for all accessed registers. Any registers that are unexpectedly accessed or
52
registers with an unexpected value will be reported as an error.
53
 
54
### Compliance Tests
55
Each compliance test runs one of the RISC-V RV32I compliance tests. Success of compliance tests is
56
judged by comparing a region of memory to a reference file. The compliance tests determine where this
57
region of memory is located by reading the ELF symbol table from the test executable, then comparing
58
the memory written during simulation against the content of memory at the end of the run.
59
 
60
 
61
### Zephyr Tests
62
With the exception of the 'Hello World' test, Zephyr tests tend to run for a long time. Consequently,
63
it is recommended to run these tests individually and interactively.
64
 
65
The Zephyr tests support two command-line options for debug purposes:
66
- +TRACE_FUNCS -- Displays a trace of function entry/exit driven by symbols read from the ELF file and the execution trace
67
- +TRACE_INSTR -- Displays each instruction that is executed.
68
 
69
The function trace is very helpful at debugging bringup of a new Zephyr port. Here is a trace of the beginning of Zephyr boot:
70
 
71
```
72
  ==> __initialize
73
    ==> _PrepC
74
      ==> _bss_zero
75
        ==> memset
76
          ==>
77
          <==
78
        ==> _data_copy
79
          ==> memcpy
80
            ==>
81
            <==
82
          ==> _Cstart
83
            ==> memset
84
              ==>
85
              <==
86
            <== memset
87
            ==> _sys_device_do_config_level
88
              ==> ram_console_init
89
                ==> __printk_hook_install
90
                <== __printk_hook_install
91
                ==> __stdout_hook_install
92
                <== __stdout_hook_install
93
              <== ram_console_init
94
            <== _sys_device_do_config_level
95
            ==> _sys_device_do_config_level
96
              ==> z_clock_driver_init
97
              <== z_clock_driver_init
98
            <== _sys_device_do_config_level
99
            ==> _sched_init
100
              ==> reset_time_slice
101
                ==> _get_next_timeout_expiry
102
                  ==> k_spin_lock.isra.1
103
                  <== k_spin_lock.isra.1
104
                <== _get_next_timeout_expiry
105
                ==> z_clock_elapsed
106
                <== z_clock_elapsed
107
                ==> z_clock_set_timeout
108
            <== _sched_init
109
            ==> _setup_new_thread
110
              ==> _new_thread
111
                ==> _init_thread_base
112
                <== _init_thread_base
113
              <== _new_thread
114
            <== _setup_new_thread
115
```
116
 
117
The simulation-based Zephyr board definition uses the RAM console to display messages. The Zephyr-tests testbench
118
determines the local of the RAM console by reading the ELF symbol table. Messages sent to the RAM console are
119
displayed on the terminal with a '#' prefix. For example:
120
 
121
```
122
# ***** Booting Zephyr OS zephyr-v1.13.0-1808-gd18ff80 *****
123
# threadA: Hello World from fwrisc_sim!
124
# threadB: Hello World from fwrisc_sim!
125
# threadA: Hello World from fwrisc_sim!
126
# threadB: Hello World from fwrisc_sim!
127
 
128
```
129
 
130
 
131
## System-level Tests
132
The System-level tests have a similar structure to the unit-level tests. The main difference is that the testbench
133
only has access to the LED and UART Tx signals on the boundary of the design.
134
 
135
 
136
## Running a Test
137
 
138
Tests for both core- and system-level environments are run from the respective 'sim' directory using the _runtest.pl_ script.
139
Before running a test, be sure to configure your tool environment and source the FWRISC project setup script.
140
 
141
Each test is described using a test file in the 'tests' subdirectory. The test file specifies which GoogleTest
142
testcase to run, and any options to pass to the test. Here is the test file for the 'ECALL' unit test:
143
 
144
```
145
--gtest_filter=fwrisc_instr_tests_system.ecall
146
```
147
 
148
Here is the test file for the ADDI RISCV compliance test:
149
 
150
```
151
+SW_IMAGE=${BUILD_DIR}/esw/I-ADDI-01.elf
152
+REF_FILE=${FWRISC}/ve/fwrisc/tests/riscv-compliance/riscv-test-suite/rv32i/references/I-ADDI-01.reference_output
153
--gtest_filter=riscv_compliance_tests.coretest
154
 
155
```
156
 
157
Note how the ELF file and reference file are specified as plusargs to the test.
158
 
159
The example below shows how to run the 'ECALL' unit test:
160
 
161
```
162
% cd fwrisc/ve/fwrisc/sim
163
% runtest.pl -test tests/fwrisc_instr_tests_system_ecall.f
164
```
165
 
166
 
167
## Running a Testlist
168
 
169
Test suites are captured using testlists. Running a testlist is also done using the _runtest.pl_ script.
170
Here is an example of how to run the RISCV Compliance Tests testlist:
171
 
172
```
173
% cd fwrisc/ve/fwrisc/sim
174
% runtest.pl -testlist testlists/fwrisc_riscv_compliance_tests.tl
175
```
176
 
177
 
178
The full test suite is run with the fwrisc_riscv_all_tests.tl testlist:
179
 
180
```
181
% cd fwrisc/ve/fwrisc/sim
182
% runtest.pl -testlist testlists/fwrisc_riscv_all_tests.tl
183
```
184
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.