Modifying End of Test (EOT) Code
This user guide covers how to modify the end of test (EOT) code in Riescue as well as an example on how to write EOT code for each hart in the test.
Default EOT
The default EOT code is generated by Riescue.
By default it writes a 0x1 (pass) or 0x3 (fail) to tohost, and then halts the test.
See the EOT reference (End of Test (EOT)) for more information on the default EOT code.
Overriding EOT Code
EOT code can be overridden using hooks that insert code, byt using the riescue.FeatMgr.register_hook() method with different riescue.lib.enums.HookPoint enum values
For example setting the PRE_HALT hook to insert code before the hart is halted.
See the FeatMgr reference (FeatMgr) for more information on how to use hooks.
Simple EOT Pass and Fail Hooks
A simple case is to to write a custom value to an address on pass and fail. This can be accomplished by writing a couple python functions that generate assembly code.
In order to register a function as a “hook”, the function needs to accept a FeatMgr instance and return a string.
E.g.
from riescue import FeatMgr
def test_passed(featmgr: FeatMgr) -> str:
"Write PASS in ASCII to the EOT address"
return """
# Custom Pass EOT
li t0, 0x10000000
li t1, 0x50415353 # PASS
sw t1, 0(t0)
""""
def test_failed(featmgr: FeatMgr) -> str:
"Write FAIL in ASCII to the EOT address"
return """
# Custom Fail EOT
li t0, 0x10000000
li t1, 0x4641494C # FAIL
sw t1, 0(t0)
""""
Next these methods need to be registered as PRE_PASS and PRE_FAIL hooks.
The simplest way to do this is to use a Conf script and passing it to RiescueD.
Using a Conf script
Conf scripts are python files that contain a setup() method that returns an instance of a riescue.Conf subclass.
The simplest way to do this is to write a conf.py python file with the overridden content, then pass it into RiescueD or RiescueC using the --conf command-line option.
To implement the simple EOT Pas and Fail Hooks, those methods can be added as instance methods to a Conf subclass.
Then the riescue.Conf.add_hooks() needs to register the hooks.
# conf.py
from riescue import Conf, FeatMgr
from riescue.lib.enums import HookPoint
class MyEotConf(Conf):
def test_passed(self, featmgr: FeatMgr) -> str:
"Write PASS in ASCII to the EOT address"
return """
li t0, 0x10000000
li t1, 0x50415353 # PASS
sw t1, 0(t0)
""""
def test_failed(self, featmgr: FeatMgr) -> str:
"Write FAIL in ASCII to the EOT address"
return """
li t0, 0x10000000
li t1, 0x4641494C # FAIL
sw t1, 0(t0)
""""
def add_hooks(self, featmgr: FeatMgr) -> None:
featmgr.register_hook(HookPoint.PRE_PASS, self.test_passed)
featmgr.register_hook(HookPoint.PRE_FAIL, self.test_failed)
def setup() -> Conf:
return MyEotConf()
This conf.py Conf script can be passed to RiescueD or RiescueC using --conf. E.g.
riescued --testfile test.s --conf conf.py
riescuec --json rv64i.json --conf conf.py
The Conf reference (Conf) for more information on how to use Conf scripts.
Example MP Mode EOT Code with a Conf script
For example if a platform requires that each hart writes to an address + (hartID * offset), the user can use the PRE_PASS and PRE_FAIL hooks to insert code before and after the test is marked as passed.
The riescue.FeatMgr has the num_cpus attribute which includes the number of harts in the test.
This can be accessed in a Hook to generaet EOT sequence for each hart in the test.
E.g. For a platform that requires:
EOT address =
0x7000_0000+ (hartID *0x10)EOT Pass Value =
0x11EOT Fail Value =
0x13
# conf.py
from riescue import RiescueD, FeatMgr, Conf
from riescue.lib.enums import HookPoint
def end_test(num_cpus: int, eot_value: int) -> str:
"""
Generates EOT sequence for given eot value.
:param hart_id: The hart ID
:param eot_value: The value to write to tohost
"""
code = f"li t0, {eot_value}\n"
for hart_id in range(num_cpus):
address = 0x7000_0000 + (hart_id * 0x10)
code += f"li t1, 0x{address:x}\n"
code += f"sw t0, 0(t1)\n"
return code
def test_passed(featmgr: FeatMgr) -> str:
return end_test(featmgr.num_cpus, 0x11)
def test_failed(featmgr: FeatMgr) -> str:
return end_test(featmgr.num_cpus, 0x13)
class CustomEot(Conf):
def add_hooks(self, featmgr: FeatMgr) -> None:
featmgr.register_hook(HookPoint.PRE_PASS, test_passed)
featmgr.register_hook(HookPoint.PRE_FAIL, test_failed)
def setup() -> Conf:
return CustomEot()
It uses FeatMgr.num_cpus to get the number of harts in the test and then generates the EOT sequence for each hart.
riescued --testfile test.s --conf conf.py --num_cpus 2
riescuec --json rv64i.json --conf conf.py
References
EOT Reference: End of Test (EOT)
FeatMgr Reference: FeatMgr
Conf Reference: Conf