test_interrupt_controller.py
1 from amaranth import * 2 3 from transactron.lib.adapters import AdapterTrans 4 from transactron.testing import TestCaseWithSimulator, TestbenchContext, TestbenchIO 5 from transactron.utils.dependencies import DependencyContext 6 7 from coreblocks.arch import InterruptCauseNumber, PrivilegeLevel 8 from coreblocks.arch.isa_consts import ExceptionCause 9 from coreblocks.interface.keys import CSRInstancesKey 10 from coreblocks.params import GenParams 11 from coreblocks.params.configurations import test_core_config 12 from coreblocks.priv.csr.csr_instances import CSRInstances 13 from coreblocks.priv.traps.interrupt_controller import InternalInterruptController 14 15 16 class InterruptControllerTestCircuit(Elaboratable): 17 def __init__(self, gen_params: GenParams): 18 self.gen_params = gen_params 19 20 def elaborate(self, platform): 21 m = Module() 22 23 m.submodules.csr_instances = self.csr_instances = CSRInstances(self.gen_params) 24 DependencyContext.get().add_dependency(CSRInstancesKey(), self.csr_instances) 25 26 m.submodules.dut = self.dut = InternalInterruptController(self.gen_params) 27 28 m.submodules.entry = self.entry = TestbenchIO(AdapterTrans.create(self.dut.entry)) 29 m.submodules.sret = self.sret = TestbenchIO(AdapterTrans.create(self.dut.sret)) 30 m.submodules.interrupt_cause = self.interrupt_cause = TestbenchIO(AdapterTrans.create(self.dut.interrupt_cause)) 31 32 return m 33 34 35 class TestInterruptControllerSModeTraps(TestCaseWithSimulator): 36 def setup_method(self): 37 self.gen_params = GenParams(test_core_config.replace(supervisor_mode=True, xlen=64, fetch_block_bytes_log=3)) 38 self.tc = InterruptControllerTestCircuit(self.gen_params) 39 40 async def entry_to_supervisor_process(self, sim: TestbenchContext): 41 illegal_instruction = int(ExceptionCause.ILLEGAL_INSTRUCTION) 42 43 sim.set(self.tc.csr_instances.m_mode.priv_mode.value, PrivilegeLevel.USER) 44 sim.set(self.tc.dut.mstatus_sie.value, 1) 45 sim.set(self.tc.dut.medeleg.value, 1 << illegal_instruction) 46 await sim.tick() 47 48 entry = await self.tc.entry.call(sim, cause=illegal_instruction) 49 assert entry["target_priv"] == PrivilegeLevel.SUPERVISOR 50 await sim.tick() 51 52 assert sim.get(self.tc.csr_instances.m_mode.priv_mode.value) == PrivilegeLevel.SUPERVISOR 53 assert sim.get(self.tc.dut.mstatus_sie.value) == 0 54 assert sim.get(self.tc.dut.mstatus_spie.value) == 1 55 assert sim.get(self.tc.dut.mstatus_spp.value) == 0 56 57 async def entry_to_delegated_exception_does_not_reduce_privilege_process(self, sim: TestbenchContext): 58 illegal_instruction = int(ExceptionCause.ILLEGAL_INSTRUCTION) 59 60 sim.set(self.tc.csr_instances.m_mode.priv_mode.value, PrivilegeLevel.MACHINE) 61 sim.set(self.tc.dut.mstatus_mie.value, 1) 62 sim.set(self.tc.dut.medeleg.value, 1 << illegal_instruction) 63 await sim.tick() 64 65 entry = await self.tc.entry.call(sim, cause=illegal_instruction) 66 assert entry["target_priv"] == PrivilegeLevel.MACHINE 67 await sim.tick() 68 69 assert sim.get(self.tc.csr_instances.m_mode.priv_mode.value) == PrivilegeLevel.MACHINE 70 assert sim.get(self.tc.dut.mstatus_mie.value) == 0 71 assert sim.get(self.tc.dut.mstatus_mpie.value) == 1 72 assert sim.get(self.tc.dut.mstatus_mpp.value) == PrivilegeLevel.MACHINE 73 74 async def sret_restores_mode_and_interrupts_process(self, sim: TestbenchContext): 75 sim.set(self.tc.csr_instances.m_mode.priv_mode.value, PrivilegeLevel.SUPERVISOR) 76 sim.set(self.tc.dut.mstatus_sie.value, 0) 77 sim.set(self.tc.dut.mstatus_spie.value, 1) 78 sim.set(self.tc.dut.mstatus_spp.value, 0) 79 await sim.tick() 80 81 await self.tc.sret.call(sim) 82 await sim.tick() 83 84 assert sim.get(self.tc.csr_instances.m_mode.priv_mode.value) == PrivilegeLevel.USER 85 assert sim.get(self.tc.dut.mstatus_sie.value) == 1 86 assert sim.get(self.tc.dut.mstatus_spie.value) == 1 87 assert sim.get(self.tc.dut.mstatus_spp.value) == 0 88 89 async def machine_interrupt_priority_over_supervisor_process(self, sim: TestbenchContext): 90 mei = int(InterruptCauseNumber.MEI) 91 sei = int(InterruptCauseNumber.SEI) 92 93 sim.set(self.tc.csr_instances.m_mode.priv_mode.value, PrivilegeLevel.MACHINE) 94 sim.set(self.tc.dut.mstatus_mie.value, 1) 95 sim.set(self.tc.dut.mstatus_sie.value, 1) 96 sim.set(self.tc.dut.mie.value, (1 << mei) | (1 << sei)) 97 sim.set(self.tc.dut.mideleg.value, 1 << sei) 98 sim.set(self.tc.dut.internal_report_level, (1 << mei) | (1 << sei)) 99 100 for _ in range(8): 101 await sim.tick() 102 if sim.get(self.tc.dut.interrupt_insert): 103 break 104 105 assert sim.get(self.tc.dut.interrupt_insert) == 1 106 await sim.tick() 107 cause = await self.tc.interrupt_cause.call(sim) 108 assert cause["cause"] == mei 109 110 def test_entry_to_supervisor(self): 111 with self.run_simulation(self.tc) as sim: 112 sim.add_testbench(self.entry_to_supervisor_process) 113 114 def test_entry_to_delegated_exception_does_not_reduce_privilege(self): 115 with self.run_simulation(self.tc) as sim: 116 sim.add_testbench(self.entry_to_delegated_exception_does_not_reduce_privilege_process) 117 118 def test_sret_restores_mode_and_interrupts(self): 119 with self.run_simulation(self.tc) as sim: 120 sim.add_testbench(self.sret_restores_mode_and_interrupts_process) 121 122 def test_machine_interrupt_priority_over_supervisor(self): 123 with self.run_simulation(self.tc) as sim: 124 sim.add_testbench(self.machine_interrupt_priority_over_supervisor_process)