diff --git a/demos/smb/App.Msg.s b/demos/smb/App.Msg.s index 7a3d4aa..6464600 100644 --- a/demos/smb/App.Msg.s +++ b/demos/smb/App.Msg.s @@ -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 diff --git a/demos/smb/Main.s b/demos/smb/Main.s index ab8b055..5400b4c 100644 --- a/demos/smb/Main.s +++ b/demos/smb/Main.s @@ -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 diff --git a/demos/smb/_FileInformation.txt b/demos/smb/_FileInformation.txt index 1bbc79f..f4873a7 100644 --- a/demos/smb/_FileInformation.txt +++ b/demos/smb/_FileInformation.txt @@ -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) diff --git a/demos/smb/apu.s b/demos/smb/apu.s index 6405627..7ca1f71 100644 --- a/demos/smb/apu.s +++ b/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 diff --git a/demos/smb/font.s b/demos/smb/font.s index 8c71e10..8d03d8b 100644 --- a/demos/smb/font.s +++ b/demos/smb/font.s @@ -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 diff --git a/demos/smb/rom2.s b/demos/smb/rom2.s index aff7e0e..b0e6847 100644 --- a/demos/smb/rom2.s +++ b/demos/smb/rom2.s @@ -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