"""Abstract hardware machine with CPU and memory.""" import enum from typing import Dict, Tuple, Callable, Optional from py65 import memory as py65_memory class AccessMode(enum.IntFlag): READ = 0x1 WRITE = 0x2 RW = READ | WRITE class Event(object): def __init__(self, event_type, details): self.event_type = event_type self.details = details def __str__(self) -> str: return "Event(%s): %s" % (self.event_type, self.details) def Log(region:str, message:str): print("%s event: %s" % (region, message)) # TODO: why? def _Event(region:str, message:str): def _Event(_): Log(region, message) return _Event class TrapException(Exception): def __init__(self, address:int, msg:str): self.address = address self.msg = msg def __str__(self) -> str: return "$%04X: %s" % (self.address, self.msg) class SoftSwitch: def __init__( self, name: str, clear_addr: int, set_addr: int, status_addr: int, mode: AccessMode = AccessMode.WRITE, callback=None): self.name = name self.clear_addr = clear_addr self.set_addr = set_addr self.status_addr = status_addr # Whether switch is set/clear by READ/WRITE or both self.mode = mode # type: AccessMode self.state = False # type: bool self.callback = callback # type: Callable[[bool], Optional[int]] def set(self) -> Optional[int]: self.state = True Log(self.name, "Setting soft switch") if self.callback: return self.callback(True) def clear(self) -> Optional[int]: self.state = False Log(self.name, "Clearing soft switch") if self.callback: return self.callback(False) def get(self) -> int: Log(self.name, "Reading soft switch (%s)" % ( "on" if self.state else "off")) return 0x80 & self.state @staticmethod def unimplemented(_): raise NotImplementedError def register(self, io_map): def _clear(mode, value): return self.clear() def _set(mode, value): return self.set() def _get(mode, value): return self.get() io_map[self.clear_addr] = ( self.mode, "%s OFF" % self.name, _clear) io_map[self.set_addr] = ( self.mode, "%s ON" % self.name, _set) io_map[self.status_addr] = ( AccessMode.READ, "%s READ" % self.name, _get) class Machine: def __init__(self): self.memory_manager = None # type: memory.MemoryManager self.memory = None # type: py65_memory.ObservableMemory self.cpu = None self.io_map = {} # type: Dict[int, Tuple[AccessMode, str, Callable]] @staticmethod def unimplemented_io_callback(mode, value): raise NotImplementedError def io_interceptor(self, address, value=None): access_mode = ( AccessMode.READ if (value is None) else AccessMode.WRITE) try: (mode, name, callback) = self.io_map[address] if access_mode & mode: if access_mode & AccessMode.READ: print("==== IO EVENT: READ %s" % name) else: print("==== IO EVENT: WRITE %s -> %02x" % (name, value)) if callback: return callback(access_mode, value) else: return else: print("**** IO EVENT with unexpected mode: %s" % access_mode) raise TrapException(address, access_mode) except KeyError: if value: raise TrapException( address, 'Wrote %02X ("%s")' % (value, chr(value))) else: raise TrapException(address, 'Read')