From 21d183616efd73da8b04c556a60a0c6947f97c04 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Sat, 24 Feb 2018 17:23:30 -0500 Subject: [PATCH] chiptune_player: split interrupt handler to own file --- asm_routines/lz4_decode.s | 7 +- chiptune_player/Makefile | 2 +- chiptune_player/chiptune_player.s | 170 +--------------------------- chiptune_player/interrupt_handler.s | 158 ++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 168 deletions(-) create mode 100644 chiptune_player/interrupt_handler.s diff --git a/asm_routines/lz4_decode.s b/asm_routines/lz4_decode.s index 52e4ca39..66a7c878 100644 --- a/asm_routines/lz4_decode.s +++ b/asm_routines/lz4_decode.s @@ -36,7 +36,8 @@ ;COUNT EQU $06 ;DELTA EQU $08 -orgoff EQU $5E00 ; offset of first unpacked byte +;UNPACK_BUFFER EQU $5E00 ; offset of first unpacked byte + ;====================== ; LZ4 decode @@ -54,9 +55,9 @@ lz4_decode: adc LZ4_END+1 sta LZ4_END+1 - lda #>orgoff ; original unpacked data offset + lda #>UNPACK_BUFFER ; original unpacked data offset sta LZ4_DST+1 - lda #CHUNK_BUFFER + lda #>UNPACK_BUFFER sta INH @@ -196,167 +196,8 @@ done_play: forever_loop: jmp forever_loop - ;============================= - ;============================= - ; simple interrupt handler - ;============================= - ;============================= - ; On Apple II/6502 the interrupt handler jumps to address in 0xfffe - ; This is in the ROM, which saves the registers - ; on older IIe it saved A to $45 (which could mess with DISK II) - ; newer IIe doesn't do that. - ; It then calculates if it is a BRK or not (which trashes A) - ; Then it sets up the stack like an interrupt and calls 0x3fe - -interrupt_handler: - pha ; save A ; 3 -; tya -; pha -; txa -; pha - ; Should we save X and Y too? - -; inc $0404 ; debug - - bit $C404 ; clear 6522 interrupt by reading T1C-L ; 4 - ;============ - ; 7 - ;===================== - ; Update time counter - ;===================== - - inc FRAME_COUNT ; 5 - lda FRAME_COUNT ; 3 - cmp #50 ; 3 - bne frame_good ; 3/2nt - - lda #$0 ; 2 - sta FRAME_COUNT ; 3 - -update_second_ones: - inc $7d0+17 ; 6 - inc $bd0+17 ; 6 - lda $bd0+17 ; 4 - cmp #$ba ; one past '9' ; 2 - bne frame_good ; 3/2nt - lda #'0'+$80 ; 2 - sta $7d0+17 ; 4 - sta $bd0+17 ; 4 -update_second_tens: - inc $7d0+16 ; 6 - inc $bd0+16 ; 6 - lda $bd0+16 ; 4 - cmp #$b6 ; 6 (for 60 seconds) ; 2 - bne frame_good ; 3/2nt - lda #'0'+$80 ; 2 - sta $7d0+16 ; 4 - sta $bd0+16 ; 4 -update_minutes: - inc $7d0+14 ; 6 - inc $bd0+14 ; 6 - ; we don't handle > 9:59 songs yet - - ;============= - ; 90 worst - -frame_good: - - ldy MB_FRAME_DIFF ; get chunk offset ; 3 - - ldx #0 ; set up reg count ; 2 - - ;============= - ; 5 - -mb_write_loop: - lda (INL),y ; load register value ; 5 - - ; if REG==1 and high bit set - ; then end of song - - bpl mb_not_done ; 3/2nt - cpx #1 ; 2 - bne mb_not_done ; 3/2nt - - lda #1 ; set done playing ; 2 - sta DONE_PLAYING ; 3 - jmp done_interrupt ; 3 - -mb_not_done: - - ; special case R13. If it is 0xff, then don't update - ; otherwise might spuriously reset the envelope settings - - cpx #13 ; 2 - bne mb_not_13 ; 3/2nt - cmp #$ff ; 2 - beq skip_r13 ; 3/2nt - -mb_not_13: - sta MB_VALUE ; 3 - - ; always write out all to zero page - ; we mostly care about vola/volb/volc so this wastes 11 bytes of RAM - ; code is simpler, and save on three cmp/branches per loop - - and #$f ; 2 - sta REGISTER_DUMP,X ; 4 - - ; INLINE this (could save 72 cycles) - jsr write_ay_both ; assume 3 channel (not six) ; 6 - ; so write same to both - ; left/right - ; 53 - - clc ; point to next interleaved ; 2 - lda INH ; page by adding $300 ; 3 - adc #CHUNKSIZE ; 2 - sta INH ; 3 - - inx ; point to next register ; 2 - cpx #14 ; if 14 we're done ; 2 - bmi mb_write_loop ; otherwise, loop ; 3/2nt - ;============ - ; roughly 95? - ; *13= 1235? -skip_r13: - - inc MB_FRAME_DIFF ; increment offset ; 5 - bne reset_chunk ; if not zero, done ; 3/2nt - -wraparound: - - inc MB_CHUNK ; go to next chunk ; 5 - lda MB_CHUNK ; 3 - cmp #CHUNKSIZE ; have we reached end? ; 2 - bne reset_chunk ; 3/2nt - lda #0 ; if so reset ; 2 - sta MB_CHUNK ; 3 - - ; can't tail call as need to restore stack and rti - jsr next_subsong ; and decompress next ; 6 - - -reset_chunk: - lda MB_CHUNK ; reset input pointer ; 3 - clc ; to the beginning ; 2 - - adc #>CHUNK_BUFFER ; in proper chunk (1 of 3) ; 2 - sta INH ; 3 - - - ;============ - ; 18 -done_interrupt: - pla ; restore a ; 4 - - rti ; return from interrupt ; 6 - - ;============ - ; typical - ; 1358 cycles ;================= ; load a new song @@ -526,13 +367,13 @@ bloop22: ; DST: chunk_buffer+$2A00+(COPY_OFFSET*256) page_copy: clc ; 2 - lda #>(CHUNK_BUFFER+512) ; 3 + lda #>(UNPACK_BUFFER+512) ; 3 adc COPY_OFFSET ; 3 adc COPY_OFFSET ; 3 adc COPY_OFFSET ; 3 sta page_copy_loop+2 ; self modify ; 5 - lda #>(CHUNK_BUFFER+$2A00) ; 2 + lda #>(UNPACK_BUFFER+$2A00) ; 2 adc COPY_OFFSET ; 3 sta page_copy_loop+5 ; self modify ; 5 @@ -581,6 +422,7 @@ krw_file: .include "../asm_routines/lz4_decode.s" .include "rasterbars.s" .include "volume_bars.s" +.include "interrupt_handler.s" ;========= ; strings diff --git a/chiptune_player/interrupt_handler.s b/chiptune_player/interrupt_handler.s new file mode 100644 index 00000000..b6f2a346 --- /dev/null +++ b/chiptune_player/interrupt_handler.s @@ -0,0 +1,158 @@ + ;================================ + ;================================ + ; mockingboard interrupt handler + ;================================ + ;================================ + ; On Apple II/6502 the interrupt handler jumps to address in 0xfffe + ; This is in the ROM, which saves the registers + ; on older IIe it saved A to $45 (which could mess with DISK II) + ; newer IIe doesn't do that. + ; It then calculates if it is a BRK or not (which trashes A) + ; Then it sets up the stack like an interrupt and calls 0x3fe + +interrupt_handler: + pha ; save A ; 3 + ; Should we save X and Y too? + +; inc $0404 ; debug + + bit $C404 ; clear 6522 interrupt by reading T1C-L ; 4 + + + ;============ + ; 7 + ;===================== + ; Update time counter + ;===================== + + inc FRAME_COUNT ; 5 + lda FRAME_COUNT ; 3 + cmp #50 ; 3 + bne frame_good ; 3/2nt + + lda #$0 ; 2 + sta FRAME_COUNT ; 3 + +update_second_ones: + inc $7d0+17 ; 6 + inc $bd0+17 ; 6 + lda $bd0+17 ; 4 + cmp #$ba ; one past '9' ; 2 + bne frame_good ; 3/2nt + lda #'0'+$80 ; 2 + sta $7d0+17 ; 4 + sta $bd0+17 ; 4 +update_second_tens: + inc $7d0+16 ; 6 + inc $bd0+16 ; 6 + lda $bd0+16 ; 4 + cmp #$b6 ; 6 (for 60 seconds) ; 2 + bne frame_good ; 3/2nt + lda #'0'+$80 ; 2 + sta $7d0+16 ; 4 + sta $bd0+16 ; 4 +update_minutes: + inc $7d0+14 ; 6 + inc $bd0+14 ; 6 + ; we don't handle > 9:59 songs yet + + ;============= + ; 90 worst + +frame_good: + + ldy MB_FRAME_DIFF ; get chunk offset ; 3 + + ldx #0 ; set up reg count ; 2 + + ;============= + ; 5 + +mb_write_loop: + lda (INL),y ; load register value ; 5 + + ; if REG==1 and high bit set + ; then end of song + + bpl mb_not_done ; 3/2nt + cpx #1 ; 2 + bne mb_not_done ; 3/2nt + + lda #1 ; set done playing ; 2 + sta DONE_PLAYING ; 3 + jmp done_interrupt ; 3 + +mb_not_done: + + ; special case R13. If it is 0xff, then don't update + ; otherwise might spuriously reset the envelope settings + + cpx #13 ; 2 + bne mb_not_13 ; 3/2nt + cmp #$ff ; 2 + beq skip_r13 ; 3/2nt + +mb_not_13: + sta MB_VALUE ; 3 + + ; always write out all to zero page + ; we mostly care about vola/volb/volc so this wastes 11 bytes of RAM + ; code is simpler, and save on three cmp/branches per loop + + and #$f ; 2 + sta REGISTER_DUMP,X ; 4 + + ; INLINE this (could save 72 cycles) + jsr write_ay_both ; assume 3 channel (not six) ; 6 + ; so write same to both + ; left/right + ; 53 + + clc ; point to next interleaved ; 2 + lda INH ; page by adding $300 ; 3 + adc #CHUNKSIZE ; 2 + sta INH ; 3 + + inx ; point to next register ; 2 + cpx #14 ; if 14 we're done ; 2 + bmi mb_write_loop ; otherwise, loop ; 3/2nt + ;============ + ; roughly 95? + ; *13= 1235? +skip_r13: + + inc MB_FRAME_DIFF ; increment offset ; 5 + bne reset_chunk ; if not zero, done ; 3/2nt + +wraparound: + + inc MB_CHUNK ; go to next chunk ; 5 + lda MB_CHUNK ; 3 + cmp #CHUNKSIZE ; have we reached end? ; 2 + bne reset_chunk ; 3/2nt + lda #0 ; if so reset ; 2 + sta MB_CHUNK ; 3 + + ; can't tail call as need to restore stack and rti + jsr next_subsong ; and decompress next ; 6 + + +reset_chunk: + lda MB_CHUNK ; reset input pointer ; 3 + clc ; to the beginning ; 2 + + adc #>UNPACK_BUFFER ; in proper chunk (1 of 3) ; 2 + sta INH ; 3 + + + ;============ + ; 18 +done_interrupt: + pla ; restore a ; 4 + + rti ; return from interrupt ; 6 + + ;============ + ; typical + ; 1358 cycles +