Unrelated to previous questions:
Hmm, I tried to make the test automatically find the proper timings for the APU IRQ timing, so it works not only on both NTSC and PAL, but on any broken emulator that might not have its timings right (since the focus of the test is not at accurate timings, but in the BRK-IRQ overriding effect that I have dubbed Higgs boson for its observation evading nature).
But turns out that blargg's sync_apu function actually relies on hard-coded NTSC timings, which makes the whole synchronization loop ("IRQ timing") pointless. If the emulator does not have accurate NTSC timings, the loop may yield random values.
I tried discarding the sync_apu function and instead, making my own synchronization code (still relying on the binary search), but it does not work nicely. I tried for example, delay N cycles, read IRQ status (clearing it), delay N cycles again, read IRQ status, and see if IRQ status was set on both times. (Two times necessary to overcome the unknown jitter factor.) I tried looping ten times and checking if IRQ status was set each time. Or ANDing the statuses of individual loops together.
None of these produced anything that would not produce completely random results (that were right sometimes, but often off by 1 or off by 40).
Any ideas? Here is the (partial) source code of one of these attempts.
Code:
sei
; Disable IRQ
delay 8
setb SNDMODE, $40
delay 8
lda SNDCHN
delay 8
; Run one IRQ.
setb SNDMODE, 0 ; Enable IRQ (but the CPU will still block them)
; Wait
lda num_cycles_plan+0 ; 3 cycles
sec ; 2 cycles
sbc #40 ; 2 cycles
tax ; 2 cycles
lda num_cycles_plan+1 ; 3 cycles
sbc #0 ; 2 cycles
jsr delay_256a_x_26_clocks ; OVERHEAD: 3+2+2+2+3+2+26
; Check whether APU is ready to trigger an IRQ
lda SNDCHN ; 4 cycles
sta somewhere ; 3 cycles
; Do it again to counteract the odd/even frames effect. Subtract those 7 cycles.
lda num_cycles_plan+0 ; 3 cycles
sec ; 2 cycles
sbc #(40-7) ; 2 cycles
tax ; 2 cycles
lda num_cycles_plan+1 ; 3 cycles
sbc #0 ; 2 cycles
jsr delay_256a_x_26_clocks ; OVERHEAD: 3+2+2+2+3+2+26
lda SNDCHN
and somewhere
; The bits now tell if the IRQ happened on both times.
and #$40
; Binary search condition: A = nonzero.
The code below gets 29820 cycles in Nintendulator, 29813 cycles in Nestopia.
Code:
sei
; Disable IRQ
delay 8
setb SNDMODE, $40
delay 8
lda SNDCHN
delay 8
; Run one IRQ.
setb SNDMODE, 0 ; Enable IRQ (but block them at CPU)
; Wait
lda num_cycles_plan+0 ; 3 cycles
sec ; 2 cycles
sbc #40 ; 2 cycles
tax ; 2 cycles
lda num_cycles_plan+1 ; 3 cycles
sbc #0 ; 2 cycles
jsr delay_256a_x_26_clocks ; OVERHEAD: 3+2+2+2+3+2+26
ldx SNDCHN ; 4 cycles
lda SNDCHN ; 4 cycles
; X should be #$00, A should be #$40.
and #$40 ; 2 cycles
sta timing_temp_1 ; 3 cycles
txa ; 2 cycles
and #$40 ; 2 cycles
sec ; 2 cycles
sbc timing_temp_1 ; 3 cycles
sta timing_temp_1 ; 3 cycles --total: 4+4+2+3+2+2+2+3+3 = 25 cycles
; X=$00, A=$00 (too early) result: $00
; X=$00, A=$40 (right time) result: $C0
; X=$40, A=$00 (too late) result: $40
; X=$40, A=$40 (impossible) result: $00
; Do it again to counteract the odd/even frames effect. Subtract those 25 cycles.
lda num_cycles_plan+0 ; 3 cycles
sec ; 2 cycles
sbc #(40-25) ; 2 cycles
tax ; 2 cycles
lda num_cycles_plan+1 ; 3 cycles
sbc #0 ; 2 cycles
jsr delay_256a_x_26_clocks ; OVERHEAD: 3+2+2+2+3+2+26
ldx SNDCHN
lda SNDCHN
and #$40 ; 2 cycles
sta timing_temp_2 ; 3 cycles
txa ; 2 cycles
and #$40 ; 2 cycles
sec ; 2 cycles
sbc timing_temp_2 ; 3 cycles
sta timing_temp_2 ; 3 cycles
; Now:
; timing_temp_1 timing_temp_2
; $00 $00 too early (1)
; $00 $40 too early (1)
; $00 $C0 too early (1)
; $40 $00 too late (0)
; $40 $40 too late (0)
; $40 $C0 too late (0)
; $C0 $00 too early (1)
; $C0 $40 too late (0)
; $C0 $C0 RIGHT TIME (0)
ldx #0
lda timing_temp_1
beq @make_1
cmp #$40
beq @make_0
lda timing_temp_2
beq @make_1
@make_0:
.byte $A9 ; lda #imm
@make_1:
inx
; Translate the 0/1 value into carry flag for function return.
cpx #$01
rts
I'll have to doublecheck whether my delay function works as intended, too.
EDIT: Yeah, I had a bug in the delay code. (Which means that all previous test results may have been bogus!) But I'm still getting differences of 0/1 cycles in this loop.