The best I can do is show several code sequences and the result they produce, and leave it to you to come up with a simple model to explain it. This is the same raw data I have to work with.
The comments in the following code show what is printed when it is run on my NES. The calls to sync_apu synchronize with the APU even/odd "jitter" so that the write to $4017 will be on an even internal cycle, such that there is no extra clock delay before the new mode begins. The times of some events are commented, relative to the write to $4017.
Delays are made with delay_yaN, with a comment indicating the total clocks taken by the ldy, lda, jsr, delay routine, and rts. In other words, deleting the three instructions that invoke the delay would cause the following instructions to execute that many clocks earlier.
These demonstrate when the set IRQ flag becomes visible via a $4015 read, and the way the IRQ flag is apparently set multiple times (or not cleared when reads are at particular times):
Code: Select all
print_a_x:
jsr debug_byte
txa
jsr debug_byte
rts
reset:
jsr setup_apu
jsr sync_apu
lda #$00 ; start mode
sta $4017 ; write at 0
ldy #48 ; 29826 delay
lda #123
jsr delay_ya1
lda $4015 ; read at 29830
ldx $4015 ; read at 29834
jsr print_a_x ; prints $00 $40
jsr sync_apu
lda #$00 ; start mode
sta $4017
ldy #48 ; 29827 delay
lda #123
jsr delay_ya2
lda $4015 ; read at 29831
ldx $4015
jsr print_a_x ; prints $40 $40
jsr sync_apu
lda #$00 ; start mode
sta $4017
ldy #48 ; 29828 delay
lda #123
jsr delay_ya3
lda $4015 ; read at 29832
ldx $4015
jsr print_a_x ; prints $40 $40
jsr sync_apu
lda #$00 ; start mode
sta $4017
ldy #48 ; 29829 delay
lda #123
jsr delay_ya4
lda $4015 ; read at 29833
ldx $4015
jsr print_a_x ; prints $40 $00
Code: Select all
irq:
bit $4015 ; clear IRQ flag
txa ; save current value of X
rti
reset:
jsr setup_apu
jsr sync_apu
lda #$40 ; clear frame IRQ flag first
sta $4017
cli
lda #$00 ; start mode
sta $4017 ; write at 0
ldy #48 ; 29828 delay
lda #123
jsr delay_ya3
ldx #0
ldx #1 ; first clock at 29831
; IRQ occurs at 29833
ldx #2
ldx #3
sei
jsr debug_byte ; prints $01
jsr sync_apu
lda #$40 ; clear frame IRQ flag first
sta $4017
cli
lda #$00 ; start mode
sta $4017 ; write at 0
ldy #48 ; 29827 delay
lda #123
jsr delay_ya2
ldx #0
ldx #1
ldx #2 ; first clock at 29832
; IRQ occurs at 29834
ldx #3
sei
jsr debug_byte ; prints $02