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 (:doc:`../reference/riescue_runtime/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 :py:meth:`riescue.FeatMgr.register_hook` method with different :py:class:`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 (:doc:`../reference/python_api/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. .. code-block:: python 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 :py:class:`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 :py:meth:`riescue.Conf.add_hooks` needs to register the hooks. .. code-block:: python # 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. .. code-block:: bash riescued --testfile test.s --conf conf.py riescuec --json rv64i.json --conf conf.py The Conf reference (:doc:`../reference/python_api/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 :py:class:`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 = ``0x11`` - EOT Fail Value = ``0x13`` .. code-block:: python # 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. .. code-block:: bash riescued --testfile test.s --conf conf.py --num_cpus 2 riescuec --json rv64i.json --conf conf.py References ----------- - EOT Reference: :doc:`../reference/riescue_runtime/eot` - FeatMgr Reference: :doc:`../reference/python_api/FeatMgr` - Conf Reference: :doc:`../reference/python_api/Conf`