[CSR] added read/write checks and unified name to addr resuloution

kernel-mode
Anton Lydike 4 years ago
parent 291f44a192
commit 49b59cd46a

@ -1,6 +1,7 @@
from typing import Dict, Union, Callable from typing import Dict, Union, Callable, Optional
from collections import defaultdict from collections import defaultdict
from functools import wraps from .privmodes import PrivModes
from .Exceptions import IllegalInstructionTrap
MSTATUS_OFFSETS = { MSTATUS_OFFSETS = {
'uie': 0, 'uie': 0,
@ -68,27 +69,22 @@ class CSR:
self.listeners = defaultdict(lambda: (lambda x, y: None)) self.listeners = defaultdict(lambda: (lambda x, y: None))
def set(self, addr: Union[str, int], val: int): def set(self, addr: Union[str, int], val: int):
if isinstance(addr, str): addr = self._addr_to_name(addr)
if addr not in self.name_to_addr: if addr is None:
print("Unknown CSR register {}".format(addr)) return
return
addr = self.name_to_addr[addr]
self.listeners[addr](self.regs[addr], val) self.listeners[addr](self.regs[addr], val)
self.regs[addr] = val self.regs[addr] = val
def get(self, addr: Union[str, int]): def get(self, addr: Union[str, int]):
if isinstance(addr, str): addr = self._addr_to_name(addr)
if addr not in self.name_to_addr: if addr is None:
print("Unknown CSR register {}".format(addr)) return
return
addr = self.name_to_addr[addr]
return self.regs[addr] return self.regs[addr]
def set_listener(self, addr: Union[str, int], listener: Callable[[int, int], None]): def set_listener(self, addr: Union[str, int], listener: Callable[[int, int], None]):
if isinstance(addr, str): addr = self._addr_to_name(addr)
if not addr in self.name_to_addr: if addr is None:
print("Unknown CSR register {}".format(addr)) return
addr = self.name_to_addr[addr]
self.listeners[addr] = listener self.listeners[addr] = listener
# mstatus properties # mstatus properties
@ -122,3 +118,19 @@ class CSR:
self.set_listener(addr, func) self.set_listener(addr, func)
return func return func
return inner return inner
def assert_can_read(self, mode: PrivModes, addr: int):
if (addr >> 8) & 3 > mode.value():
raise IllegalInstructionTrap()
def assert_can_write(self, mode: PrivModes, addr: int):
if (addr >> 8) & 3 > mode.value() or addr >> 10 == 11:
raise IllegalInstructionTrap()
def _addr_to_name(self, addr: Union[str, int]) -> Optional[int]:
if isinstance(addr, str):
if addr not in self.name_to_addr:
print("Unknown CSR register {}".format(addr))
return None
return self.name_to_addr[addr]
return addr

@ -21,11 +21,15 @@ class PrivRV32I(RV32I):
""" """
def instruction_csrrw(self, ins: 'LoadedInstruction'): def instruction_csrrw(self, ins: 'LoadedInstruction'):
rd, rs, ind = self.parse_crs_ins(ins) rd, rs, csr_addr = self.parse_crs_ins(ins)
if rd != 'zero': if rd != 'zero':
old_val = int_from_bytes(self.cpu.csr[ind]) self.cpu.csr.assert_can_read(self.cpu.mode, csr_addr)
old_val = self.cpu.csr.get(csr_addr)
self.regs.set(rd, old_val) self.regs.set(rd, old_val)
self.cpu.csr.set(ind, rs) if rs != 'zero':
new_val = self.regs.get(rs)
self.cpu.csr.assert_can_write(self.cpu.mode, csr_addr)
self.cpu.csr.set(csr_addr, new_val)
def instruction_csrrs(self, ins: 'LoadedInstruction'): def instruction_csrrs(self, ins: 'LoadedInstruction'):
INS_NOT_IMPLEMENTED(ins) INS_NOT_IMPLEMENTED(ins)
@ -122,7 +126,7 @@ class PrivRV32I(RV32I):
def parse_crs_ins(self, ins: 'LoadedInstruction'): def parse_crs_ins(self, ins: 'LoadedInstruction'):
ASSERT_LEN(ins.args, 3) ASSERT_LEN(ins.args, 3)
return ins.get_reg(0), self.get_reg_content(ins, 1), ins.get_imm(2) return ins.get_reg(0), ins.get_reg(1), ins.get_imm(2)
def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]: def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
ASSERT_LEN(ins.args, 3) ASSERT_LEN(ins.args, 3)

Loading…
Cancel
Save