First RiescueD Test
This tutorial walks you through creating and running a simple directed test, along with some of the basic RiescueD concepts.
Prerequisites
RiESCUE installed (Install and Setup)
Basic RISC-V assembly knowledge
Running RiescueD
RiescueD can be ran from the command line or as a Python library.
CLI Usage
The command line offers allows test writers to iteratively develop tests and run them on an ISS.
To see available options, run:
riescued --help
To generate and compile a test, pass in the test file using `--testname
riescued --testname tutorial_example_test.s
To run the test on an ISS, add the --run_iss
flag. By default this runs on Whisper, but using --iss spike
you can run the test on Spike.
riescued --testname tutorial_example_test.s --run_iss
Python Library Usage
The python library can also be used to build and run tests. Using it in python code allows for more complex test configuration and generation.
With a test tutorial_example_test.s
, the following code will generate and compile the test.
.. code-block:: python
from riescue import RiescueD from pathlib import Path
rd = RiescueD(testfile=Path(“tutorial_example_test.s”)) featmgr = rd.configure(args=None) generator = rd.generate(featmgr) rd.build(featmgr, generator)
A Simple Test
We can start by creating a simple discrete test that does some basic arithmetic and a branch instruction.
Here we will be building a test case with a single discrete test, test01
.
Copy the example test file tutorial_example_test.s
into your working directory:
;#test.author developer@company.com
;#test.arch rv64
;#test.priv machine
;#test.env bare_metal
.section .code, "ax"
test_setup:
# Executed before each test, exactly once
;#test_passed()
;#random_data(name=test_data, type=bits32, and_mask=0xfffffff0)
;#discrete_test(test=test01)
test01:
li t0, test_data
li t1, 0xdeadbeef
add t2, t0, t1
bne t2, x0, test01_pass
;#test_failed()
test01_pass:
;#test_passed()
test_cleanup:
# Executed after all tests are run, exactly once
;#test_passed()
.section .data
RiescueD Test Headers
At the top of the file we have some test headers that begin with ;#test.
.
These headers are key value pairs that can be used to configure the test.
;#test.arch
: Selects the target architecture as rv64
configuring it for the RV64I ISA.
;#test.priv
: Selects the privilege level as machine
configuring it for the Machine mode. This is the privilege that the discrete tests will run in by default.
;#test.env
: Selects the test environment as bare_metal
configuring it for the bare metal environment, not using the hypervisor.
RiescueD Test Structure
The example test contains a few required labels to test code correctly:
test_setup:
Executed before each test, exactly once. This is required
test_cleanup:
This is a required lables executed after all tests are run, exactly once.
;#test_failed()
This indicates a test failed and starts the end of test sequence.
;#test_passed()
This indicates a test passed or some test setup code has finished. It resumes control to the test runtime environment and proceeds to the next test or successful end of test.
RiescueD Directives
The test file uses several RiescueD Directives. These are comments in the code RiescueD parses and uses to configure the test.
These start with ;#
and handle randomizing variables, registering test cases, and managing the test environment.
The directives in this test are:
;#random_data(name=test_data, type=bits32, and_mask=0xfffffff0)
This directive generates random test data as a symbol in the test. The compiler will replace the symbol with a random value.
;#discrete_test(test=test01)
This marks individual test cases. The argument test=test01
is the label of the test case to run.
Run RiescueD and build the test
riescued --testname tutorial_example_test.s
This will generate the test runtime environment, linker script, and compile the test into an ELF binary.
Adding --run_iss
will also run the test on an Instruction Set Simulator to verify the test is valid.
Examining the Output
In your working directory, you should see your compiled ELF tutorial_example_test
along with some test runtime environment .inc
, a linker script, and a disassembly file.
In the disassembly file (tutorial_example_test.dis
) we can see the discrete test was compiled with the test runtime environment in the subroutine test01
:
Disassembly of section .code:
0000000080010122 <test_setup>:
80010122: 0300006f j 80010152 <passed>
0000000080010126 <test01>:
80010126: 008722b7 lui x5,0x872
8001012a: 8602829b addw x5,x5,-1952 # 871860 <test_data>
8001012e: 00038337 lui x6,0x38
80010132: ab73031b addw x6,x6,-1353 # 37ab7 <XLEN+0x37a77>
80010136: 00e31313 sll x6,x6,0xe
8001013a: eef30313 add x6,x6,-273
8001013e: 006283b3 add x7,x5,x6
80010142: 00039463 bnez x7,8001014a <test01_pass>
80010146: 0240006f j 8001016a <failed>
Next Steps
Now that you’ve seen a basic test, you can learn about managing memory and test configurations:
How to randomize data and memory in Randomizing Data & Addresses
How to configure page mapping in Virtual Memory
Learn about Configuration & Memory Map Basics
Explore Randomizing Data & Addresses
For complete documentation of all available directives, see the RiESCUE Directives Reference and Test Headers Reference.