diff --git a/riscemu/priv/CSR.py b/riscemu/priv/CSR.py index b7b007e..2b1b1c6 100644 --- a/riscemu/priv/CSR.py +++ b/riscemu/priv/CSR.py @@ -1,7 +1,7 @@ from typing import Dict, Union, Callable, Optional from collections import defaultdict from .privmodes import PrivModes -from .Exceptions import IllegalInstructionTrap +from .Exceptions import InstructionAccessFault from ..helpers import to_unsigned MSTATUS_OFFSETS = { diff --git a/riscemu/priv/Exceptions.py b/riscemu/priv/Exceptions.py index 60e653a..fd0dac8 100644 --- a/riscemu/priv/Exceptions.py +++ b/riscemu/priv/Exceptions.py @@ -1,5 +1,16 @@ -from typing import Optional +from typing import Optional, NewType +from enum import Enum +from .privmodes import PrivModes +import typing +if typing.TYPE_CHECKING: + from .ElfLoader import ElfInstruction + +class CpuTrapType(Enum): + TIMER = 1 + SOFTWARE = 2 + EXTERNAL = 3 + EXCEPTION = 4 class CpuTrap(BaseException): code: int @@ -10,17 +21,28 @@ class CpuTrap(BaseException): """ The isInterrupt bit in the mstatus register """ + mtval: int """ contents of the mtval register """ - def __init__(self, interrupt: int, code: int, mtval=0): - assert 0 <= interrupt <= 1 + type: CpuTrapType + """ + The type (timer, external, software) of the trap + """ + + priv: PrivModes + """ + The privilege level this trap targets + """ - self.interrupt = interrupt + def __init__(self, code: int, mtval, type: CpuTrapType, priv: PrivModes = PrivModes.MACHINE): + self.interrupt = 0 if type == CpuTrapType.EXCEPTION else 1 self.code = code self.mtval = mtval + self.priv = priv + self.type = type @property def mcause(self): @@ -28,17 +50,20 @@ class CpuTrap(BaseException): class IllegalInstructionTrap(CpuTrap): - def __init__(self): - super().__init__(0, 2, 0) + def __init__(self, ins: 'ElfInstruction'): + super().__init__(2, ins.encoded, CpuTrapType.EXCEPTION) class InstructionAddressMisalignedTrap(CpuTrap): def __init__(self, addr: int): - super().__init__(0, 0, addr) + super().__init__(0, addr, CpuTrapType.EXCEPTION) class InstructionAccessFault(CpuTrap): def __init__(self, addr: int): - super().__init__(0, 1, addr) + super().__init__(1, addr, CpuTrapType.EXCEPTION) +class TimerInterrupt(CpuTrap): + def __init(self): + super().__init__(7, 0, CpuTrapType.TIMER) diff --git a/riscemu/priv/PrivCPU.py b/riscemu/priv/PrivCPU.py index fe0df86..ed5d3db 100644 --- a/riscemu/priv/PrivCPU.py +++ b/riscemu/priv/PrivCPU.py @@ -169,7 +169,7 @@ class PrivCPU(CPU): if not self._time_interrupt_enabled: return if self._time_timecmp < (time.perf_counter_ns() // self.TIME_RESOLUTION_NS) - self._time_start: - self.pending_traps.append(CpuTrap(1, 7, 0)) + self.pending_traps.append(TimerInterrupt()) self._time_interrupt_enabled = False def _check_interrupt(self): diff --git a/riscemu/priv/PrivRV32I.py b/riscemu/priv/PrivRV32I.py index 1c17791..be808f6 100644 --- a/riscemu/priv/PrivRV32I.py +++ b/riscemu/priv/PrivRV32I.py @@ -49,7 +49,7 @@ class PrivRV32I(RV32I): def instruction_mret(self, ins: 'LoadedInstruction'): if self.cpu.mode != PrivModes.MACHINE: print("MRET not inside machine level code!") - raise IllegalInstructionTrap() + raise IllegalInstructionTrap(ins) # retore mie mpie = self.cpu.csr.get_mstatus('mpie') self.cpu.csr.set_mstatus('mie', mpie) @@ -61,21 +61,21 @@ class PrivRV32I(RV32I): self.cpu.pc = mepc def instruction_uret(self, ins: 'LoadedInstruction'): - raise IllegalInstructionTrap() + raise IllegalInstructionTrap(ins) def instruction_sret(self, ins: 'LoadedInstruction'): - raise IllegalInstructionTrap() + raise IllegalInstructionTrap(ins) def instruction_scall(self, ins: 'LoadedInstruction'): """ Overwrite the scall from userspace RV32I """ if self.cpu.mode == PrivModes.USER: - raise CpuTrap(0, 8) # ecall from U mode + raise CpuTrap(8, 0, CpuTrapType.SOFTWARE, self.cpu.mode) # ecall from U mode elif self.cpu.mode == PrivModes.SUPER: - raise CpuTrap(0, 9) # ecall from S mode - should not happen + raise CpuTrap(9, 0, CpuTrapType.SOFTWARE, self.cpu.mode) # ecall from S mode - should not happen elif self.cpu.mode == PrivModes.MACHINE: - raise CpuTrap(0, 11) # ecall from M mode + raise CpuTrap(11, 0, CpuTrapType.SOFTWARE, self.cpu.mode) # ecall from M mode def instruction_beq(self, ins: 'LoadedInstruction'): rs1, rs2, dst = self.parse_rs_rs_imm(ins)