mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
bdbba2a52f
With cycle charging on, the dirty-RAM interpreter charges an instruction's fetch and base cycle before its body runs. When that charge reaches a device deadline, the device event runs first. If it raises an interrupt, CAUSE.IP2 is set before MFC0/CFC0 read CAUSE, so the read sees an IRQ that belongs to the next instruction boundary. Compiled code batches its charges to the boundary and never shows this. Seen in the kernel's syscall handler: `mfc0 a1,Cause` ran interpreted, a CD IRQ fell due on its own cycle, and the handler saved CAUSE 0x420 instead of 0x20. The IRQ itself was taken at the right boundary; only the value saved inside the instruction was wrong. MFC0 and CFC0 now return COP0 as it stood when the instruction began. interp_cop0_read_sample links the production decoder (cycle charging on) into a fixture at -O0 and -O2, with a device service that raises IP2 on the read's own cycle. It reads 0x420 before this change and 0x20 after. Controls cover no event and an IRQ raised before the instruction. fixture_link.py stubs every other runtime seam with abort(), so an unexpected call fails the test.
24 lines
898 B
Python
24 lines
898 B
Python
"""MFC0/CFC0 read COP0 from before their own cycle charge.
|
|
|
|
Links the production decoder (interp_cop0_decoder.c, cycle charging on) into
|
|
test_interp_cop0_read_sample.c at -O0 and -O2; every other runtime seam is an
|
|
abort() stub (fixture_link.py).
|
|
"""
|
|
import argparse
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from fixture_link import build_and_run
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--cc', default='gcc')
|
|
args = parser.parse_args()
|
|
here = Path(__file__).resolve().parent
|
|
with tempfile.TemporaryDirectory() as root:
|
|
for opt in ('-O0', '-O2'):
|
|
build_and_run(args.cc, here, here.parent, opt, Path(root),
|
|
[str(here / 'interp_cop0_decoder.c')],
|
|
'test_interp_cop0_read_sample.c')
|
|
print('PASS: MFC0/CFC0 read CAUSE from before their own cycle charge (O0/O2)')
|