timing adjustments
This commit is contained in:
@@ -9,8 +9,12 @@ from ..vectors import read_vectors_min
|
||||
from .constants import (
|
||||
FRT_TCR_OCIEA,
|
||||
FRT_TCSR_OCFA,
|
||||
FRT1_FRC_H,
|
||||
FRT1_OCRA_H,
|
||||
FRT1_TCR,
|
||||
FRT1_TCSR,
|
||||
FRT2_FRC_H,
|
||||
FRT2_OCRA_H,
|
||||
FRT2_TCR,
|
||||
FRT2_TCSR,
|
||||
IPRA,
|
||||
@@ -36,6 +40,7 @@ from .errors import EmulatorError, UnsupportedInstruction
|
||||
from .fast_paths import P9FastPath, P9FastPathConfig
|
||||
from .memory import MemoryMap
|
||||
from .sci import SCI1
|
||||
from .timers import FrtOciaScheduler, FrtRegisters
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -47,6 +52,9 @@ class RunReport:
|
||||
tx_bytes: bytes
|
||||
tx_frames: list[bytes]
|
||||
heartbeat_seen: bool
|
||||
clock_hz: int
|
||||
frt1_ocia_period_ms: float | None = None
|
||||
frt2_ocia_period_ms: float | None = None
|
||||
unsupported: str | None = None
|
||||
trace: list[str] = field(default_factory=list)
|
||||
|
||||
@@ -56,6 +64,9 @@ class RunReport:
|
||||
f"cycles={self.cycles}",
|
||||
f"pc={h16(self.pc)}",
|
||||
f"stopped={self.stopped_reason}",
|
||||
f"clock_hz={self.clock_hz}",
|
||||
"frt1_ocia_period_ms=" + _format_optional_ms(self.frt1_ocia_period_ms),
|
||||
"frt2_ocia_period_ms=" + _format_optional_ms(self.frt2_ocia_period_ms),
|
||||
"tx_bytes=" + self.tx_bytes.hex(" ").upper(),
|
||||
"tx_frames=" + ", ".join(frame.hex(" ").upper() for frame in self.tx_frames),
|
||||
f"heartbeat_seen={self.heartbeat_seen}",
|
||||
@@ -74,8 +85,9 @@ class H8536Emulator:
|
||||
rom_bytes: bytes,
|
||||
*,
|
||||
interval_steps: int = 2048,
|
||||
frt1_ocia_steps: int = 1024,
|
||||
frt2_ocia_steps: int = 1024,
|
||||
frt1_ocia_steps: int | None = None,
|
||||
frt2_ocia_steps: int | None = None,
|
||||
clock_hz: int = 10_000_000,
|
||||
p9_fast_path: P9FastPath | None = None,
|
||||
p9_fast_path_enabled: bool = False,
|
||||
p9_fast_default_input_byte: int = 0xFF,
|
||||
@@ -90,8 +102,11 @@ class H8536Emulator:
|
||||
self.cpu = CPUState()
|
||||
self.vectors = read_vectors_min(self.memory.rom)
|
||||
self.interval_steps = max(1, interval_steps)
|
||||
self.frt1_ocia_steps = max(1, frt1_ocia_steps)
|
||||
self.frt2_ocia_steps = max(1, frt2_ocia_steps)
|
||||
self.frt1_ocia_steps = max(1, frt1_ocia_steps) if frt1_ocia_steps is not None else None
|
||||
self.frt2_ocia_steps = max(1, frt2_ocia_steps) if frt2_ocia_steps is not None else None
|
||||
self.clock_hz = max(1, clock_hz)
|
||||
self.frt1_ocia = FrtOciaScheduler(FrtRegisters("FRT1", FRT1_TCR, FRT1_TCSR, FRT1_FRC_H, FRT1_OCRA_H))
|
||||
self.frt2_ocia = FrtOciaScheduler(FrtRegisters("FRT2", FRT2_TCR, FRT2_TCSR, FRT2_FRC_H, FRT2_OCRA_H))
|
||||
self._interval_counter = 0
|
||||
self._frt1_ocia_counter = 0
|
||||
self._frt2_ocia_counter = 0
|
||||
@@ -110,8 +125,9 @@ class H8536Emulator:
|
||||
|
||||
def step(self) -> str:
|
||||
pc = self.cpu.pc
|
||||
cycles_before = self.cpu.cycles
|
||||
if self.p9_fast_path.try_handle(self):
|
||||
self._tick_peripherals()
|
||||
self._tick_peripherals(self.cpu.cycles - cycles_before)
|
||||
return f"{h16(pc)}: {'<p9-fast-path>':<17} P9 fast-path"
|
||||
|
||||
decoder = H8536Decoder(self.memory.rom, br=self.cpu.br)
|
||||
@@ -166,8 +182,9 @@ class H8536Emulator:
|
||||
|
||||
self.cpu.pc = next_pc
|
||||
self.cpu.steps += 1
|
||||
self.cpu.cycles += self._rough_cycles(raw)
|
||||
self._tick_peripherals()
|
||||
cycle_delta = self._rough_cycles(raw)
|
||||
self.cpu.cycles += cycle_delta
|
||||
self._tick_peripherals(cycle_delta)
|
||||
return f"{h16(pc)}: {' '.join(f'{byte:02X}' for byte in raw):<17} {text}"
|
||||
|
||||
def run(self, max_steps: int, trace: bool = False, stop_on_heartbeat: bool = False) -> RunReport:
|
||||
@@ -194,6 +211,9 @@ class H8536Emulator:
|
||||
tx_bytes=bytes(self.sci1.tx_bytes),
|
||||
tx_frames=list(self.sci1.tx_frames),
|
||||
heartbeat_seen=self.sci1.saw_heartbeat(),
|
||||
clock_hz=self.clock_hz,
|
||||
frt1_ocia_period_ms=self.frt1_ocia.period_ms(self.memory, self.clock_hz),
|
||||
frt2_ocia_period_ms=self.frt2_ocia.period_ms(self.memory, self.clock_hz),
|
||||
unsupported=unsupported,
|
||||
trace=trace_lines,
|
||||
)
|
||||
@@ -405,11 +425,17 @@ class H8536Emulator:
|
||||
return (pc + 3 + s8(raw[2])) & 0xFFFF
|
||||
return next_pc
|
||||
|
||||
def _tick_peripherals(self) -> None:
|
||||
def _tick_peripherals(self, cycle_delta: int) -> None:
|
||||
self.sci1.tick()
|
||||
self._interval_counter += 1
|
||||
self._frt1_ocia_counter += 1
|
||||
self._frt2_ocia_counter += 1
|
||||
if self.frt1_ocia_steps is None:
|
||||
self.frt1_ocia.tick(self.memory, cycle_delta)
|
||||
else:
|
||||
self._frt1_ocia_counter += 1
|
||||
if self.frt2_ocia_steps is None:
|
||||
self.frt2_ocia.tick(self.memory, cycle_delta)
|
||||
else:
|
||||
self._frt2_ocia_counter += 1
|
||||
self._service_pending_interrupt()
|
||||
|
||||
def _service_pending_interrupt(self) -> None:
|
||||
@@ -450,11 +476,13 @@ class H8536Emulator:
|
||||
if source == "interval_timer":
|
||||
self._interval_counter = 0
|
||||
elif source == "frt1_ocia":
|
||||
self._frt1_ocia_counter = 0
|
||||
self.memory.write8(FRT1_TCSR, self.memory.read8(FRT1_TCSR) | FRT_TCSR_OCFA)
|
||||
if self.frt1_ocia_steps is not None:
|
||||
self._frt1_ocia_counter = 0
|
||||
self.memory.write8(FRT1_TCSR, self.memory.read8(FRT1_TCSR) | FRT_TCSR_OCFA)
|
||||
elif source == "frt2_ocia":
|
||||
self._frt2_ocia_counter = 0
|
||||
self.memory.write8(FRT2_TCSR, self.memory.read8(FRT2_TCSR) | FRT_TCSR_OCFA)
|
||||
if self.frt2_ocia_steps is not None:
|
||||
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:
|
||||
@@ -484,6 +512,8 @@ class H8536Emulator:
|
||||
return (self.memory.read8(IPRA) >> 4) & 0x07
|
||||
|
||||
def _frt1_ocia_pending(self) -> bool:
|
||||
if self.frt1_ocia_steps is None:
|
||||
return self.frt1_ocia.pending(self.memory)
|
||||
if self._frt1_ocia_counter < self.frt1_ocia_steps:
|
||||
return False
|
||||
return bool(self.memory.read8(FRT1_TCR) & FRT_TCR_OCIEA)
|
||||
@@ -492,6 +522,8 @@ class H8536Emulator:
|
||||
return (self.memory.read8(IPRC) >> 4) & 0x07
|
||||
|
||||
def _frt2_ocia_pending(self) -> bool:
|
||||
if self.frt2_ocia_steps is None:
|
||||
return self.frt2_ocia.pending(self.memory)
|
||||
if self._frt2_ocia_counter < self.frt2_ocia_steps:
|
||||
return False
|
||||
return bool(self.memory.read8(FRT2_TCR) & FRT_TCR_OCIEA)
|
||||
@@ -679,3 +711,7 @@ class H8536Emulator:
|
||||
if cond == 0xE:
|
||||
return not self.cpu.z and self.cpu.n == self.cpu.v
|
||||
return self.cpu.z or self.cpu.n != self.cpu.v
|
||||
|
||||
|
||||
def _format_optional_ms(value: float | None) -> str:
|
||||
return "unavailable" if value is None else f"{value:.3f}"
|
||||
|
||||
Reference in New Issue
Block a user