import unittest from h8536.emulator.fast_paths import ( LOC_BFE0_TRANSFER_WRAPPER, LOC_BFFE_TRANSFER_WRAPPER, LOC_C08B_P9_WRITE_BYTE, LOC_C0DB_P9_READ_BYTE, P9FastPath, P9FastPathConfig, ) from h8536.emulator.runner import H8536Emulator def rom_with_reset(*, reset: int = 0x1000, size: int = 0xD000) -> bytearray: rom = bytearray([0xFF] * size) rom[0:2] = reset.to_bytes(2, "big") return rom class P9FastPathTest(unittest.TestCase): def test_disabled_fast_path_does_not_handle_known_pc(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_C08B_P9_WRITE_BYTE fast_path = P9FastPath() self.assertFalse(fast_path.try_handle(emulator)) self.assertEqual(emulator.cpu.pc, LOC_C08B_P9_WRITE_BYTE) def test_c08b_write_byte_logs_r0_sets_timeout_without_active_eeprom_transaction(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_C08B_P9_WRITE_BYTE emulator.cpu.regs[0] = 0x12A5 emulator.cpu.regs[7] = 0xFE7E emulator.cpu.c = True emulator.cpu.v = True emulator.memory.write16(0xFE7E, 0x3456) fast_path = P9FastPath(P9FastPathConfig(enabled=True)) self.assertTrue(fast_path.try_handle(emulator)) self.assertEqual(fast_path.output_bytes, [0xA5]) self.assertEqual(fast_path.events[-1].kind, "write_byte") self.assertEqual(fast_path.events[-1].value, 0xA5) self.assertFalse(fast_path.events[-1].success) self.assertEqual(emulator.cpu.regs[0], 0) self.assertEqual(emulator.cpu.pc, 0x3456) self.assertEqual(emulator.cpu.regs[7], 0xFE80) self.assertTrue(emulator.cpu.z) self.assertFalse(emulator.cpu.n) self.assertFalse(emulator.cpu.v) self.assertTrue(emulator.cpu.c) self.assertEqual(emulator.cpu.steps, 1) def test_c0db_read_byte_puts_queued_byte_in_r5_low_and_returns(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_C0DB_P9_READ_BYTE emulator.cpu.regs[5] = 0xBE00 emulator.cpu.regs[7] = 0xFE7C emulator.memory.write16(0xFE7C, 0x4567) fast_path = P9FastPath(P9FastPathConfig(enabled=True), input_bytes=[0x3C]) self.assertTrue(fast_path.try_handle(emulator)) self.assertEqual(emulator.cpu.regs[5], 0xBE3C) self.assertEqual(emulator.cpu.pc, 0x4567) self.assertEqual(emulator.cpu.regs[7], 0xFE7E) self.assertEqual(fast_path.events[-1].kind, "read_byte") self.assertEqual(fast_path.events[-1].value, 0x3C) self.assertEqual(fast_path.events[-1].source, "initial") self.assertEqual(fast_path.events[-1].queue_depth, 0) self.assertFalse(emulator.cpu.z) self.assertFalse(emulator.cpu.n) self.assertFalse(emulator.cpu.v) def test_c0db_read_byte_uses_default_when_queue_is_empty(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_C0DB_P9_READ_BYTE emulator.cpu.regs[7] = 0xFE80 emulator.memory.write16(0xFE80, 0x5678) fast_path = P9FastPath(P9FastPathConfig(enabled=True, default_input_byte=0x81)) self.assertTrue(fast_path.try_handle(emulator)) self.assertEqual(emulator.cpu.regs[5], 0x0081) self.assertEqual(emulator.cpu.pc, 0x5678) self.assertEqual(fast_path.events[-1].source, "default_input_byte") self.assertEqual(fast_path.events[-1].queue_depth, 0) self.assertIn("source=default_input_byte", fast_path.events[-1].line()) self.assertFalse(emulator.cpu.z) self.assertTrue(emulator.cpu.n) def test_named_input_script_records_read_source_and_remaining_depth(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_C0DB_P9_READ_BYTE emulator.cpu.regs[7] = 0xFE82 emulator.memory.write16(0xFE82, 0x6789) fast_path = P9FastPath(P9FastPathConfig(enabled=True)) fast_path.queue_input_script("idle-panel", [0x00, 0x80]) self.assertTrue(fast_path.try_handle(emulator)) event = fast_path.events[-1] self.assertEqual(emulator.cpu.regs[5], 0x0000) self.assertEqual(event.kind, "read_byte") self.assertEqual(event.value, 0x00) self.assertEqual(event.source, "script:idle-panel") self.assertEqual(event.queue_depth, 1) self.assertEqual(fast_path.trace_lines(), ["read_byte pc=C0DB value=00 source=script:idle-panel queued=1"]) def test_wrapper_writes_and_verifies_against_x24164_model(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_BFE0_TRANSFER_WRAPPER emulator.cpu.regs[4] = 0x0812 emulator.cpu.regs[5] = 0x3456 emulator.cpu.regs[7] = 0xFE84 emulator.memory.write16(0xFE84, 0x789A) fast_path = P9FastPath(P9FastPathConfig(enabled=True)) self.assertTrue(fast_path.try_handle(emulator)) event = fast_path.events[-1] self.assertEqual(event.kind, "wrapper_success") self.assertTrue(event.success) self.assertEqual(event.source, "x24164_write_verify") self.assertEqual(emulator.cpu.regs[0], 1) self.assertFalse(emulator.cpu.z) self.assertEqual(emulator.cpu.pc, 0x789A) self.assertEqual(emulator.memory.p9_bus.fast_read_word(0x0812), (True, 0x3456)) def test_read_wrapper_puts_x24164_word_in_r5(self): emulator = H8536Emulator(bytes(rom_with_reset())) emulator.cpu.pc = LOC_BFE0_TRANSFER_WRAPPER emulator.cpu.regs[4] = 0x0010 emulator.cpu.regs[5] = 0xCAFE emulator.cpu.regs[7] = 0xFE86 emulator.memory.write16(0xFE86, 0x89AB) fast_path = P9FastPath(P9FastPathConfig(enabled=True)) self.assertTrue(fast_path.try_handle(emulator)) emulator.cpu.pc = LOC_BFFE_TRANSFER_WRAPPER emulator.cpu.regs[4] = 0x0010 emulator.cpu.regs[5] = 0 emulator.cpu.regs[7] = 0xFE86 emulator.memory.write16(0xFE86, 0x9ABC) self.assertTrue(fast_path.try_handle(emulator)) event = fast_path.events[-1] self.assertEqual(event.kind, "wrapper_success") self.assertTrue(event.success) self.assertEqual(event.source, "x24164_read_word") self.assertEqual(emulator.cpu.regs[5], 0xCAFE) self.assertEqual(emulator.cpu.regs[0], 1) self.assertFalse(emulator.cpu.z) self.assertEqual(emulator.cpu.pc, 0x9ABC) if __name__ == "__main__": unittest.main()