1
0
Files
h8-536-decoder/tests/test_emulator_fast_paths.py
2026-05-25 22:32:13 +10:00

147 lines
5.9 KiB
Python

import unittest
from h8536.emulator.fast_paths import (
LOC_BFE0_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_success_and_returns_to_caller(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.assertEqual(emulator.cpu.regs[0], 1)
self.assertEqual(emulator.cpu.pc, 0x3456)
self.assertEqual(emulator.cpu.regs[7], 0xFE80)
self.assertFalse(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_defaults_to_timeout_when_no_p9_device_response_is_queued(self):
emulator = H8536Emulator(bytes(rom_with_reset()))
emulator.cpu.pc = LOC_BFE0_TRANSFER_WRAPPER
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_timeout")
self.assertFalse(event.success)
self.assertEqual(event.source, "default_timeout")
self.assertEqual(emulator.cpu.regs[0], 0)
self.assertTrue(emulator.cpu.z)
self.assertEqual(emulator.cpu.pc, 0x789A)
def test_wrapper_can_succeed_from_queued_p9_device_response(self):
emulator = H8536Emulator(bytes(rom_with_reset()))
emulator.cpu.pc = LOC_BFE0_TRANSFER_WRAPPER
emulator.cpu.regs[7] = 0xFE86
emulator.memory.write16(0xFE86, 0x89AB)
emulator.memory.p9_bus.queue_wrapper_results([True], source="panel-script")
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, "panel-script")
self.assertEqual(emulator.cpu.regs[0], 1)
self.assertFalse(emulator.cpu.z)
self.assertEqual(emulator.cpu.pc, 0x89AB)
if __name__ == "__main__":
unittest.main()