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.