Repository navigation
Conversation
The interpreter syncs the beam after every opcode and yields at the first instruction boundary after the H/V comparator latches. Region-paced code polls only the host's master deadline, which the beam frame driver sets to the frame end, so a raster IRQ that latches inside compiled code is taken at the next deadline yield, at a later instruction boundary than the interpreter takes it. The driver now arms an IRQ deadline around its CPU slice with a callback that returns the master clock at which the beam walk latches the next match (beam + snes_master_clocks_until_irq + 1, the park step's rule). While it is armed and I is clear, interp_bridge_lle_master_deadline_reached is also true once inIrq is set or the master clock reaches that latch. The callback is asked at every such poll, so writes to $4200 and $4207-$420A and the $4211 acknowledge take effect at the next boundary without any invalidation. Only a poll that directly follows cpu_aot_instruction_boundary() takes the IRQ deadline. Region-paced emission is the only emitter that reports instruction boundaries, and only there is master_cycles the exact clock of an instruction boundary at the poll; an aggregate block polls before its block-level charge, so a mid-block latch could not be placed on the interpreter's boundary anyway. Gating on the reported boundary leaves default emission's behavior unchanged and adds only a flag test to its deadline poll, with no new runtime flag and no emitter change. The bridge's own boundary call after a paired bounce is followed by interpreted opcodes that charge clocks first, so its mark never matches a later compiled poll. Test: tests/interp816/bridge_test.c S8i (yield at the latch; no yield with I set; a comparator reprogrammed inside the body moves the deadline either way; a pending IRQ yields; an acknowledged one does not; an aggregate poll, a stale boundary and a disarmed deadline do not).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
As I reported on #251, region-paced code only sees the host's frame-end deadline, so a raster IRQ that latches inside compiled code is taken at the next deadline yield, a later instruction boundary than the interpreter's. The interpreter syncs the beam after every opcode and yields at the first boundary after the comparator latches. I offered a fix there; this is it.
The beam frame driver now arms an IRQ deadline around its CPU slice:
interp_bridge_set_irq_deadline(next_irq_latch), where the callback returnsbeamMasterLast + snes_master_clocks_until_irq() + 1(the park step's rule). While armed and I is clear,interp_bridge_lle_master_deadline_reachedis also true onceinIrqis set or the master clock reaches that latch. The callback is asked at every such poll, so$4200and$4207–$420Awrites and the$4211acknowledge take effect at the next boundary without any invalidation. (On #251 I described a cached prediction refreshed on those writes; asking live is simpler and needs no change tosnes.c.)Only a poll that directly follows
cpu_aot_instruction_boundary()takes it. Only region-paced code emits that call, and only there ismaster_cyclesthe exact clock of an instruction boundary at the poll. Default emission keeps its behavior; its poll gains a single flag test. No emitter change, no new runtime flag, no new link dependencies for the bridge.The equivalent change in my fork, on top of #251, removed all raster-IRQ divergences between native and interpreted runs in the game's mode-7 scenes (the numbers are in my #251 comment). I can't run that game on plain upstream yet, so this exact code is covered by the test below, not by the game.
Test:
tests/interp816/bridge_test.cS8i. It covers:Results (MinGW gcc 16.2, Windows):
bridge_test471/471, also withSNESRECOMP_INTERP_FUSED_ROM_READ0 and 1interp816_test89/89,interrupt_tail_test27/27tests/v2614 passed; the one failure needs thelib/recomp-netsubmodule, which isn't checked out hereNot addressed here:
interp_tier_dispatch_tail) poll neither the frame deadline nor this one.