From b90eb5877eb60d1ec3e251edef8a74e38fb13fa6 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Mon, 5 Feb 2018 14:39:03 -0500 Subject: [PATCH] mockingboard: got compressed version working (mostly) --- mockingboard/Makefile | 21 ++- mockingboard/ksp_theme_compressed.inc | 3 +- mockingboard/ksp_theme_compressed.s | 164 +++++++++++++--------- mockingboard/ksp_theme_interrupt.s | 188 ++++++++++++++++++++++++++ mockingboard/mock_test.dsk | Bin 143360 -> 143360 bytes mockingboard/zp.inc | 3 +- 6 files changed, 314 insertions(+), 65 deletions(-) create mode 100644 mockingboard/ksp_theme_interrupt.s diff --git a/mockingboard/Makefile b/mockingboard/Makefile index e1fb0d4d..0b952057 100644 --- a/mockingboard/Makefile +++ b/mockingboard/Makefile @@ -3,11 +3,13 @@ include ../Makefile.inc DOS33 = ../dos33fs-utils/dos33 PNG2GR = ../gr-utils/png2gr -all: dump_ed mock.dsk +all: dump_ed mock.dsk lzss_compress -mock.dsk: KSP_THEME_UNCOMPRESSED KSP_THEME_COMPRESSED +mock.dsk: KSP_THEME_UNCOMPRESSED KSP_THEME_COMPRESSED \ + KSP_THEME_INTERRUPT $(DOS33) -y mock_test.dsk BSAVE -a 0x1000 KSP_THEME_UNCOMPRESSED $(DOS33) -y mock_test.dsk BSAVE -a 0x1000 KSP_THEME_COMPRESSED + $(DOS33) -y mock_test.dsk BSAVE -a 0x1000 KSP_THEME_INTERRUPT KSP_THEME_COMPRESSED: ksp_theme_compressed.o ld65 -o KSP_THEME_COMPRESSED ksp_theme_compressed.o -C ./apple2_1000.inc @@ -17,6 +19,15 @@ ksp_theme_compressed.o: ksp_theme_compressed.s \ ksp_theme_compressed.inc ca65 -o ksp_theme_compressed.o ksp_theme_compressed.s -l ksp_theme_compressed.lst +KSP_THEME_INTERRUPT: ksp_theme_interrupt.o + ld65 -o KSP_THEME_INTERRUPT ksp_theme_interrupt.o -C ./apple2_1000.inc + +ksp_theme_interrupt.o: ksp_theme_interrupt.s \ + ../asm_routines/mockingboard.s \ + ksp_title.inc + ca65 -o ksp_theme_interrupt.o ksp_theme_interrupt.s -l ksp_theme_interrupt.lst + + KSP_THEME_UNCOMPRESSED: ksp_theme_uncompressed.o ld65 -o KSP_THEME_UNCOMPRESSED ksp_theme_uncompressed.o -C ./apple2_1000.inc @@ -40,6 +51,12 @@ dump_ed: dump_ed.o notes.o $(CC) $(LFLAGS) -o dump_ed dump_ed.o notes.o +lzss_compress.o: lzss_compress.c + $(CC) $(CFLAGS) -c lzss_compress.c + +lzss_compress: lzss_compress.o + $(CC) $(LFLAGS) -o lzss_compress lzss_compress.o + clean: rm -f *~ TITLE.GR *.o *.lst ED KSP_THEME_UNCOMPRESSED dump_ed diff --git a/mockingboard/ksp_theme_compressed.inc b/mockingboard/ksp_theme_compressed.inc index 27fa1126..a1a744d4 100644 --- a/mockingboard/ksp_theme_compressed.inc +++ b/mockingboard/ksp_theme_compressed.inc @@ -7,7 +7,7 @@ ksptheme: ; Author name: Felipe Falanghe ; Comment: Tracked by Vince Weaver -.byte $00,$80,$38,$00 ; 00000 +.byte $01,$80,$38,$00 ; 00000 .byte $60,$35,$BD,$EE,$DD,$01,$07,$0D,$0D,$0D ; 00096 .byte $01,$00,$07,$0E,$0E,$0E ; 00097 .byte $01,$00,$07,$0F,$0F,$0F ; 00098 @@ -939,5 +939,6 @@ ksptheme: .byte $01,$00,$01,$09 ; 04035 .byte $08,$00,$01,$08 ; 04043 .byte $01,$01,$00,$01,$00 ; 04044 +.byte $ff ; Raw size = 57792 bytes ; Updated size = 4800 bytes diff --git a/mockingboard/ksp_theme_compressed.s b/mockingboard/ksp_theme_compressed.s index 853ba0e2..c040eb66 100644 --- a/mockingboard/ksp_theme_compressed.s +++ b/mockingboard/ksp_theme_compressed.s @@ -20,6 +20,27 @@ sta OUTH jsr move_and_print + jsr mockingboard_detect_slot4 + cpx #$1 + beq mockingboard_found + + lda #not_message + sta OUTH + inc CV + jsr move_and_print + + jmp forever_loop + +mockingboard_found: + lda #found_message + sta OUTH + inc CV + jsr move_and_print + ;============================ ; Init the Mockingboard ;============================ @@ -40,8 +61,8 @@ lda #>ksptheme sta INH - ldy #0 new_frame: + ldy #0 lda (INL),Y ; read in frame delay cmp #$ff ; see if end beq done_play ; if so, done @@ -49,90 +70,96 @@ new_frame: tax old_frame: dex ; decrement the frame diff - bpl delay_a_bit ; if not there yet, delay + beq bottom_regs ; if not there yet, delay + jsr delay_50Hz + jmp old_frame -top_regs: +bottom_regs: iny - lda (INL),Y ; load low reg bitmask - ldx #$ff -top_regs_loop: - inx - cmp #$8 - beq bottom_regs - ror - bcc top_regs_loop + lda (INL),Y ; load low reg bitmask + sta MASK + ldx #$ff ; init to -1 +bottom_regs_loop: + inx ; increment X + cpx #$8 ; if we reach 8, done + beq top_regs ; move on to top - stx XX - sty YY + ror MASK + bcc bottom_regs_loop ; if bit not set in mask, skip reg - iny - lda (INL),Y ; read in value - tax + stx XX ; save X - ldy XX + iny ; get next output value + lda (INL),Y ; read in value + + sty YY ; save Y + + tax ; value in X + ldy XX ; register# in Y ; reg in Y, value in X - jsr write_ay_left ; assume 3 channel (not six) - jsr write_ay_right ; so write same to both left/write + jsr write_ay_left ; assume 3 channel (not six) + jsr write_ay_right ; so write same to both left/write + + ldx XX ; restore X + ldy YY ; restore Y + + jmp bottom_regs_loop ; loop + +top_regs: + iny ; point to next value + lda (INL),Y ; load top reg bitmask + sta MASK + ldx #$7 ; load X as 7 (we increment first) +top_regs_loop: + inx ; increment + cpx #$16 + beq done_with_masks ; exit if done + + ror MASK + bcc top_regs_loop ; loop if not set + + stx XX ; save X value + + iny ; point to value + lda (INL),Y ; read in output value + + sty YY ; save Y value + + tax ; value in X + ldy XX ; register in Y + + ; reg in Y, value in X + jsr write_ay_left ; assume 3 channel (not six) + jsr write_ay_right ; so write same to both left/write ldx XX ldy YY jmp top_regs_loop -bottom_regs: +done_with_masks: iny - lda (INL),Y ; load low reg bitmask - ldx #$ff -bottom_regs_loop: - inx - cmp #$8 - beq delay_a_bit - ror - bcc bottom_regs_loop + clc + tya + adc INL + sta INL + lda #0 + adc INH + sta INH + jsr delay_50Hz - stx XX - sty YY + jmp new_frame - iny - lda (INL),Y ; read in value - tax - - ldy XX - - ; reg in Y, value in X - jsr write_ay_left ; assume 3 channel (not six) - jsr write_ay_right ; so write same to both left/write - - ldx XX - ldy YY - - jmp bottom_regs_loop - - ; reg in Y, value in X - jsr write_ay_left ; assume 3 channel (not six) - jsr write_ay_right ; so write same to both left/write - -delay_a_bit: - - lda #86 - jsr WAIT ; delay 1/2(26+27A+5A^2) us - ; 50Hz = 20ms = 20000us - ; 40000 = 26+27A+5A^2 - ; 5a^2+27a-39974 = 0 - ; A = 86.75 - - jmp old_frame done_play: jsr clear_ay_left jsr clear_ay_right - lda #0 sta CH - lda #2 + lda #3 sta CV lda #mocking_message + sta OUTH + jsr move_and_print + + jsr mockingboard_detect_slot4 + cpx #$1 + beq mockingboard_found + + lda #not_message + sta OUTH + inc CV + jsr move_and_print + + jmp forever_loop + +mockingboard_found: + + lda #found_message + sta OUTH + inc CV + jsr move_and_print + + + ;============================ + ; Init the Mockingboard + ;============================ + + jsr mockingboard_init + jsr reset_ay_left + jsr reset_ay_right + jsr clear_ay_left + jsr clear_ay_right + + + ;=========================== + ; load pointer to the music + ;=========================== + + lda #ksptheme + sta INH + + ldy #0 +new_frame: + lda (INL),Y ; read in frame delay + cmp #$ff ; see if end + beq done_play ; if so, done + + tax +old_frame: + dex ; decrement the frame diff + bpl delay_a_bit ; if not there yet, delay + +top_regs: + iny + lda (INL),Y ; load low reg bitmask + ldx #$ff +top_regs_loop: + inx + cmp #$8 + beq bottom_regs + ror + bcc top_regs_loop + + stx XX + sty YY + + iny + lda (INL),Y ; read in value + tax + + ldy XX + + ; reg in Y, value in X + jsr write_ay_left ; assume 3 channel (not six) + jsr write_ay_right ; so write same to both left/write + + ldx XX + ldy YY + + jmp top_regs_loop + +bottom_regs: + iny + lda (INL),Y ; load low reg bitmask + ldx #$ff +bottom_regs_loop: + inx + cmp #$8 + beq delay_a_bit + ror + bcc bottom_regs_loop + + + stx XX + sty YY + + iny + lda (INL),Y ; read in value + tax + + ldy XX + + ; reg in Y, value in X + jsr write_ay_left ; assume 3 channel (not six) + jsr write_ay_right ; so write same to both left/write + + ldx XX + ldy YY + + jmp bottom_regs_loop + + ; reg in Y, value in X + jsr write_ay_left ; assume 3 channel (not six) + jsr write_ay_right ; so write same to both left/write + +delay_a_bit: + + lda #86 + jsr WAIT ; delay 1/2(26+27A+5A^2) us + ; 50Hz = 20ms = 20000us + ; 40000 = 26+27A+5A^2 + ; 5a^2+27a-39974 = 0 + ; A = 86.75 + + jmp old_frame +done_play: + + jsr clear_ay_left + jsr clear_ay_right + + + lda #0 + sta CH + lda #2 + sta CV + lda #done_message + sta OUTH + jsr move_and_print + + +forever_loop: + jmp forever_loop + +;========= +;routines +;========= +.include "../asm_routines/gr_offsets.s" +.include "../asm_routines/text_print.s" +.include "../asm_routines/mockingboard.s" + +;======= +; music +;======= +.include "ksp_theme_compressed.inc" + +;========= +; strings +;========= +mocking_message: .asciiz "LOOKING FOR MOCKINGBOARD IN SLOT #4: " +not_message: .byte "NOT " +found_message: .asciiz "FOUND" +done_message: .asciiz "DONE PLAYING" diff --git a/mockingboard/mock_test.dsk b/mockingboard/mock_test.dsk index a9e7e47691025b71db0fdc2487dbc5b80dbc9ca9..6c040492ddc1d21e7f61d379f99a645bd4919b49 100644 GIT binary patch literal 143360 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

O85h4k<0-~8^ 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 F{{vsY`PBdb delta 1407 zcmds1-Afcv6rVG$>)_7Eok(0K(7U#h)~?zjLaeZE7(uvD`9Xxz_OPT6fkC|`yHS%p ztiD|8`Vwt!LX#=VKtmR^LZX(kWxl&gkGb?g(8t;|ilPto4|reBIT!Bvo!{?wxUmcu z%W&gROB&O~#Ge-FeK&NGSLwrKw3gF_@t~yp>Xt$GPPs(lYl@K23C?)&2JT86vvr8v zdx*`q5x(^ifx@aN3PkK7{Wf{1D+)gx8SPqvkYO zT_0i+%tY=9owTZmp9fH0atchIkJLL6eO?p8`Z_0`KikTc>|E1&;Fk*r!3#+9^Y04jtA zS+l8GYtk+?8`h^*;sUvHw9)7fKuRJjBQay)8^o;4pE87x&?qI}*MkvS0+95x9RV=< zUqebHuA3R%8(YpNs4zr2%TObg=7w%yRqCK4hEq@DlXGzti6SivM~<^KJ#?e*G;0eS|(5gJColjuReB`$B6))SG% z46Q8#7i$)5#8Q#J#F&h2X>MtLdTeHq+$bq>D0aq_*!lE_=|#Fy3QlU2!72TC-G$Am z_-EAsELk0i8VgO9!HykNhCFCJ#uf>b?*tE9Y@_^D@YtLVCr|k}csM0bu_^hAeUG_n zOudA7=e}J!FbXKFl1KTZrNe