mirror of
https://github.com/daniel5151/ANESE.git
synced 2025-04-02 10:32:00 -04:00
185 lines
3 KiB
ArmAsm
Vendored
185 lines
3 KiB
ArmAsm
Vendored
; Allows precise PPU synchronization in NMI handler, without
|
|
; having to cycle-time code outside NMI handler.
|
|
|
|
.zeropage
|
|
nmi_sync_count: .res 1
|
|
|
|
.code
|
|
.align 256 ; branches must not cross page
|
|
|
|
; Initializes synchronization and enables NMI
|
|
; Preserved: X, Y
|
|
; Time: 15 frames average, 28 frames max
|
|
init_nmi_sync:
|
|
; Disable interrupts and rendering
|
|
sei
|
|
lda #0
|
|
sta $2000
|
|
sta $2001
|
|
|
|
; Coarse synchronize
|
|
bit $2002
|
|
init_nmi_sync_1:
|
|
bit $2002
|
|
bpl init_nmi_sync_1
|
|
|
|
; Synchronize to odd CPU cycle
|
|
sta $4014
|
|
|
|
; Fine synchronize
|
|
lda #3
|
|
init_nmi_sync_2:
|
|
sta nmi_sync_count
|
|
bit $2002
|
|
bit $2002
|
|
php
|
|
eor #$02
|
|
nop
|
|
nop
|
|
plp
|
|
bpl init_nmi_sync_2
|
|
|
|
; Delay one frame
|
|
init_nmi_sync_3:
|
|
bit $2002
|
|
bpl init_nmi_sync_3
|
|
|
|
; Enable rendering long enough for frame to
|
|
; be shortened if it's a short one, but not long
|
|
; enough that background will get displayed.
|
|
lda #$08
|
|
sta $2001
|
|
|
|
; Can reduce delay by up to 5 and this still works,
|
|
; so there's a good margin.
|
|
; delay 2377
|
|
lda #216
|
|
init_nmi_sync_4:
|
|
nop
|
|
nop
|
|
sec
|
|
sbc #1
|
|
bne init_nmi_sync_4
|
|
|
|
sta $2001
|
|
|
|
lda nmi_sync_count
|
|
|
|
; Wait for this and next frame to finish.
|
|
; If this frame was short, loop ends. If it was
|
|
; long, loop runs for a third frame.
|
|
init_nmi_sync_5:
|
|
bit $2002
|
|
bit $2002
|
|
php
|
|
eor #$02
|
|
sta nmi_sync_count
|
|
nop
|
|
nop
|
|
plp
|
|
bpl init_nmi_sync_5
|
|
|
|
; Enable NMI
|
|
lda #$80
|
|
sta $2000
|
|
|
|
rts
|
|
|
|
|
|
; Initializes synchronization and enables NMI on PAL NES
|
|
; Preserved: X, Y
|
|
; Time: about 20 frames
|
|
init_nmi_sync_pal:
|
|
; NMI will first occur within frame 2 after
|
|
; synchronization
|
|
lda #2
|
|
sta nmi_sync_count
|
|
|
|
; Disable interrupts and rendering
|
|
sei
|
|
lda #0
|
|
sta $2000
|
|
sta $2001
|
|
|
|
; Coarse synchronize
|
|
bit $2002
|
|
init_nmi_sync_pal_1:
|
|
bit $2002
|
|
bpl init_nmi_sync_pal_1
|
|
|
|
; Synchronize to odd CPU cycle
|
|
sta $4014
|
|
bit <0
|
|
|
|
; Fine synchronize
|
|
init_nmi_sync_pal_2:
|
|
bit <0
|
|
nop
|
|
bit $2002
|
|
bit $2002
|
|
bpl init_nmi_sync_pal_2
|
|
|
|
; Enable NMI
|
|
lda #$80
|
|
sta $2000
|
|
|
|
rts
|
|
|
|
|
|
; Waits until NMI occurs.
|
|
; Preserved: A, X, Y
|
|
wait_nmi:
|
|
pha
|
|
|
|
; Reset high/low flag so NMI can depend on it
|
|
bit $2002
|
|
|
|
; NMI must not occur during taken branch, so we
|
|
; only use branch to get out of loop.
|
|
lda nmi_sync_count
|
|
wait_nmi_1:
|
|
cmp nmi_sync_count
|
|
bne wait_nmi_2
|
|
jmp wait_nmi_1
|
|
wait_nmi_2:
|
|
pla
|
|
rts
|
|
|
|
|
|
; Must be called in NMI handler, before sprite DMA.
|
|
; Preserved: X, Y
|
|
begin_nmi_sync:
|
|
lda nmi_sync_count
|
|
and #$02
|
|
beq begin_nmi_sync_1
|
|
begin_nmi_sync_1:
|
|
rts
|
|
|
|
|
|
; Must be called after sprite DMA. Instructions before this
|
|
; must total 1715 (NTSC)/6900 (PAL) cycles, treating
|
|
; JSR begin_nmi_sync and STA $4014 as taking 10 cycles total)
|
|
; Next instruction will begin 2286 (NTSC)/7471 (PAL) cycles
|
|
; after the cycle that the frame began in.
|
|
; Preserved: X, Y
|
|
end_nmi_sync:
|
|
lda nmi_sync_count
|
|
inc nmi_sync_count
|
|
and #$02
|
|
bne end_nmi_sync_1
|
|
end_nmi_sync_1:
|
|
lda $2002
|
|
bmi end_nmi_sync_2
|
|
end_nmi_sync_2:
|
|
bmi end_nmi_sync_3
|
|
end_nmi_sync_3:
|
|
rts
|
|
|
|
|
|
; Keeps track of synchronization on frames where no
|
|
; synchronization is needed (where begin_nmi_sync/end_nmi_sync
|
|
; aren't called).
|
|
; Preserved: A, X, Y
|
|
track_nmi_sync:
|
|
inc nmi_sync_count
|
|
rts
|