Mostly full implementations of the pulse channels
This commit is contained in:
parent
60d566e78c
commit
99184396fc
|
@ -1,3 +1,4 @@
|
|||
mx %00
|
||||
HexToChar dfb '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
|
||||
; Convert a byte (Acc) into a string and store at (Y)
|
||||
|
@ -40,6 +41,18 @@ Addr2ToString xba
|
|||
jsr ByteToString
|
||||
rts
|
||||
|
||||
; A=Value
|
||||
; X=Screen offset
|
||||
DrawByte phx ; Save register value
|
||||
phy
|
||||
ldy #ByteBuff+1
|
||||
jsr ByteToString
|
||||
ply
|
||||
plx
|
||||
lda #ByteBuff
|
||||
jsr DrawString
|
||||
rts
|
||||
|
||||
; A=Value
|
||||
; X=Screen offset
|
||||
DrawWord phx ; Save register value
|
||||
|
@ -57,6 +70,7 @@ ClearWord lda #EmptyBuff
|
|||
rts
|
||||
|
||||
EmptyBuff str ' '
|
||||
ByteBuff str '00'
|
||||
WordBuff str '0000'
|
||||
Addr3Buff str '000000' ; str adds leading length byte
|
||||
|
||||
|
|
|
@ -197,15 +197,15 @@ EvtLoop
|
|||
stz nmiCount
|
||||
|
||||
; sep #$20
|
||||
; lda #7
|
||||
; lda #1
|
||||
; stal ROMBase+$075f
|
||||
; stal ROMBase+$0766
|
||||
|
||||
; lda #3
|
||||
; lda #2
|
||||
; stal ROMBase+$0763
|
||||
; stal ROMBase+$075c
|
||||
|
||||
; lda #3
|
||||
; lda #2
|
||||
; stal ROMBase+$0767
|
||||
; stal ROMBase+$0760
|
||||
; rep #$30
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
SMBProto.SHK=Type(E0),AuxType(8002),VersionCreate(80),MinVersion(87),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
SMBProto2.SHK=Type(E0),AuxType(8002),VersionCreate(80),MinVersion(87),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
APUSim=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
SuperMarioGS=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
|
|
362
demos/smb/apu.s
362
demos/smb/apu.s
|
@ -315,17 +315,143 @@ pulse2_sound_settings = *
|
|||
triangle_sound_settings = *
|
||||
dfb $00+triangle_oscillator,default_freq ; frequency low register
|
||||
dfb $20+triangle_oscillator,default_freq/256 ; frequency high register
|
||||
dfb $40+triangle_oscillator,128 ; volume register, volume = 0
|
||||
dfb $40+triangle_oscillator,0 ; volume register, volume = 0
|
||||
dfb $80+triangle_oscillator,5 ; wavetable pointer register, point to $0500
|
||||
dfb $c0+triangle_oscillator,0 ; wavetable size register, 256 byte length
|
||||
dfb $a0+triangle_oscillator,0 ; mode register, set to free run
|
||||
|
||||
backup_interrupt_ptr ds 4
|
||||
|
||||
;-----------------------------------------------------------------------------------------
|
||||
; APU internals
|
||||
;-----------------------------------------------------------------------------------------
|
||||
mx %11
|
||||
clock_length mac
|
||||
lda ]1+{APU_PULSE1_REG1-APU_PULSE1}
|
||||
bit #PULSE_HALT_FLAG
|
||||
bne no_count
|
||||
lda ]1+{APU_PULSE1_LENGTH_COUNTER-APU_PULSE1}
|
||||
beq no_count
|
||||
dec
|
||||
sta ]1+{APU_PULSE1_LENGTH_COUNTER-APU_PULSE1}
|
||||
no_count <<<
|
||||
|
||||
clock_sweep mac
|
||||
lda ]1+{APU_PULSE1_SWEEP_DIVIDER-APU_PULSE1}
|
||||
dec
|
||||
sta ]1+{APU_PULSE1_SWEEP_DIVIDER-APU_PULSE1}
|
||||
bpl no_sweep
|
||||
|
||||
lda #1
|
||||
sta ]1+{APU_PULSE1_RELOAD_FLAG-APU_PULSE1}
|
||||
|
||||
lda ]1+{APU_PULSE1_REG2-APU_PULSE1} ; get the barrel shift argument from the register
|
||||
bpl no_sweep ; if sweep is not enabled, do nothing
|
||||
and #$07
|
||||
beq no_sweep ; shift must be != 0
|
||||
asl
|
||||
tax
|
||||
|
||||
lda ]1+{APU_PULSE1_REG2-APU_PULSE1} ; put the negate flag in the y register
|
||||
and #$08
|
||||
tay
|
||||
|
||||
rep #$20
|
||||
lda ]1+{APU_PULSE1_CURRENT_PERIOD-APU_PULSE1}
|
||||
cmp #8
|
||||
bcc no_sweep0 ; current period must be >= 8
|
||||
|
||||
lda ]1+{APU_PULSE1_REG3-APU_PULSE1} ; raw period stored in the register
|
||||
and #$7FF
|
||||
jmp (bitshift,x) ; shift it by the shifter amount
|
||||
bitshift da bitshift_0,bitshift_1,bitshift_2,bitshift_3,bitshift_4,bitshift_5,bitshift_6,bitshift_7
|
||||
bitshift_7 lsr
|
||||
bitshift_6 lsr
|
||||
bitshift_5 lsr
|
||||
bitshift_4 lsr
|
||||
bitshift_3 lsr
|
||||
bitshift_2 lsr
|
||||
bitshift_1 lsr
|
||||
bitshift_0
|
||||
cpy #0 ; check if the negate flag was set
|
||||
beq no_negate
|
||||
eor #$FFFF ; pulse 1 uses 1's complement
|
||||
DO ]2
|
||||
inc
|
||||
FIN
|
||||
no_negate clc
|
||||
adc ]1+{APU_PULSE1_CURRENT_PERIOD-APU_PULSE1}
|
||||
sta ]1+{APU_PULSE1_TARGET_PERIOD-APU_PULSE1}
|
||||
|
||||
stz ]1+{APU_PULSE1_MUTE-APU_PULSE1}
|
||||
ldy #1
|
||||
cmp #$800
|
||||
bcc *+5
|
||||
sty ]1+{APU_PULSE1_MUTE-APU_PULSE1} ; mute the output is the period is too large
|
||||
bcs *+5
|
||||
sta ]1+{APU_PULSE1_CURRENT_PERIOD-APU_PULSE1} ; set the current period if the target is within a valid range
|
||||
|
||||
lda ]1+{APU_PULSE1_CURRENT_PERIOD-APU_PULSE1}
|
||||
cmp #8
|
||||
bcs *+5
|
||||
sty ]1+{APU_PULSE1_MUTE-APU_PULSE1} ; mute the output if the period is too small
|
||||
|
||||
no_sweep0
|
||||
sep #$20
|
||||
no_sweep
|
||||
lda ]1+{APU_PULSE1_RELOAD_FLAG-APU_PULSE1} ; check if we need to reload the sweep delay
|
||||
beq no_reload
|
||||
stz ]1+{APU_PULSE1_RELOAD_FLAG-APU_PULSE1}
|
||||
lda ]1+{APU_PULSE1_REG2-APU_PULSE1}
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
and #7
|
||||
sta ]1+{APU_PULSE1_SWEEP_DIVIDER-APU_PULSE1}
|
||||
no_reload <<<
|
||||
|
||||
clock_envelope mac
|
||||
lda ]1+{APU_PULSE1_START_FLAG-APU_PULSE1}
|
||||
beq no_start
|
||||
stz ]1+{APU_PULSE1_START_FLAG-APU_PULSE1} ; clear the start flag
|
||||
lda #15
|
||||
sta ]1+{APU_PULSE1_ENVELOPE-APU_PULSE1} ; reset the envelope saw wave decay value
|
||||
lda ]1+{APU_PULSE1_REG1-APU_PULSE1}
|
||||
and #$0F
|
||||
sta ]1+{APU_PULSE1_ENVELOPE_DIVIDER-APU_PULSE1} ; reset the divider value
|
||||
bra envelope_out ; nothing else to do
|
||||
|
||||
no_start
|
||||
lda ]1+{APU_PULSE1_ENVELOPE_DIVIDER-APU_PULSE1} ; clock the divider
|
||||
dec
|
||||
sta ]1+{APU_PULSE1_ENVELOPE_DIVIDER-APU_PULSE1}
|
||||
bpl envelope_out ; as long as divider is >=0, nothing to do
|
||||
|
||||
lda ]1+{APU_PULSE1_REG1-APU_PULSE1} ; reset the divider to the volume/envelope value
|
||||
and #$0F
|
||||
sta ]1+{APU_PULSE1_ENVELOPE_DIVIDER-APU_PULSE1}
|
||||
|
||||
lda ]1+{APU_PULSE1_ENVELOPE-APU_PULSE1}
|
||||
bne tick_envelope
|
||||
|
||||
lda ]1+{APU_PULSE1_REG1-APU_PULSE1} ; if decay level counter is 0, check the loop bit and set counter to 15 if loop bit is set
|
||||
bit #PULSE_HALT_FLAG
|
||||
beq envelope_out
|
||||
lda #16 ; Set to 15
|
||||
tick_envelope
|
||||
dec
|
||||
sta ]1+{APU_PULSE1_ENVELOPE-APU_PULSE1}
|
||||
envelope_out <<<
|
||||
|
||||
;-----------------------------------------------------------------------------------------
|
||||
; interupt handler
|
||||
;-----------------------------------------------------------------------------------------
|
||||
|
||||
apu_frame_steps equ 5
|
||||
PULSE_HALT_FLAG equ $20
|
||||
PULSE_CONST_VOL_FLAG equ $10
|
||||
|
||||
interrupt_handler = *
|
||||
|
||||
phb
|
||||
|
@ -345,6 +471,36 @@ interrupt_handler = *
|
|||
sep #$30
|
||||
mx %11
|
||||
|
||||
; Update the frame counter. We double-count so that frame counter can be used directly to dispatch to the
|
||||
; appropriate tick handler
|
||||
|
||||
ldx apu_frame_counter
|
||||
inx
|
||||
inx
|
||||
cpx #2*apu_frame_steps ; TODO: This is set by MSB in $4017 (4 or 5). 4 = PAL, 5 = NTSC.
|
||||
bcc *+4
|
||||
ldx #0
|
||||
stx apu_frame_counter
|
||||
jmp (:frame_counter_proc,x)
|
||||
:frame_counter_proc da :quarter_frame,:half_frame,:quarter_frame,:no_frame,:half_frame
|
||||
:half_frame
|
||||
|
||||
; clock the length counters
|
||||
clock_length APU_PULSE1
|
||||
clock_length APU_PULSE2
|
||||
|
||||
; clock the sweep units
|
||||
clock_sweep APU_PULSE1;0
|
||||
clock_sweep APU_PULSE2;1
|
||||
|
||||
; quarter frame updates run every APU frame (for 4-cycle)
|
||||
:quarter_frame
|
||||
|
||||
; clock the envelopes and triangle linear counter
|
||||
clock_envelope APU_PULSE1
|
||||
clock_envelope APU_PULSE2
|
||||
|
||||
:no_frame
|
||||
jsr access_doc_registers
|
||||
|
||||
ldal osc_interrupt ; which oscillator generated the interrupt?
|
||||
|
@ -358,19 +514,30 @@ interrupt_handler = *
|
|||
|
||||
lda #$80+pulse1_oscillator
|
||||
sta sound_address
|
||||
lda APU_PULSE1_REG1 ; Get the cycle duty bits
|
||||
lda APU_PULSE1_REG1 ; Get the cycle duty bits
|
||||
jsr set_pulse_duty_cycle
|
||||
|
||||
lda #$40+pulse1_oscillator
|
||||
sta sound_address
|
||||
|
||||
lda APU_PULSE1_MUTE ; If the sweep muted the channel, no output
|
||||
beq :no_mute_pulse1
|
||||
lda #0
|
||||
bra :set_volume_pulse1
|
||||
:no_mute_pulse1
|
||||
lda APU_PULSE1_LENGTH_COUNTER ; If the length counter is zero, no output
|
||||
beq :set_volume_pulse1
|
||||
lda APU_PULSE1_REG1
|
||||
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
||||
bne :set_volume_pulse1
|
||||
lda APU_PULSE1_ENVELOPE
|
||||
:set_volume_pulse1
|
||||
jsr set_pulse_volume
|
||||
|
||||
rep #$30
|
||||
lda APU_PULSE1_REG3
|
||||
jsr get_pulse_freq ; return freq in 16-bic accumulator
|
||||
lda APU_PULSE1_CURRENT_PERIOD
|
||||
jsr get_pulse_freq ; return freq in 16-bit accumulator
|
||||
sep #$30
|
||||
|
||||
ldx #$00+pulse1_oscillator
|
||||
stx sound_address
|
||||
sta sound_data
|
||||
|
@ -388,14 +555,25 @@ interrupt_handler = *
|
|||
|
||||
lda #$40+pulse2_oscillator
|
||||
sta sound_address
|
||||
|
||||
lda APU_PULSE2_MUTE ; If the sweep muted the channel, no output
|
||||
beq :no_mute_pulse2
|
||||
lda #0
|
||||
bra :set_volume_pulse2
|
||||
:no_mute_pulse2
|
||||
lda APU_PULSE2_LENGTH_COUNTER ; If the length counter is zero, no output
|
||||
beq :set_volume_pulse2
|
||||
lda APU_PULSE2_REG1
|
||||
bit #PULSE_CONST_VOL_FLAG ; Check the constant volume bit
|
||||
bne :set_volume_pulse2
|
||||
lda APU_PULSE2_ENVELOPE
|
||||
:set_volume_pulse2
|
||||
jsr set_pulse_volume
|
||||
|
||||
rep #$30
|
||||
lda APU_PULSE2_REG3
|
||||
lda APU_PULSE2_CURRENT_PERIOD
|
||||
jsr get_pulse_freq ; return freq in 16-bic accumulator
|
||||
sep #$30
|
||||
|
||||
ldx #$00+pulse2_oscillator
|
||||
stx sound_address
|
||||
sta sound_data
|
||||
|
@ -405,6 +583,7 @@ interrupt_handler = *
|
|||
sta sound_data
|
||||
|
||||
; Now the triangle wave. This wave needs linear counter support to be silenced
|
||||
; brl :not_timer
|
||||
|
||||
rep #$30
|
||||
lda APU_TRIANGLE_REG3
|
||||
|
@ -463,7 +642,7 @@ set_pulse_volume
|
|||
; Solving for F_HL = (1 / 0.200807) * 111860.812 / (t + 1)
|
||||
; = 557056.338 / (t + 1)
|
||||
;
|
||||
; if t < 8 this value is out of range and the scillator should be silenced
|
||||
; if t < 8 this value is out of range and the oscillator should be silenced
|
||||
;
|
||||
; otherwise, break apart the ratio
|
||||
;
|
||||
|
@ -471,9 +650,7 @@ set_pulse_volume
|
|||
;
|
||||
get_pulse_freq
|
||||
mx %00
|
||||
and #$07FF ; Load the timer value (11-bits); freq = 1.79MHz / (16 * (t - 1)) = 111860Hz / (t-1)
|
||||
cmp #8
|
||||
bcc :no_sound
|
||||
and #$7FF ; prevent overflow...
|
||||
inc
|
||||
sta divisor
|
||||
lda #55706
|
||||
|
@ -495,13 +672,8 @@ get_pulse_freq
|
|||
asl
|
||||
asl
|
||||
clc
|
||||
adc dividend ; multiple by 10 to get the approx DOC value (0.2Hz per + post-multiple)
|
||||
adc dividend ; multiple by 10 to get the DOC value
|
||||
asl
|
||||
|
||||
; sta dividend
|
||||
rts
|
||||
:no_sound
|
||||
lda #0
|
||||
rts
|
||||
|
||||
turn_off_interrupts
|
||||
|
@ -514,6 +686,33 @@ turn_off_interrupts
|
|||
plp
|
||||
rts
|
||||
|
||||
; Internal APU registers.
|
||||
;
|
||||
; These variables track the internal flags, counters and other status bits that make up
|
||||
; the core functionality of the different channel hardware
|
||||
|
||||
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
|
||||
border_color dw 0
|
||||
dividend dw 0
|
||||
|
@ -539,17 +738,43 @@ _SetDOCReg mac
|
|||
|
||||
; Pulse Channel 1
|
||||
APU_PULSE1
|
||||
APU_PULSE1_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
|
||||
APU_PULSE1_REG1 ds 1 ; DDLC NNNN - Duty, length counter halt, constant volume/evelope, envelope period/volume
|
||||
APU_PULSE1_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
|
||||
APU_PULSE1_REG3 ds 1 ; LLLL LLLL - Timer Low
|
||||
APU_PULSE1_REG4 ds 1 ; llll lHHH - Length counter load, timer high (also resets duty and starts envelope)
|
||||
|
||||
APU_PULSE1_LENGTH_COUNTER dfb 0 ; internal register for the length counter
|
||||
APU_PULSE1_RELOAD_FLAG dfb 0 ; internal register to reload the sweep divider value
|
||||
APU_PULSE1_SWEEP_DIVIDER dfb 0 ; internal register to track the sweep divider value
|
||||
APU_PULSE1_TARGET_PERIOD dw 0 ; internal register to hold the sweep unit target period
|
||||
APU_PULSE1_CURRENT_PERIOD dw 0 ; internal register to hold the current period driving the oscillator
|
||||
APU_PULSE1_MUTE dfb 0
|
||||
APU_PULSE1_START_FLAG dfb 0
|
||||
APU_PULSE1_ENVELOPE_DIVIDER dfb 0
|
||||
APU_PULSE1_ENVELOPE dfb 0
|
||||
|
||||
_apu_pulse1_last_period dw 0 ; optimization
|
||||
|
||||
|
||||
APU_PULSE2
|
||||
APU_PULSE2_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
|
||||
APU_PULSE2_REG1 ds 1 ; DDLC NNNN - Duty, length counter halt, constant volume/evelope, envelope period/volume
|
||||
APU_PULSE2_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
|
||||
APU_PULSE2_REG3 ds 1 ; LLLL LLLL - Timer Low
|
||||
APU_PULSE2_REG4 ds 1 ; llll lHHH - Length counter load, timer high (also resets duty and starts envelope)
|
||||
|
||||
APU_PULSE2_LENGTH_COUNTER dfb 0 ; internal register for the length counter
|
||||
APU_PULSE2_RELOAD_FLAG dfb 0 ; internal register to reload the sweep divider value
|
||||
APU_PULSE2_SWEEP_DIVIDER dfb 0 ; internal register to track the sweep divider value
|
||||
APU_PULSE2_TARGET_PERIOD dw 0 ; internal register to hold the sweep unit target period
|
||||
APU_PULSE2_CURRENT_PERIOD dw 0 ; internal register to hold the current period driving the oscillator
|
||||
APU_PULSE2_MUTE dfb 0
|
||||
APU_PULSE2_START_FLAG dfb 0
|
||||
APU_PULSE2_ENVELOPE_DIVIDER dfb 0
|
||||
APU_PULSE2_ENVELOPE dfb 0
|
||||
|
||||
_apu_pulse2_last_period dw 0 ; optimization
|
||||
|
||||
|
||||
APU_TRIANGLE
|
||||
APU_TRIANGLE_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
|
||||
APU_TRIANGLE_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
|
||||
|
@ -564,32 +789,103 @@ APU_PULSE1_REG1_WRITE ENT
|
|||
rtl
|
||||
|
||||
APU_PULSE1_REG2_WRITE ENT
|
||||
php
|
||||
pha
|
||||
stal APU_PULSE1_REG2
|
||||
lda #1
|
||||
stal APU_PULSE1_RELOAD_FLAG ; mark that this register was written to
|
||||
pla
|
||||
plp
|
||||
rtl
|
||||
|
||||
APU_PULSE1_REG3_WRITE ENT
|
||||
stal APU_PULSE1_CURRENT_PERIOD
|
||||
stal APU_PULSE1_REG3
|
||||
rtl
|
||||
|
||||
APU_PULSE1_REG4_WRITE ENT
|
||||
php
|
||||
phx
|
||||
pha
|
||||
|
||||
stal APU_PULSE1_REG4
|
||||
and #$07
|
||||
stal APU_PULSE1_CURRENT_PERIOD+1
|
||||
|
||||
; If the APU_STATUS bit is enabled, then load the length counter
|
||||
ldal APU_STATUS
|
||||
bit #$01
|
||||
beq :no_reload
|
||||
|
||||
ldal APU_PULSE1_REG4
|
||||
and #$F8
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
ldal LengthTable,x
|
||||
stal APU_PULSE1_LENGTH_COUNTER ; Immediately start the counter
|
||||
lda #1
|
||||
stal APU_PULSE1_START_FLAG
|
||||
|
||||
:no_reload
|
||||
pla
|
||||
plx
|
||||
plp
|
||||
rtl
|
||||
|
||||
; From https://www.nesdev.org/wiki/APU_Length_Counter
|
||||
LengthTable
|
||||
db 10,254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14
|
||||
db 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30
|
||||
|
||||
APU_PULSE2_REG1_WRITE ENT
|
||||
stal APU_PULSE2_REG1
|
||||
rtl
|
||||
|
||||
APU_PULSE2_REG2_WRITE ENT
|
||||
php
|
||||
pha
|
||||
stal APU_PULSE2_REG2
|
||||
lda #1
|
||||
stal APU_PULSE2_RELOAD_FLAG
|
||||
pla
|
||||
plp
|
||||
rtl
|
||||
|
||||
APU_PULSE2_REG3_WRITE ENT
|
||||
stal APU_PULSE2_CURRENT_PERIOD
|
||||
stal APU_PULSE2_REG3
|
||||
rtl
|
||||
|
||||
APU_PULSE2_REG4_WRITE ENT
|
||||
php
|
||||
phx
|
||||
pha
|
||||
|
||||
stal APU_PULSE2_REG4
|
||||
and #$07
|
||||
stal APU_PULSE2_CURRENT_PERIOD+1
|
||||
|
||||
ldal APU_STATUS
|
||||
bit #$01
|
||||
beq :no_reload
|
||||
|
||||
ldal APU_PULSE2_REG4
|
||||
and #$F8
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
ldal LengthTable,x
|
||||
stal APU_PULSE2_LENGTH_COUNTER ; Immediately start the counter
|
||||
lda #1
|
||||
stal APU_PULSE2_START_FLAG
|
||||
|
||||
:no_reload
|
||||
pla
|
||||
plx
|
||||
plp
|
||||
rtl
|
||||
|
||||
|
||||
|
@ -614,23 +910,21 @@ APU_STATUS_WRITE ENT
|
|||
stal APU_STATUS
|
||||
pha
|
||||
|
||||
; Pulse 1 is OSC 0
|
||||
bit #$01
|
||||
beq :pulse1_off
|
||||
; _SetDOCReg #$40+pulse1_oscillator;#128
|
||||
bra :pulse1_end
|
||||
:pulse1_off
|
||||
; _SetDOCReg #$40+pulse1_oscillator;#0
|
||||
:pulse1_end
|
||||
; From NESDev Wiki: When the enabled bit is cleared (via $4015), the length counter is forced to 0
|
||||
; and cannot be changed until enabled is set again (the length counter's previous value is lost).
|
||||
; There is no immediate effect when enabled is set.
|
||||
|
||||
; Pulse 2 is OSC 2
|
||||
; Pulse 1
|
||||
bit #$01
|
||||
bne :pulse1_on
|
||||
stz APU_PULSE1_LENGTH_COUNTER
|
||||
:pulse1_on
|
||||
|
||||
; Pulse 2
|
||||
bit #$02
|
||||
beq :pulse2_off
|
||||
; _SetDOCReg #$40+pulse2_oscillator;#128
|
||||
bra :pulse2_end
|
||||
:pulse2_off
|
||||
; _SetDOCReg #$40+pulse2_oscillator;#0
|
||||
:pulse2_end
|
||||
bne :pulse2_on
|
||||
stz APU_PULSE2_LENGTH_COUNTER
|
||||
:pulse2_on
|
||||
|
||||
; Triangle is OSC 4
|
||||
; bit #$03
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
; draw char at loc
|
||||
; update loc
|
||||
; see if length hit - no? back to draw char
|
||||
rel
|
||||
; rel
|
||||
mx %00
|
||||
]F_Length ds 2 ;length of string (only one byte currently used)
|
||||
]F_CharIdx ds 2 ;index of current character
|
||||
|
@ -19,6 +19,55 @@
|
|||
]F_StrPtr equ $01 ;pointer to string (including length byte) / DP
|
||||
]F_StrClr equ $03
|
||||
|
||||
;x = TopLeft screen pos
|
||||
;y = font mask
|
||||
;a = 8-bit char
|
||||
DrawBottom
|
||||
pha ; local variable space
|
||||
pha
|
||||
tsc
|
||||
phd
|
||||
tcd
|
||||
|
||||
sty ]F_StrClr
|
||||
lda 3,s
|
||||
sec
|
||||
sbc #' '
|
||||
asl ;*2
|
||||
tay
|
||||
|
||||
jsr drawBottom
|
||||
|
||||
pld
|
||||
pla
|
||||
pla
|
||||
rts
|
||||
|
||||
;x = TopLeft screen pos
|
||||
;y = font mask
|
||||
;a = 8-bit char
|
||||
DrawChar
|
||||
pha ; local variable space
|
||||
pha
|
||||
tsc
|
||||
phd
|
||||
tcd
|
||||
|
||||
sty ]F_StrClr
|
||||
lda 3,s
|
||||
sec
|
||||
sbc #' '
|
||||
asl ;*2
|
||||
tay
|
||||
|
||||
jsr drawChar
|
||||
|
||||
pld
|
||||
pla
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
DrawString
|
||||
pha ; local variable space
|
||||
pha
|
||||
|
@ -52,16 +101,20 @@ NextChar lda ]F_CharIdx
|
|||
asl ;*2
|
||||
tay
|
||||
ldx ]F_CurrentPos
|
||||
jsr :drawChar
|
||||
jsr drawChar
|
||||
inc ]F_CurrentPos ;compare to addition time (?)
|
||||
inc ]F_CurrentPos
|
||||
inc ]F_CurrentPos
|
||||
inc ]F_CurrentPos ;update screen pos (2 words=8 pixels)
|
||||
bra NextChar
|
||||
|
||||
;x = TopLeft screen pos
|
||||
;y = char table offset
|
||||
:drawChar lda FontTable,y ;get real address of char data
|
||||
drawBottom lda FontTable,y ;get real address of char data
|
||||
sec
|
||||
sbc #FontData ;pivot offset - now a is offset of fontdata
|
||||
tay ;so we'll index with that
|
||||
brl bottom
|
||||
|
||||
drawChar lda FontTable,y ;get real address of char data
|
||||
sec
|
||||
sbc #FontData ;pivot offset - now a is offset of fontdata
|
||||
tay ;so we'll index with that
|
||||
|
@ -106,6 +159,7 @@ NextChar lda ]F_CharIdx
|
|||
and ]F_StrClr
|
||||
stal {$E12000+160*4+2},x
|
||||
|
||||
bottom
|
||||
lda FontData+20,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*5},x
|
||||
|
|
|
@ -722,30 +722,37 @@ APU_IND_X_REG3_W
|
|||
:reg_tbl dw APU_PULSE1_REG3_W,APU_PULSE1_REG3_W
|
||||
dw APU_PULSE2_REG3_W,APU_PULSE2_REG3_W,
|
||||
dw APU_TRIANGLE_REG3_W,APU_TRIANGLE_REG3_W
|
||||
dw NO_OP,NO_OP
|
||||
|
||||
APU_IND_X_REG4_W
|
||||
jmp (:reg_tbl,x)
|
||||
:reg_tbl dw APU_PULSE1_REG4_W,APU_PULSE1_REG4_W
|
||||
dw APU_PULSE2_REG4_W,APU_PULSE2_REG4_W,
|
||||
dw APU_TRIANGLE_REG4_W,APU_TRIANGLE_REG4_W
|
||||
dw NO_OP,NO_OP
|
||||
|
||||
APU_PULSE1_REG1_W
|
||||
jsl APU_PULSE1_REG1_WRITE
|
||||
NO_OP
|
||||
rts
|
||||
APU_PULSE1_REG1_WX
|
||||
phx
|
||||
pha
|
||||
txa
|
||||
jsl APU_PULSE1_REG1_WRITE
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
APU_PULSE1_REG2_W
|
||||
jsl APU_PULSE1_REG2_WRITE
|
||||
rts
|
||||
APU_PULSE1_REG2_WY
|
||||
phy
|
||||
pha
|
||||
tya
|
||||
jsl APU_PULSE1_REG2_WRITE
|
||||
pla
|
||||
ply
|
||||
rts
|
||||
APU_PULSE1_REG3_W
|
||||
jsl APU_PULSE1_REG3_WRITE
|
||||
|
@ -758,25 +765,31 @@ APU_PULSE2_REG1_W
|
|||
jsl APU_PULSE2_REG1_WRITE
|
||||
rts
|
||||
APU_PULSE2_REG1_WX
|
||||
phx
|
||||
pha
|
||||
txa
|
||||
jsl APU_PULSE2_REG1_WRITE
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
APU_PULSE2_REG2_W
|
||||
jsl APU_PULSE2_REG2_WRITE
|
||||
rts
|
||||
APU_PULSE2_REG2_WY
|
||||
phy
|
||||
pha
|
||||
tya
|
||||
jsl APU_PULSE2_REG2_WRITE
|
||||
pla
|
||||
ply
|
||||
rts
|
||||
APU_PULSE2_REG2_WX
|
||||
phx
|
||||
pha
|
||||
txa
|
||||
jsl APU_PULSE2_REG2_WRITE
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
APU_PULSE2_REG3_W
|
||||
jsl APU_PULSE2_REG3_WRITE
|
||||
|
@ -802,7 +815,10 @@ APU_STATUS_W
|
|||
rts
|
||||
APU_STATUS_WX
|
||||
phx
|
||||
pha
|
||||
txa
|
||||
jsl APU_STATUS_WRITE
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
; Hooks to call back to the GTE harness for PPU memory-mapped accesses
|
||||
|
|
Loading…
Reference in New Issue