diff --git a/riscemu/priv/CSR.py b/riscemu/priv/CSR.py index ef35763..32bbb97 100644 --- a/riscemu/priv/CSR.py +++ b/riscemu/priv/CSR.py @@ -41,6 +41,11 @@ class CSR: All Control and Status Registers are stored here """ + virtual_regs: Dict[int, Callable[[], int]] + """ + list of virtual CSR registers, with values computed on read + """ + name_to_addr: Dict[str, int] = { 'mstatus': 0x300, 'misa': 0x301, @@ -56,7 +61,9 @@ class CSR: 'mhartid': 0xF14, 'time': 0xc01, 'timeh': 0xc81, - 'halt': 0x789 + 'halt': 0x789, + 'mtimecmp': 0x780, + 'mtimecmph': 0x781, } """ Translation for named registers @@ -67,6 +74,7 @@ class CSR: def __init__(self): self.regs = defaultdict(lambda: 0) self.listeners = defaultdict(lambda: (lambda x, y: None)) + #TODO: implement write masks (bitmasks which control writeable bits in registers def set(self, addr: Union[str, int], val: int): addr = self._addr_to_name(addr) @@ -75,15 +83,18 @@ class CSR: self.listeners[addr](self.regs[addr], val) self.regs[addr] = val - def get(self, addr: Union[str, int]): + def get(self, addr: Union[str, int]) -> int: addr = self._addr_to_name(addr) if addr is None: return + if addr in self.virtual_regs: + return self.virtual_regs[addr]() return self.regs[addr] def set_listener(self, addr: Union[str, int], listener: Callable[[int, int], None]): addr = self._addr_to_name(addr) if addr is None: + print("unknown csr address name: {}".format(addr)) return self.listeners[addr] = listener @@ -107,7 +118,7 @@ class CSR: new_val = erased | (val << off) self.set('mstatus', new_val) - def get_mstatus(self, name): + def get_mstatus(self, name) -> int: size = 2 if name in MSTATUS_LEN_2 else 1 off = MSTATUS_OFFSETS[name] mask = (2**size - 1) << off @@ -134,3 +145,14 @@ class CSR: return None return self.name_to_addr[addr] return addr + + def virtual_register(self, addr: Union[str, int]): + addr = self._addr_to_name(addr) + if addr is None: + print("unknown csr address name: {}".format(addr)) + + def inner(func: Callable[[], int]): + self.virtual_regs[addr] = func + return func + + return inner