kernel-mode #1
@ -3,8 +3,17 @@ from typing import Optional
|
||||
|
||||
class CpuTrap(BaseException):
|
||||
code: int
|
||||
"""
|
||||
31-bit value encoding the exception code in the mstatus register
|
||||
"""
|
||||
interrupt: int
|
||||
"""
|
||||
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
|
||||
|
@ -3,21 +3,16 @@ RiscEmu (c) 2021 Anton Lydike
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
"""
|
||||
import time
|
||||
|
||||
from riscemu.CPU import *
|
||||
from enum import IntEnum
|
||||
from riscemu.Executable import LoadedMemorySection
|
||||
from .Exceptions import *
|
||||
from .CSR import CSR
|
||||
from .PrivRV32I import PrivRV32I
|
||||
from ..instructions.RV32M import RV32M
|
||||
from .PrivMMU import PrivMMU
|
||||
from .ElfLoader import ElfExecutable
|
||||
from .Exceptions import *
|
||||
from .PrivMMU import PrivMMU
|
||||
from .PrivRV32I import PrivRV32I
|
||||
from .privmodes import PrivModes
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from typing import Union
|
||||
from ..instructions.RV32M import RV32M
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from riscemu import Executable, LoadedExecutable, LoadedInstruction
|
||||
@ -33,6 +28,14 @@ class PrivCPU(CPU):
|
||||
"""
|
||||
|
||||
csr: CSR
|
||||
"""
|
||||
Reference to the control and status registers
|
||||
"""
|
||||
|
||||
TIME_RESOLUTION_NS: int = 1000000
|
||||
"""
|
||||
controls the resolution of the time csr register (in nanoseconds)
|
||||
"""
|
||||
|
||||
INS_XLEN = 4
|
||||
"""
|
||||
@ -49,6 +52,14 @@ class PrivCPU(CPU):
|
||||
self.pc = kernel.run_ptr
|
||||
self.syscall_int = None
|
||||
|
||||
self.launch_debug = False
|
||||
|
||||
self.pending_traps: List[CpuTrap] = list()
|
||||
|
||||
self._time_start = 0
|
||||
self._time_timecmp = 0
|
||||
self._time_interrupt_enabled = False
|
||||
|
||||
# init csr
|
||||
self._init_csr()
|
||||
|
||||
@ -58,59 +69,23 @@ class PrivCPU(CPU):
|
||||
ins = None
|
||||
try:
|
||||
while not self.exit:
|
||||
try:
|
||||
self.cycle += 1
|
||||
ins = self.mmu.read_ins(self.pc)
|
||||
if verbose:
|
||||
print(FMT_CPU + " Running 0x{:08X}:{} {}".format(self.pc, FMT_NONE, ins))
|
||||
self.run_instruction(ins)
|
||||
self.pc += self.INS_XLEN
|
||||
except CpuTrap as trap:
|
||||
mie = self.csr.get_mstatus('mie')
|
||||
if not mie:
|
||||
print("Caught trap while mie={}!".format(mie))
|
||||
# TODO: handle this a lot better
|
||||
continue
|
||||
# raise trap
|
||||
|
||||
# caught a trap!
|
||||
self.csr.set('mepc', self.pc) # store MEPC
|
||||
self.csr.set_mstatus('mpp', self.mode) # save mpp
|
||||
self.csr.set_mstatus('mpie', mie) # save mie
|
||||
self.csr.set_mstatus('mie', 0) # disable further interrupts
|
||||
self.csr.set('mcause', trap.mcause) # store cause
|
||||
|
||||
# set mtval csr
|
||||
self.csr.set('mtval', trap.mtval)
|
||||
|
||||
# set priv mode to machine
|
||||
self.mode = PrivModes.MACHINE
|
||||
|
||||
# trap vector
|
||||
mtvec = self.csr.get('mtvec')
|
||||
if mtvec & 3 == 1:
|
||||
# vectored mode!
|
||||
self.pc = (mtvec >> 2) + (self.INS_XLEN * trap.code)
|
||||
else:
|
||||
# standard mode
|
||||
self.pc = (mtvec >> 2)
|
||||
self.step(verbose=False)
|
||||
except RiscemuBaseException as ex:
|
||||
if not isinstance(ex, LaunchDebuggerException):
|
||||
if isinstance(ex, LaunchDebuggerException):
|
||||
self.launch_debug = True
|
||||
else:
|
||||
print(FMT_ERROR + "[CPU] excpetion caught at 0x{:08X}: {}:".format(self.pc - 1, ins) + FMT_NONE)
|
||||
print(ex.message())
|
||||
self.pc -= 1
|
||||
|
||||
if self.active_debug:
|
||||
print(FMT_CPU + "[CPU] Returning to debugger!" + FMT_NONE)
|
||||
return
|
||||
if self.conf.debug_on_exception:
|
||||
launch_debug_session(self, self.mmu, self.regs,
|
||||
"Exception encountered, launching debug:")
|
||||
|
||||
if self.conf.debug_on_exception:
|
||||
self.launch_debug = True
|
||||
if self.exit:
|
||||
print()
|
||||
print(FMT_CPU + "Program exited with code {}".format(self.exit_code) + FMT_NONE)
|
||||
sys.exit(self.exit_code)
|
||||
elif self.launch_debug:
|
||||
launch_debug_session(self, self.mmu, self.regs,
|
||||
"Launching debugger:")
|
||||
self._run(verbose)
|
||||
else:
|
||||
print()
|
||||
print(FMT_CPU + "Program stopped without exiting - perhaps you stopped the debugger?" + FMT_NONE)
|
||||
@ -126,6 +101,7 @@ class PrivCPU(CPU):
|
||||
|
||||
def run(self):
|
||||
print(FMT_CPU + '[CPU] Started running from 0x{:08X} ({})'.format(self.pc, "kernel") + FMT_NONE)
|
||||
self._time_start = time.perf_counter_ns() // self.TIME_RESOLUTION_NS
|
||||
self._run(True)
|
||||
|
||||
def _init_csr(self):
|
||||
@ -133,10 +109,12 @@ class PrivCPU(CPU):
|
||||
self.csr = CSR()
|
||||
self.csr.set('mhartid', 0) # core id
|
||||
# TODO: set correct value
|
||||
self.csr.set('mimpid', 1) # implementation id
|
||||
self.csr.set('mimpid', 0) # implementation id
|
||||
# set mxl to 1 (32 bit) and set bits for i and m isa
|
||||
self.csr.set('misa', (1 << 30) + (1 << 8) + (1 << 12)) # available ISA
|
||||
|
||||
# CSR write callbacks:
|
||||
|
||||
@self.csr.callback('halt')
|
||||
def halt(old: int, new: int):
|
||||
if new != 0:
|
||||
@ -146,3 +124,52 @@ class PrivCPU(CPU):
|
||||
@self.csr.callback('mstatus')
|
||||
def mstatus(old: int, new: int):
|
||||
pass
|
||||
|
||||
@self.csr.callback('mtimecmp')
|
||||
def mtimecmp(old, new):
|
||||
self._time_timecmp = (self.csr.get('mtimecmph') << 32) + new
|
||||
self._time_interrupt_enabled = True
|
||||
|
||||
@self.csr.callback('mtimecmph')
|
||||
def mtimecmp(old, new):
|
||||
self._time_timecmp = (new << 32) + self.csr.get('mtimecmp')
|
||||
self._time_interrupt_enabled = True
|
||||
|
||||
# virtual CSR registers:
|
||||
|
||||
@self.csr.virtual_register('time')
|
||||
def get_time():
|
||||
return (time.perf_counter_ns() // self.TIME_RESOLUTION_NS) & (2 ** 32 - 1)
|
||||
|
||||
@self.csr.virtual_register('timeh')
|
||||
def get_timeh():
|
||||
return (time.perf_counter_ns() // self.TIME_RESOLUTION_NS) >> 32
|
||||
|
||||
# add minstret and mcycle counters
|
||||
|
||||
def _handle_trap(self, trap: CpuTrap):
|
||||
# implement trap handling!
|
||||
self.pending_traps.append(trap)
|
||||
|
||||
def step(self, verbose = True):
|
||||
try:
|
||||
self.cycle += 1
|
||||
self._timer_step()
|
||||
self._check_interrupt()
|
||||
ins = self.mmu.read_ins(self.pc)
|
||||
if verbose:
|
||||
print(FMT_CPU + " Running 0x{:08X}:{} {}".format(self.pc, FMT_NONE, ins))
|
||||
self.run_instruction(ins)
|
||||
self.pc += self.INS_XLEN
|
||||
except CpuTrap as trap:
|
||||
self._handle_trap(trap)
|
||||
|
||||
def _timer_step(self):
|
||||
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._time_interrupt_enabled = False
|
||||
|
||||
def _check_interrupt(self):
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user