EMualtor im
This commit is contained in:
@@ -7,15 +7,22 @@ from ..formatting import h16
|
||||
from ..rom import DecodeError
|
||||
from ..vectors import read_vectors_min
|
||||
from .constants import (
|
||||
FRT_TCR_OCIEA,
|
||||
FRT_TCSR_OCFA,
|
||||
FRT2_TCR,
|
||||
FRT2_TCSR,
|
||||
IPRA,
|
||||
IPRC,
|
||||
IPRE,
|
||||
SCI_SCR_TIE,
|
||||
SCI_SSR_TDRE,
|
||||
VECTOR_FRT2_OCIA,
|
||||
VECTOR_INTERVAL_TIMER,
|
||||
VECTOR_SCI1_TXI,
|
||||
)
|
||||
from .cpu import CPUState, mask, s8, s16, sign_bit
|
||||
from .errors import EmulatorError, UnsupportedInstruction
|
||||
from .fast_paths import P9FastPath, P9FastPathConfig
|
||||
from .memory import MemoryMap
|
||||
from .sci import SCI1
|
||||
|
||||
@@ -51,15 +58,29 @@ class RunReport:
|
||||
|
||||
|
||||
class H8536Emulator:
|
||||
def __init__(self, rom_bytes: bytes, *, interval_steps: int = 2048) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
rom_bytes: bytes,
|
||||
*,
|
||||
interval_steps: int = 2048,
|
||||
frt2_ocia_steps: int = 1024,
|
||||
p9_fast_path: P9FastPath | None = None,
|
||||
p9_fast_path_enabled: bool = False,
|
||||
p9_fast_default_input_byte: int = 0xFF,
|
||||
) -> None:
|
||||
if not rom_bytes:
|
||||
raise ValueError("ROM image is empty")
|
||||
self.sci1 = SCI1()
|
||||
self.memory = MemoryMap(rom_bytes, self.sci1)
|
||||
self.p9_fast_path = p9_fast_path or P9FastPath(
|
||||
P9FastPathConfig(enabled=p9_fast_path_enabled, default_input_byte=p9_fast_default_input_byte)
|
||||
)
|
||||
self.cpu = CPUState()
|
||||
self.vectors = read_vectors_min(self.memory.rom)
|
||||
self.interval_steps = max(1, interval_steps)
|
||||
self.frt2_ocia_steps = max(1, frt2_ocia_steps)
|
||||
self._interval_counter = 0
|
||||
self._frt2_ocia_counter = 0
|
||||
self.reset()
|
||||
|
||||
def reset(self) -> None:
|
||||
@@ -72,6 +93,10 @@ class H8536Emulator:
|
||||
|
||||
def step(self) -> str:
|
||||
pc = self.cpu.pc
|
||||
if self.p9_fast_path.try_handle(self):
|
||||
self._tick_peripherals()
|
||||
return f"{h16(pc)}: {'<p9-fast-path>':<17} P9 fast-path"
|
||||
|
||||
decoder = H8536Decoder(self.memory.rom, br=self.cpu.br)
|
||||
ins = decoder.decode(pc)
|
||||
if not ins.valid:
|
||||
@@ -99,6 +124,7 @@ class H8536Emulator:
|
||||
self._cmp(self.cpu.regs[reg], int.from_bytes(raw[1:3], "big"), 2)
|
||||
elif 0x50 <= raw[0] <= 0x57 and len(raw) == 2:
|
||||
self._reg_write(raw[0] & 0x07, raw[1], 1)
|
||||
self._set_logic_flags(raw[1], 1)
|
||||
elif 0x58 <= raw[0] <= 0x5F and len(raw) == 3:
|
||||
self.cpu.regs[raw[0] & 0x07] = int.from_bytes(raw[1:3], "big")
|
||||
self._set_logic_flags(self.cpu.regs[raw[0] & 0x07], 2)
|
||||
@@ -221,6 +247,13 @@ class H8536Emulator:
|
||||
self._set_logic_flags(result, size)
|
||||
elif base == 0x70:
|
||||
self._cmp(self._reg_read(rd, size), self._read_ea(ea, size), size)
|
||||
elif base == 0xA8:
|
||||
if size != 1:
|
||||
raise UnsupportedInstruction(pc, raw, H8536Decoder(self.memory.rom, br=self.cpu.br).decode(pc).text)
|
||||
result = (self._reg_read(rd, 1) * self._read_ea(ea, 1)) & 0xFFFF
|
||||
self.cpu.regs[rd] = result
|
||||
self._set_logic_flags(result, 2)
|
||||
self.cpu.c = False
|
||||
elif op in (0x08, 0x09, 0x0C, 0x0D):
|
||||
delta = {0x08: 1, 0x09: 2, 0x0C: -1, 0x0D: -2}[op]
|
||||
old = self._read_ea(ea, size)
|
||||
@@ -233,6 +266,10 @@ class H8536Emulator:
|
||||
elif op == 0x13:
|
||||
self._write_ea(ea, 0, size)
|
||||
self._set_logic_flags(0, size)
|
||||
elif op == 0x15:
|
||||
result = (~self._read_ea(ea, size)) & mask(size)
|
||||
self._write_ea(ea, result, size)
|
||||
self._set_logic_flags(result, size)
|
||||
elif op == 0x16:
|
||||
self._set_logic_flags(self._read_ea(ea, size), size)
|
||||
elif op == 0x10:
|
||||
@@ -335,6 +372,7 @@ class H8536Emulator:
|
||||
def _tick_peripherals(self) -> None:
|
||||
self.sci1.tick()
|
||||
self._interval_counter += 1
|
||||
self._frt2_ocia_counter += 1
|
||||
self._service_pending_interrupt()
|
||||
|
||||
def _service_pending_interrupt(self) -> None:
|
||||
@@ -349,6 +387,10 @@ class H8536Emulator:
|
||||
target = self._vector_target(VECTOR_INTERVAL_TIMER)
|
||||
if target is not None:
|
||||
candidates.append((self._interval_priority(), target, "interval_timer"))
|
||||
if self._frt2_ocia_pending():
|
||||
target = self._vector_target(VECTOR_FRT2_OCIA)
|
||||
if target is not None:
|
||||
candidates.append((self._frt2_priority(), target, "frt2_ocia"))
|
||||
|
||||
if not candidates:
|
||||
return
|
||||
@@ -357,6 +399,9 @@ class H8536Emulator:
|
||||
return
|
||||
if source == "interval_timer":
|
||||
self._interval_counter = 0
|
||||
elif source == "frt2_ocia":
|
||||
self._frt2_ocia_counter = 0
|
||||
self.memory.write8(FRT2_TCSR, self.memory.read8(FRT2_TCSR) | FRT_TCSR_OCFA)
|
||||
self._enter_interrupt(target)
|
||||
|
||||
def _enter_interrupt(self, target: int) -> None:
|
||||
@@ -385,6 +430,16 @@ class H8536Emulator:
|
||||
def _interval_priority(self) -> int:
|
||||
return (self.memory.read8(IPRA) >> 4) & 0x07
|
||||
|
||||
def _frt2_ocia_pending(self) -> bool:
|
||||
if self._frt2_ocia_counter < self.frt2_ocia_steps:
|
||||
return False
|
||||
return bool(self.memory.read8(FRT2_TCR) & FRT_TCR_OCIEA)
|
||||
|
||||
def _frt2_priority(self) -> int:
|
||||
# H8/536 IPRC assigns bits 6..4 to FRT1 and bits 2..0 to FRT2;
|
||||
# the ROM's IPRC=H'66 therefore gives both timers priority 6.
|
||||
return self.memory.read8(IPRC) & 0x07
|
||||
|
||||
def _push16(self, value: int) -> None:
|
||||
sp = (self.cpu.regs[7] - 2) & 0xFFFF
|
||||
self.cpu.regs[7] = sp
|
||||
|
||||
Reference in New Issue
Block a user