non-volatile storage emulation
This commit is contained in:
@@ -2,6 +2,7 @@ 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,
|
||||
@@ -26,7 +27,7 @@ class P9FastPathTest(unittest.TestCase):
|
||||
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):
|
||||
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
|
||||
@@ -41,10 +42,11 @@ class P9FastPathTest(unittest.TestCase):
|
||||
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.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.assertFalse(emulator.cpu.z)
|
||||
self.assertTrue(emulator.cpu.z)
|
||||
self.assertFalse(emulator.cpu.n)
|
||||
self.assertFalse(emulator.cpu.v)
|
||||
self.assertTrue(emulator.cpu.c)
|
||||
@@ -106,9 +108,11 @@ class P9FastPathTest(unittest.TestCase):
|
||||
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):
|
||||
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)
|
||||
|
||||
@@ -116,30 +120,40 @@ class P9FastPathTest(unittest.TestCase):
|
||||
|
||||
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(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_wrapper_can_succeed_from_queued_p9_device_response(self):
|
||||
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)
|
||||
emulator.memory.p9_bus.queue_wrapper_results([True], source="panel-script")
|
||||
|
||||
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, "panel-script")
|
||||
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, 0x89AB)
|
||||
self.assertEqual(emulator.cpu.pc, 0x9ABC)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -4,6 +4,55 @@ from h8536.emulator import MemoryMap, P9DDR, P9DR
|
||||
from h8536.emulator.peripherals import P9Bus
|
||||
|
||||
|
||||
def p9_start(bus: P9Bus) -> None:
|
||||
bus.write_ddr(0x93)
|
||||
bus.write_dr(0x80)
|
||||
bus.write_dr(0x82)
|
||||
bus.write_dr(0x02)
|
||||
bus.write_dr(0x00)
|
||||
|
||||
|
||||
def p9_stop(bus: P9Bus) -> None:
|
||||
bus.write_ddr(0x93)
|
||||
bus.write_dr(0x00)
|
||||
bus.write_dr(0x02)
|
||||
bus.write_dr(0x82)
|
||||
bus.write_dr(0x80)
|
||||
|
||||
|
||||
def p9_write_byte(bus: P9Bus, value: int) -> bool:
|
||||
bus.write_ddr(0x93)
|
||||
for bit_index in range(7, -1, -1):
|
||||
bit = (value >> bit_index) & 1
|
||||
low = 0x80 if bit else 0x00
|
||||
bus.write_dr(low)
|
||||
bus.write_dr(low | 0x02)
|
||||
bus.write_dr(low)
|
||||
bus.write_ddr(0x13)
|
||||
bus.write_dr(bus.dr_latch | 0x02)
|
||||
ack_low = not bool(bus.read_dr() & 0x80)
|
||||
bus.write_dr(bus.dr_latch & ~0x02)
|
||||
bus.write_ddr(0x93)
|
||||
return ack_low
|
||||
|
||||
|
||||
def p9_read_byte(bus: P9Bus, *, master_ack: bool) -> int:
|
||||
value = 0
|
||||
bus.write_ddr(0x13)
|
||||
for _ in range(8):
|
||||
bus.write_dr(bus.dr_latch | 0x02)
|
||||
value = (value << 1) | (1 if bus.read_dr() & 0x80 else 0)
|
||||
bus.write_dr(bus.dr_latch & ~0x02)
|
||||
bus.write_ddr(0x93)
|
||||
if master_ack:
|
||||
bus.write_dr(bus.dr_latch & ~0x80)
|
||||
else:
|
||||
bus.write_dr(bus.dr_latch | 0x80)
|
||||
bus.write_dr(bus.dr_latch | 0x02)
|
||||
bus.write_dr(bus.dr_latch & ~0x02)
|
||||
return value
|
||||
|
||||
|
||||
class P9BusTest(unittest.TestCase):
|
||||
def test_bit7_input_uses_queued_then_default_low_response(self):
|
||||
memory = MemoryMap(b"\x00" * 4)
|
||||
@@ -47,6 +96,44 @@ class P9BusTest(unittest.TestCase):
|
||||
self.assertIn("wrapper_result ddr=00 dr=00 value=01 success=1 source=panel-script queued=0", bus.trace_lines())
|
||||
self.assertIn("wrapper_result ddr=00 dr=00 value=00 success=0 source=default_timeout queued=0", bus.trace_lines())
|
||||
|
||||
def test_x24164_bit_banged_write_acknowledges_and_stores_data(self):
|
||||
bus = P9Bus()
|
||||
|
||||
p9_start(bus)
|
||||
self.assertTrue(p9_write_byte(bus, 0xA0))
|
||||
self.assertTrue(p9_write_byte(bus, 0x12))
|
||||
self.assertTrue(p9_write_byte(bus, 0x34))
|
||||
p9_stop(bus)
|
||||
|
||||
device = bus.x24164_bus.devices[0]
|
||||
self.assertEqual(device.read(0x12), 0x34)
|
||||
self.assertTrue(any("x24164_write_data" in line and "addr=012" in line for line in bus.trace_lines()))
|
||||
|
||||
def test_x24164_bit_banged_random_read_uses_p91_p97_lines(self):
|
||||
bus = P9Bus()
|
||||
bus.x24164_bus.devices[0].write(0x12, 0xAB)
|
||||
|
||||
p9_start(bus)
|
||||
self.assertTrue(p9_write_byte(bus, 0xA0))
|
||||
self.assertTrue(p9_write_byte(bus, 0x12))
|
||||
p9_start(bus)
|
||||
self.assertTrue(p9_write_byte(bus, 0xA1))
|
||||
self.assertEqual(p9_read_byte(bus, master_ack=False), 0xAB)
|
||||
p9_stop(bus)
|
||||
|
||||
self.assertTrue(any("x24164_prepare_read" in line and "value=AB" in line for line in bus.trace_lines()))
|
||||
|
||||
def test_x24164_fast_word_mapping_matches_rom_address_banks(self):
|
||||
bus = P9Bus()
|
||||
|
||||
self.assertTrue(bus.fast_write_word(0x0012, 0x3456))
|
||||
self.assertTrue(bus.fast_write_word(0x0812, 0xABCD))
|
||||
|
||||
self.assertEqual(bus.fast_read_word(0x0012), (True, 0x3456))
|
||||
self.assertEqual(bus.fast_read_word(0x0812), (True, 0xABCD))
|
||||
self.assertEqual(bus.x24164_bus.devices[0].read(0x12), 0x34)
|
||||
self.assertEqual(bus.x24164_bus.devices[1].read(0x12), 0xAB)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user