def execute(self, motherboard: Motherboard): value = motherboard.reg.get(self.register_pair) if value >= 256**2: raise ValueError( f"Tried to push {value} from {self.register_pair}") motherboard.push_to_stack(value) return 16
def execute(self, motherboard: Motherboard): if self.cc is not None: if motherboard.reg.get_flag_condition(self.cc): return_address = motherboard.pop_from_stack() motherboard.program_counter = return_address return 20 else: return 8 else: return_address = motherboard.pop_from_stack() motherboard.program_counter = return_address return 16
def execute(self, motherboard: Motherboard): if self.cc is None or motherboard.reg.get_flag_condition(self.cc): if type(self.destination) == Addr: motherboard.program_counter = self.destination.address return 16 elif type(self.destination) == AddrReg: motherboard.program_counter = motherboard.reg.get( self.destination.register) return 4 else: raise ValueError( f"Unhandled jump destination: {self.destination}") else: return 12
def execute(self, motherboard: Motherboard): motherboard.stopped = True motherboard.memory.write(0xFF04, 0) # Write to DIV # TODO Timer should stop running here (https://gbdev.io/pandocs/#ff04-div-divider-register-r-w) logger.info("Stopping CPU and LCD") return 4
def execute(self, motherboard: Motherboard): popped = motherboard.pop_from_stack() if popped >= 256**2: raise ValueError(f"Popped {popped} from stack. [{self}]") motherboard.reg.set(self.register_pair, popped) return 12
def _handle_header_and_entrypoint(motherboard: Motherboard) -> CartridgeHeader: motherboard.program_counter = 0x100 b = b"" for i in range(0x0100, 0x0150): b += bytes([motherboard.memory.read(i)]) logger.debug("Cartridge bytes to parse:") logger.debug(str(b)) logger.debug("") logger.debug(str(motherboard.memory._cartridge)) header = CartridgeHeader.parse(b) logger.debug(str(header)) if header.cartridge_type in [CartridgeType.ROM_ONLY, CartridgeType.MBC1]: # This should be handled correctly pass else: logger.warn( f"We may not handle cartridge correctly: {header.cartridge_type}") logger.debug("Will load instruction from " + str(motherboard.program_counter)) instruction_decoding.fetch_decode_execute(motherboard) instruction_decoding.fetch_decode_execute(motherboard) return header
def run_game_from_file(filename: str): with open(filename, "rb") as file: cartridge_data = list(file.read()) logger.info(f"Loaded game ROM ({len(cartridge_data)} bytes)") with open("DMG_ROM.bin", "rb") as boot_file: boot_rom_buffer = list(boot_file.read()) logger.info(f"Loaded boot ROM ({len(boot_rom_buffer)} bytes)") joypad = JoyPad() timer = Timer() display = Display(joypad) ram_size_enum = RAM_Size(cartridge_data[0x149]) if ram_size_enum == RAM_Size.NONE: ram_size = 0 elif ram_size_enum == RAM_Size.RAM_32KB: ram_size = 32 * 1024 elif ram_size_enum == RAM_Size.RAM_8KB: ram_size = 8 * 1024 else: raise ValueError(f"TODO Handle RAM size: {ram_size_enum}") escaped_title = bytes( cartridge_data[0x134:0x134 + 11]).decode("utf-8").replace("\x00", "") save_file_name = f"savefiles/__{escaped_title.replace(' ', '_')}__" if os.path.exists(save_file_name): logger.info(f"Savefile found: {save_file_name}") with open(save_file_name, "rb") as save_file: ram_data = list(save_file.read()) logger.debug(f"Loaded RAM data ({len(ram_data)} bytes)") if len(ram_data) != ram_size: raise ValueError( f"Expected RAM size {ram_size} but savefile has size {len(ram_data)}" ) else: ram_data = [0] * ram_size logger.info( f"Savefile not found: {save_file_name}. Created new RAM data with size {ram_size}" ) cartridge = Cartridge(cartridge_data, ram_data) memory = Memory(cartridge, joypad, timer, display) motherboard = Motherboard(memory, 0) cartridge_header = _handle_header_and_entrypoint(motherboard) display.set_title(cartridge_header.title) _run_game(motherboard, display, timer, cartridge, save_file_name) logger.info("Exiting emulator")
def execute(self, motherboard: Motherboard): motherboard.halted = True logger.debug("HALTING...") return 4
def execute(self, motherboard: Motherboard): motherboard.push_to_stack(motherboard.program_counter) motherboard.program_counter = self.address return 16
def execute(self, motherboard: Motherboard): return_address = motherboard.pop_from_stack() motherboard.program_counter = return_address motherboard.IME_flag = True return 16
def execute(self, motherboard: Motherboard): if self.cc is None or motherboard.reg.get_flag_condition(self.cc): motherboard.push_to_stack(motherboard.program_counter) motherboard.program_counter = self.address return 24 return 12
def execute(self, motherboard: Motherboard): motherboard.enable_interrupts_after_next_instruction() logger.debug("Enabling interrupts (after next instruction)") return 4