/ test / priv / traps / test_interrupt_controller.py
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)