Optimization to avoid recalculating DOC frequencies when APU value does not change

This commit is contained in:
Lucas Scharenbroich 2023-06-18 00:12:53 -05:00
parent bdb4006e22
commit a1261e8339

View File

@ -587,6 +587,9 @@ interrupt_handler = *
cmp #8 cmp #8
bcc :mute_pulse1 bcc :mute_pulse1
cmp _apu_pulse1_last_period ; it's expensive to recalc frequencies, so avoid it when possible
beq :freq_end_pulse1
sta _apu_pulse1_last_period
jsr get_pulse_freq ; return freq in 16-bit accumulator jsr get_pulse_freq ; return freq in 16-bit accumulator
sep #$30 sep #$30
ldx #$00+pulse1_oscillator ldx #$00+pulse1_oscillator
@ -596,6 +599,7 @@ interrupt_handler = *
stx sound_address stx sound_address
xba xba
sta sound_data sta sound_data
:freq_end_pulse1 sep #$30 ; redundent, but avoids extra branches
lda #$80+pulse1_oscillator lda #$80+pulse1_oscillator
sta sound_address sta sound_address
@ -627,6 +631,9 @@ interrupt_handler = *
cmp #8 cmp #8
bcc :mute_pulse2 bcc :mute_pulse2
cmp _apu_pulse2_last_period
beq :freq_end_pulse2
sta _apu_pulse2_last_period
jsr get_pulse_freq ; return freq in 16-bic accumulator jsr get_pulse_freq ; return freq in 16-bic accumulator
sep #$30 sep #$30
ldx #$00+pulse2_oscillator ldx #$00+pulse2_oscillator
@ -636,6 +643,7 @@ interrupt_handler = *
stx sound_address stx sound_address
xba xba
sta sound_data sta sound_data
:freq_end_pulse2 sep #$30
lda #$80+pulse2_oscillator lda #$80+pulse2_oscillator
sta sound_address sta sound_address
@ -676,6 +684,9 @@ interrupt_handler = *
; Man's stage. At the expense of accuracy, these can be eliminated in an emulator e.g. by halting the ; Man's stage. At the expense of accuracy, these can be eliminated in an emulator e.g. by halting the
; triangle channel when an ultrasonic frequency is set (a timer value less than 2). ; triangle channel when an ultrasonic frequency is set (a timer value less than 2).
cmp _apu_triangle_last_period
beq :freq_end_triangle
sta _apu_triangle_last_period
jsr get_pulse_freq ; return freq in 16-bic accumulator jsr get_pulse_freq ; return freq in 16-bic accumulator
lsr lsr
sep #$30 sep #$30
@ -686,6 +697,7 @@ interrupt_handler = *
stx sound_address stx sound_address
xba xba
sta sound_data sta sound_data
:freq_end_triangle sep #$30
lda #$40+triangle_oscillator lda #$40+triangle_oscillator
sta sound_address sta sound_address
@ -701,23 +713,17 @@ interrupt_handler = *
; Now the noise channel. It's mixer volume output is ~half of the pulse channels ; Now the noise channel. It's mixer volume output is ~half of the pulse channels
lda #$40+noise_oscillator
sta sound_address
lda APU_NOISE_LENGTH_COUNTER ; If the length counter is zero, no output lda APU_NOISE_LENGTH_COUNTER ; If the length counter is zero, no output
beq :set_volume_noise beq :mute_noise
lda APU_NOISE_REG1
bit #NOISE_CONST_VOL_FLAG ; Check the constant volume bit
bne :set_volume_noise
lda APU_NOISE_ENVELOPE
:set_volume_noise
jsr set_pulse_volume
rep #$30 rep #$30
lda APU_NOISE_CURRENT_PERIOD lda APU_NOISE_CURRENT_PERIOD
cmp _apu_noise_last_period ; it's expensive to recalc frequencies, so avoid it when possible
beq :freq_end_noise
sta _apu_noise_last_period
jsr get_pulse_freq ; return freq in 16-bic accumulator jsr get_pulse_freq ; return freq in 16-bic accumulator
sep #$30 sep #$30
ldx #$00+noise_oscillator ldx #$00+noise_oscillator
stx sound_address stx sound_address
sta sound_data sta sound_data
@ -725,9 +731,23 @@ interrupt_handler = *
stx sound_address stx sound_address
xba xba
sta sound_data sta sound_data
:freq_end_noise sep #$30
lda #$40+noise_oscillator
sta sound_address
lda APU_NOISE_REG1
bit #NOISE_CONST_VOL_FLAG ; Check the constant volume bit
bne :set_volume_noise
lda APU_NOISE_ENVELOPE
bra :set_volume_noise
:mute_noise
sep #$30
lda #$40+noise_oscillator
sta sound_address
lda #0
:set_volume_noise jsr set_pulse_volume
:not_timer :not_timer
sep #$30
lda #0 lda #0
jsr setborder jsr setborder
@ -817,49 +837,11 @@ turn_off_interrupts
apu_frame_counter dw 0 ; frame counter, clocked at 240Hz from the interrupt handler apu_frame_counter dw 0 ; frame counter, clocked at 240Hz from the interrupt handler
; Internal APU register offsets
;length_counter_halt equ 0
;length_counter equ 1
;constant_volume_flag equ 2
;volume equ 3
;current_period equ 4
;target_period equ 6
; Internal APU registers for channel 1
;apu_pulse1 ds 8
;apu_pulse2 ds 8
;apu_pulse1_length_counter dfb 0
;apu_pulse1_decay_level dfb 0
;apu_pulse1_current_period dw 0
;apu_pulse2_length_counter dfb 0
;apu_pulse2_decay_level dfb 0
;apu_pulse2_current_period dw 0
duty_cycle_page dfb $01,$02,$03,$04 ; Page of DOC RAM that holds the different duty cycle wavforms duty_cycle_page dfb $01,$02,$03,$04 ; Page of DOC RAM that holds the different duty cycle wavforms
border_color dw 0 border_color dw 0
dividend dw 0 dividend dw 0 ; Used when converting from NES APU values to DOC values
divisor dw 0 divisor dw 0
last_phase1_duty_cycle dfb $ff
last_phase2_duty_cycle dfb $ff
; 8-bit mode
; A = register number
; X = register value
mx %00
SetDOCReg
stal $E0C03E
txa
stal $E0C03D
rts
_SetDOCReg mac
lda ]1 ; Select the oscillator enable registers
ldx ]2
jsr SetDOCReg
<<<
; Pulse Channel 1 ; Pulse Channel 1
APU_PULSE1 APU_PULSE1
APU_PULSE1_REG1 ds 1 ; DDLC NNNN - Duty, length counter halt, constant volume/evelope, envelope period/volume APU_PULSE1_REG1 ds 1 ; DDLC NNNN - Duty, length counter halt, constant volume/evelope, envelope period/volume
@ -877,7 +859,7 @@ APU_PULSE1_START_FLAG dfb 0
APU_PULSE1_ENVELOPE_DIVIDER dfb 0 APU_PULSE1_ENVELOPE_DIVIDER dfb 0
APU_PULSE1_ENVELOPE dfb 0 APU_PULSE1_ENVELOPE dfb 0
_apu_pulse1_last_period dw 0 ; optimization _apu_pulse1_last_period dw $FFFF ; optimization
APU_PULSE2 APU_PULSE2
@ -896,7 +878,7 @@ APU_PULSE2_START_FLAG dfb 0
APU_PULSE2_ENVELOPE_DIVIDER dfb 0 APU_PULSE2_ENVELOPE_DIVIDER dfb 0
APU_PULSE2_ENVELOPE dfb 0 APU_PULSE2_ENVELOPE dfb 0
_apu_pulse2_last_period dw 0 ; optimization _apu_pulse2_last_period dw $FFFF ; optimization
APU_TRIANGLE APU_TRIANGLE
@ -910,6 +892,8 @@ APU_TRIANGLE_CURRENT_PERIOD dw 0
APU_TRIANGLE_START_FLAG dfb 0 APU_TRIANGLE_START_FLAG dfb 0
APU_TRIANGLE_LINEAR_COUNTER dfb 0 APU_TRIANGLE_LINEAR_COUNTER dfb 0
_apu_triangle_last_period dw $FFFF ; optimization
APU_NOISE APU_NOISE
APU_NOISE_REG1 ds 1 ; --LC NNNN - length counter halt, constant volume/evelope, envelope period/volume APU_NOISE_REG1 ds 1 ; --LC NNNN - length counter halt, constant volume/evelope, envelope period/volume
@ -927,6 +911,9 @@ APU_NOISE_START_FLAG dfb 0
APU_NOISE_ENVELOPE_DIVIDER dfb 0 APU_NOISE_ENVELOPE_DIVIDER dfb 0
APU_NOISE_ENVELOPE dfb 0 APU_NOISE_ENVELOPE dfb 0
_apu_noise_last_period dw $FFFF ; optimization
APU_STATUS ds 1 APU_STATUS ds 1
mx %11 mx %11