From 3fc491c3aa8eb1704631af215dcc82126e47d1e0 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 15 Aug 2023 12:53:05 -0400 Subject: [PATCH] second: sigh --- demos/second/Makefile | 129 ++ demos/second/README | 6 + demos/second/generate_common | Bin 0 -> 16720 bytes demos/second/gr_fast_clear.s | 201 ++ demos/second/gr_offsets.s | 5 + demos/second/graphics/Makefile | 32 + demos/second/graphics/fc_sr_logo.hgr | Bin 0 -> 8192 bytes demos/second/graphics/final3.hgr | Bin 0 -> 8192 bytes demos/second/graphics/icekngdm.hgr | Bin 0 -> 8192 bytes demos/second/graphics/mntscrl3.hgr | Bin 0 -> 8192 bytes demos/second/hardware.inc | 92 + demos/second/interrupt_handler.s | 69 + demos/second/lc_detect.s | 40 + demos/second/music.s | 31 + demos/second/music/z00m_unreal2_part1.pt3 | Bin 0 -> 4169 bytes demos/second/music/z00m_unreal2_part2.pt3 | Bin 0 -> 4909 bytes demos/second/pt3_lib_core.s | 1993 ++++++++++++++++++++ demos/second/pt3_lib_detect_model.s | 63 + demos/second/pt3_lib_init.s | 575 ++++++ demos/second/pt3_lib_irq_handler.s | 116 ++ demos/second/pt3_lib_mockingboard.inc | 54 + demos/second/pt3_lib_mockingboard_detect.s | 222 +++ demos/second/pt3_lib_mockingboard_patch.s | 120 ++ demos/second/pt3_lib_mockingboard_setup.s | 261 +++ demos/second/qboot_sector.s | 244 +++ demos/second/qboot_stage2.s | 382 ++++ demos/second/qload.s | 194 ++ demos/second/second.s | 358 ++++ demos/second/text_print.s | 93 + demos/second/title.s | 44 + demos/second/wait.s | 18 + demos/second/wait_a_bit.s | 37 + demos/second/wait_keypress.s | 5 + demos/second/zp.inc | 187 ++ demos/second/zx02_optim.s | 159 ++ 35 files changed, 5730 insertions(+) create mode 100644 demos/second/Makefile create mode 100644 demos/second/README create mode 100755 demos/second/generate_common create mode 100644 demos/second/gr_fast_clear.s create mode 100644 demos/second/gr_offsets.s create mode 100644 demos/second/graphics/Makefile create mode 100644 demos/second/graphics/fc_sr_logo.hgr create mode 100644 demos/second/graphics/final3.hgr create mode 100644 demos/second/graphics/icekngdm.hgr create mode 100644 demos/second/graphics/mntscrl3.hgr create mode 100644 demos/second/hardware.inc create mode 100644 demos/second/interrupt_handler.s create mode 100644 demos/second/lc_detect.s create mode 100644 demos/second/music.s create mode 100644 demos/second/music/z00m_unreal2_part1.pt3 create mode 100644 demos/second/music/z00m_unreal2_part2.pt3 create mode 100644 demos/second/pt3_lib_core.s create mode 100644 demos/second/pt3_lib_detect_model.s create mode 100644 demos/second/pt3_lib_init.s create mode 100644 demos/second/pt3_lib_irq_handler.s create mode 100644 demos/second/pt3_lib_mockingboard.inc create mode 100644 demos/second/pt3_lib_mockingboard_detect.s create mode 100644 demos/second/pt3_lib_mockingboard_patch.s create mode 100644 demos/second/pt3_lib_mockingboard_setup.s create mode 100644 demos/second/qboot_sector.s create mode 100644 demos/second/qboot_stage2.s create mode 100644 demos/second/qload.s create mode 100644 demos/second/second.s create mode 100644 demos/second/text_print.s create mode 100644 demos/second/title.s create mode 100644 demos/second/wait.s create mode 100644 demos/second/wait_a_bit.s create mode 100644 demos/second/wait_keypress.s create mode 100644 demos/second/zp.inc create mode 100644 demos/second/zx02_optim.s diff --git a/demos/second/Makefile b/demos/second/Makefile new file mode 100644 index 00000000..a668fb2a --- /dev/null +++ b/demos/second/Makefile @@ -0,0 +1,129 @@ +include ../../Makefile.inc + +DOS33 = ../../utils/dos33fs-utils/dos33 +DOS33_RAW = ../../utils/dos33fs-utils/dos33_raw +EMPTY_DISK = ../../empty_disk/empty.dsk +TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft +LINKER_SCRIPTS = ../../linker_scripts/ + +all: second.dsk + +#second.dsk: HELLO ZW +# cp $(EMPTY_DISK) second.dsk +# $(DOS33) -y second.dsk SAVE A HELLO +# $(DOS33) -y second.dsk BSAVE -a 0x6000 ZW + +second.dsk: QBOOT QLOAD SECOND MUSIC + cp $(EMPTY_DISK) second.dsk + $(DOS33_RAW) second.dsk 0 0 QBOOT 0 1 + $(DOS33_RAW) second.dsk 0 2 QBOOT 1 1 + $(DOS33_RAW) second.dsk 0 4 QBOOT 2 1 + $(DOS33_RAW) second.dsk 1 0 QLOAD 0 0 + $(DOS33_RAW) second.dsk 3 0 MUSIC 0 0 + $(DOS33_RAW) second.dsk 5 0 SECOND 0 0 + +#### + +QBOOT: qboot_sector.o + ld65 -o QBOOT qboot_sector.o -C $(LINKER_SCRIPTS)/apple2_800.inc + +qboot_sector.o: qboot_sector.s qboot_stage2.s + ca65 -o qboot_sector.o qboot_sector.s -l qboot_sector.lst + + +#### + +QLOAD: qload.o + ld65 -o QLOAD qload.o -C $(LINKER_SCRIPTS)/apple2_1200.inc + +qload.o: qload.s \ + gr_offsets.s \ + wait.s wait_a_bit.s \ + lc_detect.s gr_fast_clear.s \ + text_print.s \ + pt3_lib_detect_model.s pt3_lib_mockingboard_detect.s \ + pt3_lib_mockingboard_setup.s interrupt_handler.s \ + pt3_lib_mockingboard_patch.s +# hgr.inc simple_sounds.s \ +# audio.s decompress_fast_v2.s +# hgr_hlin.s hgr_vlin.s hgr_box.s hgr_tables.s hgr_14x14_sprite.s \ +# hgr_sprite.s hgr_partial_restore.s + ca65 -o qload.o qload.s -l qload.lst + +#### + +SECOND: second.o + ld65 -o SECOND second.o -C ../../linker_scripts/apple2_6000.inc + +second.o: second.s zx02_optim.s \ + text_print.s title.s \ + graphics/icekngdm.hgr.zx02 \ + graphics/final3.hgr.zx02 \ + graphics/mntscrl3.hgr.zx02 \ + zp.inc hardware.inc qload.inc music.inc + ca65 -o second.o second.s -l second.lst + +#### + +qload.inc: generate_common QLOAD + ./generate_common -a 0x1200 -s load_file qload.lst > qload.inc + ./generate_common -a 0x1200 -s detect_appleii_model qload.lst >> qload.inc + ./generate_common -a 0x1200 -s clear_all qload.lst >> qload.inc + ./generate_common -a 0x1200 -s set_normal qload.lst >> qload.inc + ./generate_common -a 0x1200 -s set_inverse qload.lst >> qload.inc + ./generate_common -a 0x1200 -s wait qload.lst >> qload.inc + ./generate_common -a 0x1200 -s wait_a_bit qload.lst >> qload.inc + ./generate_common -a 0x1200 -s move_and_print qload.lst >> qload.inc + ./generate_common -a 0x1200 -s detect_language_card qload.lst >> qload.inc + ./generate_common -a 0x1200 -s mockingboard_detect qload.lst >> qload.inc + ./generate_common -a 0x1200 -s clear_bottom qload.lst >> qload.inc + +# ./generate_common -a 0x1200 -s mockingboard_patch qload.lst >> qload.inc +# ./generate_common -a 0x1200 -s mockingboard_init qload.lst >> qload.inc +# ./generate_common -a 0x1200 -s mockingboard_setup_interrupt qload.lst >> qload.inc +# ./generate_common -a 0x1200 -s disable_music qload.lst >> qload.inc +# ./generate_common -a 0x1200 -s reset_ay_both qload.lst >> qload.inc +# ./generate_common -a 0x1200 -s clear_ay_both qload.lst >> qload.inc + +#### + +music.inc: generate_common MUSIC + ./generate_common -a 0xd000 -s pt3_init_song music.lst > music.inc + ./generate_common -a 0xd000 -s mockingboard_init music.lst >> music.inc + ./generate_common -a 0xd000 -s reset_ay_both music.lst >> music.inc + ./generate_common -a 0xd000 -s clear_ay_both music.lst >> music.inc + ./generate_common -a 0xd000 -s mockingboard_setup_interrupt music.lst >> music.inc + ./generate_common -a 0xd000 -s mockingboard_disable_interrupt music.lst >> music.inc + ./generate_common -a 0xd000 -s done_pt3_irq_handler music.lst >> music.inc + ./generate_common -a 0xd000 -s PT3_LOC music.lst >> music.inc + +#### + +MUSIC: music.o + ld65 -o MUSIC music.o -C $(LINKER_SCRIPTS)/apple2_d000.inc + +music.o: music.s zp.inc \ + music/z00m_unreal2_part1.pt3 \ + pt3_lib_core.s \ + pt3_lib_mockingboard_detect.s \ + pt3_lib_mockingboard.inc \ + pt3_lib_init.s \ + pt3_lib_mockingboard_setup.s \ + pt3_lib_irq_handler.s + ca65 -o music.o music.s -l music.lst + + + + + +generate_common: generate_common.o + $(CC) $(LFLAGS) -o generate_common generate_common.o + +generate_common.o: generate_common.c + $(CC) $(CFLAGS) -c generate_common.c + +### + + +clean: + rm -f *~ *.o *.lst HELLO SECOND QBOOT QLOAD MUSIC diff --git a/demos/second/README b/demos/second/README new file mode 100644 index 00000000..5c4145d4 --- /dev/null +++ b/demos/second/README @@ -0,0 +1,6 @@ +Second Reality demo for Apple II proof of concept + +no I really don't think I'm going to do this whole thing, +I found a pt3 version of the music and was messing around +with Kris Kennaway's conversion tool + https://github.com/KrisKennaway/ii-pix diff --git a/demos/second/generate_common b/demos/second/generate_common new file mode 100755 index 0000000000000000000000000000000000000000..82fdf4aff345e53fbc0a34b3060e8b2aa647cebb GIT binary patch literal 16720 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 Fe*#Y0x19h0 literal 0 HcmV?d00001 diff --git a/demos/second/gr_fast_clear.s b/demos/second/gr_fast_clear.s new file mode 100644 index 00000000..76035a21 --- /dev/null +++ b/demos/second/gr_fast_clear.s @@ -0,0 +1,201 @@ +;clear_screens: +; ;=================================== +; ; Clear top/bottom of page 0 +; ;=================================== +; +; lda #$0 +; sta DRAW_PAGE +; jsr clear_top +; jsr clear_bottom + +; ;=================================== +; ; Clear top/bottom of page 1 +; ;=================================== +; +; lda #$4 +; sta DRAW_PAGE +; jsr clear_top +; jsr clear_bottom +; +; rts + + + + + ;========================================================= + ; clear_top + ;========================================================= + ; clear DRAW_PAGE + ; original = 14,558 cycles(?) 15ms, 70Hz + ; OPTIMIZED MAX (page0,48rows): 45*120+4+6 = 5410 = 5.4ms 185Hz + ; (pageX,40rows): 50*120+4+6 = 6010 = 6.0ms 166Hz + ; 50*120+4+6+37 = 6055 = 6.0ms 166Hz +clear_top: + lda #0 ; 2 +clear_top_a: + sta COLOR ; 3 + clc ; 2 + lda DRAW_PAGE ; 3 + + adc #4 ; 2 + sta __ctf+2 ; 3 + sta __ctf+5 ; 3 + adc #1 ; 2 + sta __ctf+8 ; 3 + sta __ctf+11 ; 3 + adc #1 ; 2 + sta __ctf2+2 ; 3 + sta __ctf2+5 ; 3 + adc #1 ; 2 + sta __ctf2+8 ; 3 + sta __ctf2+11 ; 3 + + + ldy #120 ; 2 + lda COLOR ; 3 +clear_top_fast_loop: +__ctf: + sta $400,Y ; 5 + sta $480,Y ; 5 + sta $500,Y ; 5 + sta $580,Y ; 5 + + cpy #80 ; 2 + bpl no_draw_bottom ; 2nt/3 +__ctf2: + sta $600,Y ; 5 + sta $680,Y ; 5 + sta $700,Y ; 5 + sta $780,Y ; 5 +no_draw_bottom: + + dey ; 2 + bpl clear_top_fast_loop ; 2nt/3 + + rts ; 6 + + + + + ;========================================================= + ; clear_bottom + ;========================================================= + ; clear bottom of draw page + +clear_bottom: + clc ; 2 + lda DRAW_PAGE ; 3 + + adc #6 ; 2 + sta __cbf2+2 ; 3 + sta __cbf2+5 ; 3 + adc #1 ; 2 + sta __cbf2+8 ; 3 + sta __cbf2+11 ; 3 + + + ldy #120 ; 2 + lda #$a0 ; Normal Space ; 2 +clear_bottom_fast_loop: +__cbf2: + sta $600,Y ; 5 + sta $680,Y ; 5 + sta $700,Y ; 5 + sta $780,Y ; 5 + + dey ; 2 + cpy #80 ; 2 + bpl clear_bottom_fast_loop ; 2nt/3 + + rts ; 6 + + +;clear_screens_notext: + ;=================================== + ; Clear top/bottom of page 0 + ;=================================== + +; lda #$0 +; sta DRAW_PAGE +; jsr clear_all + + ;=================================== + ; Clear top/bottom of page 1 + ;=================================== + +; lda #$4 +; sta DRAW_PAGE +; jsr clear_all + +; rts + + +clear_bottoms: + + lda DRAW_PAGE + pha + + ;=================================== + ; Clear bottom of page 0 + ;=================================== + + lda #$0 + sta DRAW_PAGE + jsr clear_bottom + + ;=================================== + ; Clear bottom of page 1 + ;=================================== + + lda #$4 + sta DRAW_PAGE + jsr clear_bottom + + pla + sta DRAW_PAGE + + rts + + + ;========================================================= + ; clear_all + ;========================================================= + ; clear 48 rows + +clear_all: + clc ; 2 + lda DRAW_PAGE ; 3 + + adc #4 ; 2 + sta __caf+2 ; 3 + sta __caf+5 ; 3 + adc #1 ; 2 + sta __caf+8 ; 3 + sta __caf+11 ; 3 + adc #1 ; 2 + sta __caf2+2 ; 3 + sta __caf2+5 ; 3 + adc #1 ; 2 + sta __caf2+8 ; 3 + sta __caf2+11 ; 3 + + + ldy #120 ; 2 +clear_all_color: + lda #' '|$80 ; 2 +clear_all_fast_loop: +__caf: + sta $400,Y ; 5 + sta $480,Y ; 5 + sta $500,Y ; 5 + sta $580,Y ; 5 +__caf2: + sta $600,Y ; 5 + sta $680,Y ; 5 + sta $700,Y ; 5 + sta $780,Y ; 5 + + dey ; 2 + bpl clear_all_fast_loop ; 2nt/3 + + rts ; 6 diff --git a/demos/second/gr_offsets.s b/demos/second/gr_offsets.s new file mode 100644 index 00000000..d3af91f7 --- /dev/null +++ b/demos/second/gr_offsets.s @@ -0,0 +1,5 @@ +gr_offsets: + .word $400,$480,$500,$580,$600,$680,$700,$780 + .word $428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8 + .word $450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0 + diff --git a/demos/second/graphics/Makefile b/demos/second/graphics/Makefile new file mode 100644 index 00000000..5357c5a8 --- /dev/null +++ b/demos/second/graphics/Makefile @@ -0,0 +1,32 @@ +include ../../../Makefile.inc + +ZX02 = ~/research/6502_compression/zx02.git/build/zx02 +PNG_TO_HGR = ../../../utils/hgr-utils/png2hgr + +all: icekngdm.hgr.zx02 mntscrl3.hgr.zx02 final3.hgr.zx02 fc_sr_logo.hgr.zx02 + +#### + +icekngdm.hgr.zx02: icekngdm.hgr + $(ZX02) icekngdm.hgr icekngdm.hgr.zx02 + +#### + +mntscrl3.hgr.zx02: mntscrl3.hgr + $(ZX02) mntscrl3.hgr mntscrl3.hgr.zx02 + +#### + +final3.hgr.zx02: final3.hgr + $(ZX02) final3.hgr final3.hgr.zx02 + +#### + +fc_sr_logo.hgr.zx02: fc_sr_logo.hgr + $(ZX02) fc_sr_logo.hgr fc_sr_logo.hgr.zx02 + + +#### + +clean: + rm -f *~ diff --git a/demos/second/graphics/fc_sr_logo.hgr b/demos/second/graphics/fc_sr_logo.hgr new file mode 100644 index 0000000000000000000000000000000000000000..e019426cb9fe6d17fe08a466a8442d23ff3898a5 GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/demos/second/graphics/final3.hgr b/demos/second/graphics/final3.hgr new file mode 100644 index 0000000000000000000000000000000000000000..7538c4ae8e5ec7a59f9c8d5453dcb3d509ff075d GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/demos/second/graphics/icekngdm.hgr b/demos/second/graphics/icekngdm.hgr new file mode 100644 index 0000000000000000000000000000000000000000..5b80a73dfbdd047e74313f888c82367ac907d237 GIT binary patch literal 8192 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 P7({LzALOUW?-c(Bx^~SQ literal 0 HcmV?d00001 diff --git a/demos/second/graphics/mntscrl3.hgr b/demos/second/graphics/mntscrl3.hgr new file mode 100644 index 0000000000000000000000000000000000000000..79c6c584b5f54dc011b697133c6a995615e07e82 GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/demos/second/music/z00m_unreal2_part2.pt3 b/demos/second/music/z00m_unreal2_part2.pt3 new file mode 100644 index 0000000000000000000000000000000000000000..553d018b76e7c47e06c070356e6f2ed1013e3d8b GIT binary patch literal 4909 zcmcH-ZERat_1@=~7dv@zQafc`=2b3KFb!d>W>hMwl&}aowPNj9VdD+s#Z8=f`EcYo z9xqOx-_6UjLtzC8e(_`bF~P>4X;-5aFoDuGO=HKgpB5>}27>Yji62N-nJ5fcIrlv~ zc}bj<5O})h+;i?dIbZkdIOh`a^NHRIgZ&AAXW(=G3-RI6*idgW79a7)qyE5GM-u(L zLxIq9fu~3NFI;qn( zDdYD(vQ5?@xLl&x+UhxY@X#R!4;?;o^ysI~pMUf-&jf=K>g+szyz|7#uE!t$;uB|{ zeCpm;nt#&#X!F~+fN$gDT#UQI{R?o=@h!(IjvoWQ;`oIl?^t%c5A>fMUj7^W6z}EV z;6LEM-VkrN((thGgm77SSNKF@tZ}~a0q1FF#_4zc32@SN)#Ye<-FelOasI6NkIka^ zHE~81MMl3VR>YGnPqidlehGNF<&b;a{kHpW?#rzVueSQz`rH1|#_;I_uN`>jz()sO zcQT!yZX!*Nrq!kg!RLyptfdQ*|-$t_h`kn^OVDvNSaBTH&Y*2+YcwJPWuk#_@h$5*6WG@6KxQa%v{GC_Ih z7*}sRksL=AKm19Y^6@c`GG-Hx{@PKd-3qFR5HFW<(9fr!OCj1l zYmGTmj+FJGicqG`Bz)!{`E7sHky@oV4IelUM$NbeBSSm&>(}jtQaRpN1;uOj$UMKf-#$T%c)Q(78-~>|Kd(P=z_hVlY*iz5~Zk< zC5@C6*tCj9Gzy<3)b%!bLi_rGyGR51{ zW(8(*yl&?2H;?WfhV&4XHj@&?Mp-QwW&9HU@Lo4{%WUKn+)`8^l-DSy7ql{_)#*n0 z6y+x1GUkn&#+-4(xNcmd4r5cyaGgbl*`)?; zI5NnNc{pa`!SLwF9%AO;lqq_VD2wK~%M)cmC$|)Ro+vkUGNM+;HS}C?p0}^XBzE?s%bfmqz43Esal#|~76*^KS3$%@~eu@WXVKmCn zb}8B}Ro!F9o!x47%=oQiwfX%T7Nym<;LS=G;N`*$1AtDS8B7d<34!-M%9|tv!`O!? zei7pE#Tcqi*`#QD$QBH{l~>ty3s-X?w^n9%wK)Q$71T}=a82iPxgxu!*&4(g?CuQ> zRBcQLdY-xu1i+hXXqZ^41(U%(#3&a$geh{8}Sd%bq51X&3Gf@#}8@#FTvZ6aYOOpg!b<-DuFAQI8aKEO-aGf1PowGJi z{=%v+Rw`ujN-?A4Gew2biDCvyi8`aiyuvv9^;h?h)yj;uBWPB=5ic=&%RV0iaFHU9Zj!s)1!v5QR3;uT=7Srjabh?y=(}(V| zIzmwkL|;_YBGH!=wM6u?q7oe-yBRd#?O@6Bv7{m1tk@s zo_s#c9#2l9P15fv|19_bmqAU7t>2q<$OYIdP$9Kkwl-NK-v2?^34-a$Pe4(Y2KA6pZ-noWDp zXn9h}Xm&sys7LH(2RbD%wR{S&J=7dnI|C2Svn!@mHoYb4`Vw{2oC7t_fSNO4jA3T$ z%vM{b5UYQn0MPJ1q2g)K3zUP3hZR9k95CEA$%b|p$uN;Eir~7K*`f%3aA`|=dEM4_ z5zSHr$tK$LOdXi4j@f%gPiDwe)((*D6IQZiNcIWJ%YY#P^6J7R*iM%Ummt|)kfrA! zODCX+vxM$1QAbS=sF6TTm#L=9wAHm$lPOfqQPxWK3?$$?r^=d{>}iIZGL$Ej(;!pu zYom;J6l|NarF^qg)~@arC|bzC&u(pTx~MIY(r!wdvXq~u+*H9phY{-dQknY4D}E}D zEsV|4#xaV`Ux2o=n6H0Ct>JubJ~x-Uo~HclZTQ!~*gS19Rj{IzhgzGfzQ(M)ERAn2 zHJ2!k?NE9ew0YJ=8;v&R4#MOzAnpsT!H)>|j5*v2_iDde8(j;C&fvVDu`Z5$8Z6LL4CB10)_g8iWBa F`ZoxpryT$Q literal 0 HcmV?d00001 diff --git a/demos/second/pt3_lib_core.s b/demos/second/pt3_lib_core.s new file mode 100644 index 00000000..1118b5ae --- /dev/null +++ b/demos/second/pt3_lib_core.s @@ -0,0 +1,1993 @@ +;=========================================== +; Library to decode Vortex Tracker PT3 files +; in 6502 assembly for Apple ][ Mockingboard +; +; by Vince Weaver + +; Roughly based on the Formats.pas Pascal code from Ay_Emul + +; Size Optimization -- Mem+Code (pt3_lib_end-note_a) +; + 3407 bytes -- original working implementation +; + 3302 bytes -- autogenerate the volume tables +; + 3297 bytes -- remove some un-needed bytes from struct +; + 3262 bytes -- combine some duplicated code in $1X/$BX env setting +; + 3253 bytes -- remove unnecessary variable +; + 3203 bytes -- combine common code in note decoder +; + 2937 bytes -- qkumba first pass +; + 2879 bytes -- qkumba second pass +; + 2839 bytes -- mask note command in common code +; + 2832 bytes -- combine $D0 and $E0 decode +; + 2816 bytes -- eliminate "decode_done" variable (2.75k) +; + 2817 bytes -- eliminate pt3_version. Slighly faster but also bigger +; + 2828 bytes -- fix some correctness issues +; + 2776 bytes -- init vars with loop (slower, but more correct and smaller) +; + 2739 bytes -- qkumba's crazy SMC everywhere patch +; + 2418+143 = 2561 bytes -- move NOTE structs to page0 +; + 2423+143 = 2566 bytes -- fix vibrato code +; + 2554+143 = 2697 bytes -- generate all four tone tables +; + 2537+143 = 2680 bytes -- inline GetNoteFreq + +; TODO +; move some of these flags to be bits rather than bytes? +; enabled could be bit 6 or 7 for fast checking +; NOTE_ENABLED,ENVELOPE_ENABLED,SIMPLE_GLISS,ENV_SLIDING,AMP_SLIDING? + +; Header offsets + +PT3_VERSION = $0D +PT3_HEADER_FREQUENCY = $63 +PT3_SPEED = $64 +PT3_LOOP = $66 +PT3_PATTERN_LOC_L = $67 +PT3_PATTERN_LOC_H = $68 +PT3_SAMPLE_LOC_L = $69 +PT3_SAMPLE_LOC_H = $6A +PT3_ORNAMENT_LOC_L = $A9 +PT3_ORNAMENT_LOC_H = $AA +PT3_PATTERN_TABLE = $C9 + +; Use memset to set things to 0? + +NOTE_VOLUME =0 +NOTE_TONE_SLIDING_L =1 +NOTE_TONE_SLIDING_H =2 +NOTE_ENABLED =3 +NOTE_ENVELOPE_ENABLED =4 +NOTE_SAMPLE_POINTER_L =5 +NOTE_SAMPLE_POINTER_H =6 +NOTE_SAMPLE_LOOP =7 +NOTE_SAMPLE_LENGTH =8 +NOTE_TONE_L =9 +NOTE_TONE_H =10 +NOTE_AMPLITUDE =11 +NOTE_NOTE =12 +NOTE_LEN =13 +NOTE_LEN_COUNT =14 +NOTE_ADDR_L =15 +NOTE_ADDR_H =16 +NOTE_ORNAMENT_POINTER_L =17 +NOTE_ORNAMENT_POINTER_H =18 +NOTE_ORNAMENT_LOOP =19 +NOTE_ORNAMENT_LENGTH =20 +NOTE_ONOFF =21 +NOTE_TONE_ACCUMULATOR_L =22 +NOTE_TONE_ACCUMULATOR_H =23 +NOTE_TONE_SLIDE_COUNT =24 +NOTE_ORNAMENT_POSITION =25 +NOTE_SAMPLE_POSITION =26 +NOTE_ENVELOPE_SLIDING =27 +NOTE_NOISE_SLIDING =28 +NOTE_AMPLITUDE_SLIDING =29 +NOTE_ONOFF_DELAY =30 ;ordering of DELAYs is hard-coded now +NOTE_OFFON_DELAY =31 ;ordering of DELAYs is hard-coded now +NOTE_TONE_SLIDE_STEP_L =32 +NOTE_TONE_SLIDE_STEP_H =33 +NOTE_TONE_SLIDE_DELAY =34 +NOTE_SIMPLE_GLISS =35 +NOTE_SLIDE_TO_NOTE =36 +NOTE_TONE_DELTA_L =37 +NOTE_TONE_DELTA_H =38 +NOTE_TONE_SLIDE_TO_STEP =39 + +NOTE_STRUCT_SIZE=40 + +.ifdef PT3_USE_ZERO_PAGE +note_a = $80 +note_b = $80+(NOTE_STRUCT_SIZE*1) +note_c = $80+(NOTE_STRUCT_SIZE*2) + +begin_vars=$80 +end_vars=$80+(NOTE_STRUCT_SIZE*3) + + +.else ; !PT3_USE_ZERO_PAGE +begin_vars: + +note_a: ; reset? + + .byte $0 ; NOTE_VOLUME ; 0 ; Y + .byte $0 ; NOTE_TONE_SLIDING_L ; 1 ; Y + .byte $0 ; NOTE_TONE_SLIDING_H ; 2 ; Y + .byte $0 ; NOTE_ENABLED ; 3 ; Y + .byte $0 ; NOTE_ENVELOPE_ENABLED ; 4 ; Y + .byte $0 ; NOTE_SAMPLE_POINTER_L ; 5 ; Y + .byte $0 ; NOTE_SAMPLE_POINTER_H ; 6 ; Y + .byte $0 ; NOTE_SAMPLE_LOOP ; 7 ; Y + .byte $0 ; NOTE_SAMPLE_LENGTH ; 8 ; Y + .byte $0 ; NOTE_TONE_L ; 9 + .byte $0 ; NOTE_TONE_H ; 10 + .byte $0 ; NOTE_AMPLITUDE ; 11 + .byte $0 ; NOTE_NOTE ; 12 + .byte $0 ; NOTE_LEN ; 13 + .byte $0 ; NOTE_LEN_COUNT ; 14 + .byte $0 ; NOTE_ADDR_L ; 15 + .byte $0 ; NOTE_ADDR_H ; 16 + .byte $0 ; NOTE_ORNAMENT_POINTER_L ; 17 ; Y + .byte $0 ; NOTE_ORNAMENT_POINTER_H ; 18 ; Y + .byte $0 ; NOTE_ORNAMENT_LOOP ; 19 ; Y + .byte $0 ; NOTE_ORNAMENT_LENGTH ; 20 ; Y + .byte $0 ; NOTE_ONOFF ; 21 + .byte $0 ; NOTE_TONE_ACCUMULATOR_L ; 22 + .byte $0 ; NOTE_TONE_ACCUMULATOR_H ; 23 + .byte $0 ; NOTE_TONE_SLIDE_COUNT ; 24 + .byte $0 ; NOTE_ORNAMENT_POSITION ; 25 ; Y + .byte $0 ; NOTE_SAMPLE_POSITION ; 26 ; Y + .byte $0 ; NOTE_ENVELOPE_SLIDING ; 27 + .byte $0 ; NOTE_NOISE_SLIDING ; 28 + .byte $0 ; NOTE_AMPLITUDE_SLIDING ; 29 + .byte $0 ; NOTE_ONOFF_DELAY ; 30 + .byte $0 ; NOTE_OFFON_DELAY ; 31 + .byte $0 ; NOTE_TONE_SLIDE_STEP_L ; 32 + .byte $0 ; NOTE_TONE_SLIDE_STEP_H ; 33 + .byte $0 ; NOTE_TONE_SLIDE_DELAY ; 34 + .byte $0 ; NOTE_SIMPLE_GLISS ; 35 + .byte $0 ; NOTE_SLIDE_TO_NOTE ; 36 + .byte $0 ; NOTE_TONE_DELTA_L ; 37 + .byte $0 ; NOTE_TONE_DELTA_H ; 38 + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP ; 39 + +note_b: + .byte $0 ; NOTE_VOLUME + .byte $0 ; NOTE_TONE_SLIDING_L + .byte $0 ; NOTE_TONE_SLIDING_H + .byte $0 ; NOTE_ENABLED + .byte $0 ; NOTE_ENVELOPE_ENABLED + .byte $0 ; NOTE_SAMPLE_POINTER_L + .byte $0 ; NOTE_SAMPLE_POINTER_H + .byte $0 ; NOTE_SAMPLE_LOOP + .byte $0 ; NOTE_SAMPLE_LENGTH + .byte $0 ; NOTE_TONE_L + .byte $0 ; NOTE_TONE_H + .byte $0 ; NOTE_AMPLITUDE + .byte $0 ; NOTE_NOTE + .byte $0 ; NOTE_LEN + .byte $0 ; NOTE_LEN_COUNT + .byte $0 ; NOTE_ADDR_L + .byte $0 ; NOTE_ADDR_H + .byte $0 ; NOTE_ORNAMENT_POINTER_L + .byte $0 ; NOTE_ORNAMENT_POINTER_H + .byte $0 ; NOTE_ORNAMENT_LOOP + .byte $0 ; NOTE_ORNAMENT_LENGTH + .byte $0 ; NOTE_ONOFF + .byte $0 ; NOTE_TONE_ACCUMULATOR_L + .byte $0 ; NOTE_TONE_ACCUMULATOR_H + .byte $0 ; NOTE_TONE_SLIDE_COUNT + .byte $0 ; NOTE_ORNAMENT_POSITION + .byte $0 ; NOTE_SAMPLE_POSITION + .byte $0 ; NOTE_ENVELOPE_SLIDING + .byte $0 ; NOTE_NOISE_SLIDING + .byte $0 ; NOTE_AMPLITUDE_SLIDING + .byte $0 ; NOTE_ONOFF_DELAY + .byte $0 ; NOTE_OFFON_DELAY + .byte $0 ; NOTE_TONE_SLIDE_STEP_L + .byte $0 ; NOTE_TONE_SLIDE_STEP_H + .byte $0 ; NOTE_TONE_SLIDE_DELAY + .byte $0 ; NOTE_SIMPLE_GLISS + .byte $0 ; NOTE_SLIDE_TO_NOTE + .byte $0 ; NOTE_TONE_DELTA_L + .byte $0 ; NOTE_TONE_DELTA_H + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP + +note_c: + .byte $0 ; NOTE_VOLUME + .byte $0 ; NOTE_TONE_SLIDING_L + .byte $0 ; NOTE_TONE_SLIDING_H + .byte $0 ; NOTE_ENABLED + .byte $0 ; NOTE_ENVELOPE_ENABLED + .byte $0 ; NOTE_SAMPLE_POINTER_L + .byte $0 ; NOTE_SAMPLE_POINTER_H + .byte $0 ; NOTE_SAMPLE_LOOP + .byte $0 ; NOTE_SAMPLE_LENGTH + .byte $0 ; NOTE_TONE_L + .byte $0 ; NOTE_TONE_H + .byte $0 ; NOTE_AMPLITUDE + .byte $0 ; NOTE_NOTE + .byte $0 ; NOTE_LEN + .byte $0 ; NOTE_LEN_COUNT + .byte $0 ; NOTE_ADDR_L + .byte $0 ; NOTE_ADDR_H + .byte $0 ; NOTE_ORNAMENT_POINTER_L + .byte $0 ; NOTE_ORNAMENT_POINTER_H + .byte $0 ; NOTE_ORNAMENT_LOOP + .byte $0 ; NOTE_ORNAMENT_LENGTH + .byte $0 ; NOTE_ONOFF + .byte $0 ; NOTE_TONE_ACCUMULATOR_L + .byte $0 ; NOTE_TONE_ACCUMULATOR_H + .byte $0 ; NOTE_TONE_SLIDE_COUNT + .byte $0 ; NOTE_ORNAMENT_POSITION + .byte $0 ; NOTE_SAMPLE_POSITION + .byte $0 ; NOTE_ENVELOPE_SLIDING + .byte $0 ; NOTE_NOISE_SLIDING + .byte $0 ; NOTE_AMPLITUDE_SLIDING + .byte $0 ; NOTE_ONOFF_DELAY + .byte $0 ; NOTE_OFFON_DELAY + .byte $0 ; NOTE_TONE_SLIDE_STEP_L + .byte $0 ; NOTE_TONE_SLIDE_STEP_H + .byte $0 ; NOTE_TONE_SLIDE_DELAY + .byte $0 ; NOTE_SIMPLE_GLISS + .byte $0 ; NOTE_SLIDE_TO_NOTE + .byte $0 ; NOTE_TONE_DELTA_L + .byte $0 ; NOTE_TONE_DELTA_H + .byte $0 ; NOTE_TONE_SLIDE_TO_STEP +end_vars: +.endif + +load_ornament0_sample1: + lda #0 ; 2 + jsr load_ornament ; 6 + ; fall through + + ;=========================== + ; Load Sample + ;=========================== + ; sample in A + ; which note offset in X + + ; Sample table pointers are 16-bits little endian + ; There are 32 of these pointers starting at $6a:$69 + ; Our sample starts at address (A*2)+that pointer + ; We point SAMPLE_H:SAMPLE_L to this + ; then we load the length/data values + ; and then leave SAMPLE_H:SAMPLE_L pointing to begnning of + ; the sample data + + ; Optimization: + ; see comments on ornament setting + +load_sample1: + lda #1 ; 2 + +load_sample: + + sty PT3_TEMP ; 3 + + ;pt3->ornament_patterns[i]= + ; (pt3->data[0x6a+(i*2)]<<8)|pt3->data[0x69+(i*2)]; + + asl ; A*2 ; 2 + tay ; 2 + + ; Set the initial sample pointer + ; a->sample_pointer=pt3->sample_patterns[a->sample]; + + lda PT3_LOC+PT3_SAMPLE_LOC_L,Y ; 4+ + sta SAMPLE_L ; 3 + + lda PT3_LOC+PT3_SAMPLE_LOC_L+1,Y ; 4+ + + ; assume pt3 file is at page boundary + adc #>PT3_LOC ; 2 + sta SAMPLE_H ; 3 + + ; Set the loop value + ; a->sample_loop=pt3->data[a->sample_pointer]; + + ldy #0 ; 2 + lda (SAMPLE_L),Y ; 5+ + sta note_a+NOTE_SAMPLE_LOOP,X ; 5 + + ; Set the length value + ; a->sample_length=pt3->data[a->sample_pointer]; + + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + sta note_a+NOTE_SAMPLE_LENGTH,X ; 5 + + ; Set pointer to beginning of samples + + lda SAMPLE_L ; 3 + adc #$2 ; 2 + sta note_a+NOTE_SAMPLE_POINTER_L,X ; 5 + lda SAMPLE_H ; 3 + adc #$0 ; 2 + sta note_a+NOTE_SAMPLE_POINTER_H,X ; 5 + + ldy PT3_TEMP ; 3 + + rts ; 6 + ;============ + ; 76 + + + ;=========================== + ; Load Ornament + ;=========================== + ; ornament value in A + ; note offset in X + + ; Ornament table pointers are 16-bits little endian + ; There are 16 of these pointers starting at $aa:$a9 + ; Our ornament starts at address (A*2)+that pointer + ; We point ORNAMENT_H:ORNAMENT_L to this + ; then we load the length/data values + ; and then leave ORNAMENT_H:ORNAMENT_L pointing to begnning of + ; the ornament data + + ; Optimization: + ; Loop and length only used once, can be located negative + ; from the pointer, but 6502 doesn't make addressing like that + ; easy. Can't self modify as channels A/B/C have own copies + ; of the var. + +load_ornament: + + sty PT3_TEMP ; save Y value ; 3 + + ;pt3->ornament_patterns[i]= + ; (pt3->data[0xaa+(i*2)]<<8)|pt3->data[0xa9+(i*2)]; + + asl ; A*2 ; 2 + tay ; 2 + + ; a->ornament_pointer=pt3->ornament_patterns[a->ornament]; + + lda PT3_LOC+PT3_ORNAMENT_LOC_L,Y ; 4+ + sta ORNAMENT_L ; 3 + + lda PT3_LOC+PT3_ORNAMENT_LOC_L+1,Y ; 4+ + + ; we're assuming PT3 is loaded to a page boundary + + adc #>PT3_LOC ; 2 + sta ORNAMENT_H ; 3 + + lda #0 ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; 5 + + tay ; 2 + + ; Set the loop value + ; a->ornament_loop=pt3->data[a->ornament_pointer]; + lda (ORNAMENT_L),Y ; 5+ + sta note_a+NOTE_ORNAMENT_LOOP,X ; 5 + + ; Set the length value + ; a->ornament_length=pt3->data[a->ornament_pointer]; + iny ; 2 + lda (ORNAMENT_L),Y ; 5+ + sta note_a+NOTE_ORNAMENT_LENGTH,X ; 5 + + ; Set the pointer to the value past the length + + lda ORNAMENT_L ; 3 + adc #$2 ; 2 + sta note_a+NOTE_ORNAMENT_POINTER_L,X ; 5 + lda ORNAMENT_H ; 3 + adc #$0 ; 2 + sta note_a+NOTE_ORNAMENT_POINTER_H,X ; 5 + + ldy PT3_TEMP ; restore Y value ; 3 + + rts ; 6 + + ;============ + ; 83 + + + + ;===================================== + ; Calculate Note + ;===================================== + ; note offset in X + +calculate_note: + + lda note_a+NOTE_ENABLED,X ; 4+ + bne note_enabled ; 2/3 + + sta note_a+NOTE_AMPLITUDE,X ; 5 + jmp done_note ; 3 + +note_enabled: + + lda note_a+NOTE_SAMPLE_POINTER_H,X ; 4+ + sta SAMPLE_H ; 3 + lda note_a+NOTE_SAMPLE_POINTER_L,X ; 4+ + sta SAMPLE_L ; 3 + + lda note_a+NOTE_ORNAMENT_POINTER_H,X ; 4+ + sta ORNAMENT_H ; 3 + lda note_a+NOTE_ORNAMENT_POINTER_L,X ; 4+ + sta ORNAMENT_L ; 3 + + + lda note_a+NOTE_SAMPLE_POSITION,X ; 4+ + asl ; 2 + asl ; 2 + tay ; 2 + + ; b0 = pt3->data[a->sample_pointer + a->sample_position * 4]; + lda (SAMPLE_L),Y ; 5+ + sta sample_b0_smc+1 ; 4 + + ; b1 = pt3->data[a->sample_pointer + a->sample_position * 4 + 1]; + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + sta sample_b1_smc+1 ; 4 + + ; a->tone = pt3->data[a->sample_pointer + a->sample_position*4+2]; + ; a->tone+=(pt3->data[a->sample_pointer + a->sample_position*4+3])<<8; + ; a->tone += a->tone_accumulator; + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + adc note_a+NOTE_TONE_ACCUMULATOR_L,X ; 4+ + sta note_a+NOTE_TONE_L,X ; 4 + + iny ; 2 + lda (SAMPLE_L),Y ; 5+ + adc note_a+NOTE_TONE_ACCUMULATOR_H,X ; 4+ + sta note_a+NOTE_TONE_H,X ; 4 + + ;============================= + ; Accumulate tone if set + ; (if sample_b1 & $40) + + bit sample_b1_smc+1 + bvc no_accum ; (so, if b1&0x40 is zero, skip it) + + sta note_a+NOTE_TONE_ACCUMULATOR_H,X + lda note_a+NOTE_TONE_L,X ; tone_accumulator=tone + sta note_a+NOTE_TONE_ACCUMULATOR_L,X + +no_accum: + + ;============================ + ; Calculate tone + ; j = a->note + (pt3->data[a->ornament_pointer + a->ornament_position] + clc ;;can be removed if ADC ACCUMULATOR_H cannot overflow + ldy note_a+NOTE_ORNAMENT_POSITION,X + lda (ORNAMENT_L),Y + adc note_a+NOTE_NOTE,X + + ; if (j < 0) j = 0; + bpl note_not_negative + lda #0 + + ; if (j > 95) j = 95; +note_not_negative: + cmp #96 + bcc note_not_too_high ; blt + + lda #95 + +note_not_too_high: + + ; w = GetNoteFreq(j,pt3->frequency_table); + + tay ; for GetNoteFreq later + + ; a->tone = (a->tone + a->tone_sliding + w) & 0xfff; + + clc + lda note_a+NOTE_TONE_SLIDING_L,X + adc note_a+NOTE_TONE_L,X + sta temp_word_l1_smc+1 + + lda note_a+NOTE_TONE_H,X + adc note_a+NOTE_TONE_SLIDING_H,X + sta temp_word_h1_smc+1 + + clc ;;can be removed if ADC SLIDING_H cannot overflow +temp_word_l1_smc: + lda #$d1 + adc NoteTable_low,Y ; GetNoteFreq + sta note_a+NOTE_TONE_L,X +temp_word_h1_smc: + lda #$d1 + adc NoteTable_high,Y ; GetNoteFreq + and #$0f + sta note_a+NOTE_TONE_H,X + + ;===================== + ; handle tone sliding + + lda note_a+NOTE_TONE_SLIDE_COUNT,X + bmi no_tone_sliding ; if (a->tone_slide_count > 0) { + beq no_tone_sliding + + dec note_a+NOTE_TONE_SLIDE_COUNT,X ; a->tone_slide_count--; + bne no_tone_sliding ; if (a->tone_slide_count==0) { + + + ; a->tone_sliding+=a->tone_slide_step + clc ;;can be removed if ADC freq_h cannot overflow + lda note_a+NOTE_TONE_SLIDING_L,X + adc note_a+NOTE_TONE_SLIDE_STEP_L,X + sta note_a+NOTE_TONE_SLIDING_L,X + tay ; save NOTE_TONE_SLIDING_L in y + lda note_a+NOTE_TONE_SLIDING_H,X + adc note_a+NOTE_TONE_SLIDE_STEP_H,X + sta note_a+NOTE_TONE_SLIDING_H,X + + ; a->tone_slide_count = a->tone_slide_delay; + lda note_a+NOTE_TONE_SLIDE_DELAY,X + sta note_a+NOTE_TONE_SLIDE_COUNT,X + + lda note_a+NOTE_SIMPLE_GLISS,X + bne no_tone_sliding ; if (!a->simplegliss) { + + ; FIXME: do these need to be signed compares? + +check1: + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + bpl check2 ; if ( ((a->tone_slide_step < 0) && + + ; (a->tone_sliding <= a->tone_delta) || + + ; 16 bit signed compare + tya ; y has NOTE_TONE_SLIDING_L + cmp note_a+NOTE_TONE_DELTA_L,X ; NUM1-NUM2 + lda note_a+NOTE_TONE_SLIDING_H,X + sbc note_a+NOTE_TONE_DELTA_H,X + bvc sc_loser1 ; N eor V + eor #$80 +sc_loser1: + bmi slide_to_note ; then A (signed) < NUM (signed) and BMI will branch + + ; equals case + tya ; y has NOTE_TONE_SLIDING_L + cmp note_a+NOTE_TONE_DELTA_L,X + bne check2 + lda note_a+NOTE_TONE_SLIDING_H,X + cmp note_a+NOTE_TONE_DELTA_H,X + beq slide_to_note + +check2: + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + bmi no_tone_sliding ; ((a->tone_slide_step >= 0) && + + ; (a->tone_sliding >= a->tone_delta) + + ; 16 bit signed compare + tya ; y has NOTE_TONE_SLIDING_L + cmp note_a+NOTE_TONE_DELTA_L,X ; num1-num2 + lda note_a+NOTE_TONE_SLIDING_H,X + sbc note_a+NOTE_TONE_DELTA_H,X + bvc sc_loser2 ; N eor V + eor #$80 +sc_loser2: + bmi no_tone_sliding ; then A (signed) < NUM (signed) and BMI will branch + +slide_to_note: + ; a->note = a->slide_to_note; + lda note_a+NOTE_SLIDE_TO_NOTE,X + sta note_a+NOTE_NOTE,X + lda #0 + sta note_a+NOTE_TONE_SLIDE_COUNT,X + sta note_a+NOTE_TONE_SLIDING_L,X + sta note_a+NOTE_TONE_SLIDING_H,X + + +no_tone_sliding: + + ;========================= + ; Calculate the amplitude + ;========================= +calc_amplitude: + ; get base value from the sample (bottom 4 bits of sample_b1) + +sample_b1_smc: + lda #$d1 ; a->amplitude= (b1 & 0xf); + and #$f + + ;======================================== + ; if b0 top bit is set, it means sliding + + ; adjust amplitude sliding + + bit sample_b0_smc+1 ; if ((b0 & 0x80)!=0) { + bpl done_amp_sliding ; so if top bit not set, skip + tay + + ;================================ + ; if top bits 0b11 then slide up + ; if top bits 0b10 then slide down + + ; if ((b0 & 0x40)!=0) { + lda note_a+NOTE_AMPLITUDE_SLIDING,X + sec + bvc amp_slide_down + +amp_slide_up: + ; if (a->amplitude_sliding < 15) { + ; a pain to do signed compares + sbc #15 + bvc asu_signed + eor #$80 +asu_signed: + bpl done_amp_sliding ; skip if A>=15 + inc note_a+NOTE_AMPLITUDE_SLIDING,X ; a->amplitude_sliding++; + bne done_amp_sliding_y + +amp_slide_down: + ; if (a->amplitude_sliding > -15) { + ; a pain to do signed compares + sbc #$f1 ; -15 + bvc asd_signed + eor #$80 +asd_signed: + bmi done_amp_sliding ; if A < -15, skip subtract + + dec note_a+NOTE_AMPLITUDE_SLIDING,X ; a->amplitude_sliding--; + +done_amp_sliding_y: + tya + +done_amp_sliding: + + ; a->amplitude+=a->amplitude_sliding; + clc + adc note_a+NOTE_AMPLITUDE_SLIDING,X + + ; clamp amplitude to 0 - 15 + +check_amp_lo: + bmi write_clamp_amplitude + +check_amp_hi: + cmp #16 + bcc write_amplitude ; blt + lda #15 + .byte $2C +write_clamp_amplitude: + lda #0 +write_amplitude: + sta note_amp_smc+1 + +done_clamp_amplitude: + + ; We generate the proper table at runtime now + ; so always in Volume Table + ; a->amplitude = PT3VolumeTable_33_34[a->volume][a->amplitude]; + ; a->amplitude = PT3VolumeTable_35[a->volume][a->amplitude]; + + lda note_a+NOTE_VOLUME,X ; 4+ + asl ; 2 + asl ; 2 + asl ; 2 + asl ; 2 +note_amp_smc: + ora #$d1 ; 4+ + + tay ; 2 + lda VolumeTable,Y ; 4+ + sta note_a+NOTE_AMPLITUDE,X ; 5 + +done_table: + + +check_envelope_enable: + ; Bottom bit of b0 indicates our sample has envelope + ; Also make sure envelopes are enabled + + + ; if (((b0 & 0x1) == 0) && ( a->envelope_enabled)) { +sample_b0_smc: + lda #$d1 + lsr + tay + bcs envelope_slide + + lda note_a+NOTE_ENVELOPE_ENABLED,X + beq envelope_slide + + + ; Bit 4 of the per-channel AY-3-8910 amplitude specifies + ; envelope enabled + + lda note_a+NOTE_AMPLITUDE,X ; a->amplitude |= 16; + ora #$10 + sta note_a+NOTE_AMPLITUDE,X + + +envelope_slide: + + ; Envelope slide + ; If b1 top bits are 10 or 11 + + lda sample_b0_smc+1 + asl + asl + asl ; b0 bit 5 to carry flag + lda #$20 + bit sample_b1_smc+1 ; b1 bit 7 to sign flag, bit 5 to zero flag + php + bpl else_noise_slide ; if ((b1 & 0x80) != 0) { + tya + ora #$f0 + bcs envelope_slide_down ; if ((b0 & 0x20) == 0) { + +envelope_slide_up: + ; j = ((b0>>1)&0xF) + a->envelope_sliding; + and #$0f + clc + +envelope_slide_down: + + ; j = ((b0>>1)|0xF0) + a->envelope_sliding + adc note_a+NOTE_ENVELOPE_SLIDING,X + sta e_slide_amount_smc+1 ; j + +envelope_slide_done: + + plp + beq last_envelope ; if (( b1 & 0x20) != 0) { + + ; a->envelope_sliding = j; + sta note_a+NOTE_ENVELOPE_SLIDING,X + +last_envelope: + + ; pt3->envelope_add+=j; + + clc +e_slide_amount_smc: + lda #$d1 + adc pt3_envelope_add_smc+1 + sta pt3_envelope_add_smc+1 + + jmp noise_slide_done ; skip else + +else_noise_slide: + ; Noise slide + ; else { + + ; pt3->noise_add = (b0>>1) + a->noise_sliding; + tya + clc + adc note_a+NOTE_NOISE_SLIDING,X + sta pt3_noise_add_smc+1 + + plp + beq noise_slide_done ; if ((b1 & 0x20) != 0) { + + ; noise_sliding = pt3_noise_add + sta note_a+NOTE_NOISE_SLIDING,X + +noise_slide_done: + ;====================== + ; set mixer + + lda sample_b1_smc+1 ; pt3->mixer_value = ((b1 >>1) & 0x48) | pt3->mixer_value; + lsr + and #$48 + + ora PT3_MIXER_VAL ; 3 + sta PT3_MIXER_VAL ; 3 + + + ;======================== + ; increment sample position + + inc note_a+NOTE_SAMPLE_POSITION,X ; a->sample_position++; + + lda note_a+NOTE_SAMPLE_POSITION,X + cmp note_a+NOTE_SAMPLE_LENGTH,X + + bcc sample_pos_ok ; blt + + lda note_a+NOTE_SAMPLE_LOOP,X + sta note_a+NOTE_SAMPLE_POSITION,X + +sample_pos_ok: + + ;======================== + ; increment ornament position + + inc note_a+NOTE_ORNAMENT_POSITION,X ; a->ornament_position++; + lda note_a+NOTE_ORNAMENT_POSITION,X + cmp note_a+NOTE_ORNAMENT_LENGTH,X + + bcc ornament_pos_ok ; blt + + lda note_a+NOTE_ORNAMENT_LOOP,X + sta note_a+NOTE_ORNAMENT_POSITION,X +ornament_pos_ok: + + +done_note: + ; set mixer value + ; this is a bit complex (from original code) + ; after 3 calls it is set up properly + lsr PT3_MIXER_VAL + +handle_onoff: + ldy note_a+NOTE_ONOFF,X ;if (a->onoff>0) { + beq done_onoff + + dey ; a->onoff--; + + bne put_offon ; if (a->onoff==0) { + lda note_a+NOTE_ENABLED,X + eor #$1 ; toggle note_enabled + sta note_a+NOTE_ENABLED,X + + beq do_offon +do_onoff: + ldy note_a+NOTE_ONOFF_DELAY,X ; if (a->enabled) a->onoff=a->onoff_delay; + jmp put_offon +do_offon: + ldy note_a+NOTE_OFFON_DELAY,X ; else a->onoff=a->offon_delay; +put_offon: +.ifdef PT3_USE_ZERO_PAGE + sty note_a+NOTE_ONOFF,X +.else + lda note_a+NOTE_ONOFF,X + tay +.endif + +done_onoff: + + rts ; 6 + + + + + + + ;===================================== + ; Decode Note + ;===================================== + ; X points to the note offset + + ; Note! These timings are out of date (FIXME) + ; Timings (from ===>) + ; 00: 14+30 + ; 0X: 14+15 + ; 10: 14+5 +124 + ; 1X: 14+5 +193 + ; 2X/3X: 14+5 +17 + ; 4X: 14+5+5 + 111 + ; 5X-BX: 14+5+5+ 102 + ; CX: + ; DX/EX: + ; FX: + +stop_decoding: + + ; we are still running, decrement and early return + dec note_a+NOTE_LEN_COUNT,X ; 7 + rts ; 6 + + ;===================================== + ; Decode Line + ;===================================== + +pt3_decode_line: + ; decode_note(&pt3->a,&(pt3->a_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*0) + jsr decode_note + + ; decode_note(&pt3->b,&(pt3->b_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*1) + jsr decode_note + + ; decode_note(&pt3->c,&(pt3->c_addr),pt3); + ldx #(NOTE_STRUCT_SIZE*2) + ;;jsr decode_note ; fall through + +; if (pt3->a.all_done && pt3->b.all_done && pt3->c.all_done) { +; return 1; +; } + +decode_note: + + ; Init vars + + ldy #0 ; 2 + sty spec_command_smc+1 ; 4 + + ; Skip decode if note still running + lda note_a+NOTE_LEN_COUNT,X ; 4+ + cmp #2 ; 2 + bcs stop_decoding ; blt, assume not negative ; 2/3 + +keep_decoding: + + lda note_a+NOTE_NOTE,X ; store prev note ; 4+ + sta prev_note_smc+1 ; 4 + + lda note_a+NOTE_TONE_SLIDING_H,X ; store prev sliding ; 4+ + sta prev_sliding_h_smc+1 ; 4 + lda note_a+NOTE_TONE_SLIDING_L,X ; 4+ + sta prev_sliding_l_smc+1 ; 4 + + + ;============ + ; 24 + +note_decode_loop: + lda note_a+NOTE_LEN,X ; re-up length count ; 4+ + sta note_a+NOTE_LEN_COUNT,X ; 5 + + lda note_a+NOTE_ADDR_L,X ; 4+ + sta PATTERN_L ; 3 + lda note_a+NOTE_ADDR_H,X ; 4+ + sta PATTERN_H ; 3 +;===> + ; get next value + lda (PATTERN_L),Y ; 5+ + sta note_command_smc+1 ; save termporarily ; 4 + and #$0f ; 2 + sta note_command_bottom_smc+1 ; 4 + +note_command_smc: + lda #$d1 ; 2 + + ; FIXME: use a jump table?? + ; further reflection, that would require 32-bytes of addresses + ; in addition to needing X or Y to index the jump table. hmmm + + and #$f0 ; 2 + + ; cmp #$00 + bne decode_case_1X ; 2/3 + ;============= + ; 14 + +decode_case_0X: + ;============================== + ; $0X set special effect + ;============================== + ; -1 +note_command_bottom_smc: + lda #$d1 ; 2 + + ; we can always store spec as 0 means no spec + + ; FIXME: what if multiple spec commands? + ; Doesn't seem to happen in practice + ; But AY_emul has code to handle it + + sta spec_command_smc+1 ; 4 + + bne decode_case_0X_not_zero ; 2/3 + ;============= + ; 8 + ; 00 case + ; means end of pattern + ; -1 + sta note_a+NOTE_LEN_COUNT,X ; len_count=0; ; 5 + + dec pt3_pattern_done_smc+1 ; 6 + + jmp note_done_decoding ; 3 + +decode_case_1X: + ;============================== + ; $1X -- Set Envelope Type + ;============================== + + cmp #$10 ; 2 + bne decode_case_2X ; 2/3 + ;============ + ; 5 + + ; -1 + lda note_command_bottom_smc+1 ; 4 + bne decode_case_not_10 ; 3 + +decode_case_10: + ; 10 case - disable ; -1 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; A is 0 ; 5 + beq decode_case_1x_common ; branch always ; 3 + +decode_case_not_10: + ; -1 + jsr set_envelope ; 6+64 + +decode_case_1x_common: + + iny ; 2 + lda (PATTERN_L),Y ; 5+ + lsr ; 2 + jsr load_sample ; 6+86 + + lda #0 ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + +decode_case_0X_not_zero: + + jmp done_decode_loop ; 3 + +decode_case_2X: +decode_case_3X: + ;============================== + ; $2X/$3X set noise period + ;============================== + + cmp #$40 ; 2 + bcs decode_case_4X ; branch greater/equal ; 3 + ; -1 + lda note_command_smc+1 ; 4 + adc #$e0 ; same as subtract $20 ; 2 + sta pt3_noise_period_smc+1 ; 3 + + jmp done_decode_loop ; 3 + ;=========== + ; 16 + +decode_case_4X: + ;============================== + ; $4X -- set ornament + ;============================== +; cmp #$40 ; already set ; + bne decode_case_5X ; 3 + ; -1 + lda note_command_bottom_smc+1; set ornament to bottom nibble; 4 + jsr load_ornament ; 6+93 + + jmp done_decode_loop ; 3 + ;============ + ; 110 + +decode_case_5X: + ;============================== + ; $5X-$AX set note + ;============================== + cmp #$B0 ; 2 + bcs decode_case_bX ; branch greater/equal ; 3 + + ; -1 + lda note_command_smc+1 ; 4 + adc #$b0 ; 2 + sta note_a+NOTE_NOTE,X ; note=(current_val-0x50); ; 5 + + jsr reset_note ; 6+69 + + lda #1 ; 2 + sta note_a+NOTE_ENABLED,X ; enabled=1 ; 5 + + + bne note_done_decoding ; 3 + +decode_case_bX: + ;============================================ + ; $BX -- note length or envelope manipulation + ;============================================ +; cmp #$b0 ; already set from before + bne decode_case_cX ; 3 + ; -1 + lda note_command_bottom_smc+1 ; 4 + beq decode_case_b0 ; 3 + ; -1 + sbc #1 ; envelope_type=(current_val&0xf)-1; ; 2 + bne decode_case_bx_higher ; 3 + +decode_case_b1: + ; Set Length + + ; get next byte + iny ; 2 + lda (PATTERN_L),Y ; 5 + + sta note_a+NOTE_LEN,X ; 5 + sta note_a+NOTE_LEN_COUNT,X ; 5 + bcs done_decode_loop ; branch always ; 3 + +decode_case_b0: + ; Disable envelope + sta note_a+NOTE_ENVELOPE_ENABLED,X ; 5 + sta note_a+NOTE_ORNAMENT_POSITION,X ; 5 + beq done_decode_loop ; 3 + + +decode_case_bx_higher: + + jsr set_envelope ; 6+64 + + bcs done_decode_loop ; branch always ; 3 + +decode_case_cX: + ;============================== + ; $CX -- set volume + ;============================== + cmp #$c0 ; check top nibble $C ; 2 + bne decode_case_dX ; 3 + ; -1 + lda note_command_bottom_smc+1 ; 4 + bne decode_case_cx_not_c0 ; 3 + ; -1 +decode_case_c0: + ; special case $C0 means shut down the note + + sta note_a+NOTE_ENABLED,X ; enabled=0 ; 5 + + jsr reset_note ; 6+69 + + beq note_done_decoding ; branch always ; 3 + +decode_case_cx_not_c0: + sta note_a+NOTE_VOLUME,X ; volume=current_val&0xf; 5 + bne done_decode_loop ; branch always ; 3 + +decode_case_dX: + ;============================== + ; $DX/$EX -- change sample + ;============================== + ; D0 = special case (end note) + ; D1-EF = set sample to (value - $D0) + + cmp #$f0 ; check top nibble $D/$E ; 2 + beq decode_case_fX ; 3 + ; -1 + + lda note_command_smc+1 ; 4 + sec ; 2 + sbc #$d0 ; 2 + beq note_done_decoding ; 3 + +decode_case_not_d0: + ; -1 + + jsr load_sample ; load sample in bottom nybble ; 6+?? + + bcc done_decode_loop; branch always ; 3 + + ;======================== + ; d0 case means end note +;decode_case_d0: +; jmp note_done_decoding + + + ;============================== + ; $FX - change ornament/sample + ;============================== +decode_case_fX: + ; disable envelope + lda #0 ; 2 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; 5 + + ; Set ornament to low byte of command + lda note_command_bottom_smc+1 ; 4 + jsr load_ornament ; ornament to load in A ; 6+? + + ; Get next byte + iny ; point to next byte ; 2 + lda (PATTERN_L),Y ; 5 + + ; Set sample to value/2 + lsr ; divide by two ; 2 + jsr load_sample ; sample to load in A ; 6+? + + ; fallthrough + +done_decode_loop: + + iny ; point to next byte ; 2 + + jmp note_decode_loop ; 3 + +note_done_decoding: + + iny ; point to next byte ; 2 + + ;================================= + ; handle effects + ;================================= + ; Note, the AYemul code has code to make sure these are applied + ; In the same order they appear. We don't bother? +handle_effects: + +spec_command_smc: + lda #$d1 ; 2 + + ;============================== + ; Effect #1 -- Tone Down + ;============================== +effect_1: + cmp #$1 ; 2 + bne effect_2 ; 3 + ; -1 + sta note_a+NOTE_SIMPLE_GLISS,X ; 5 + lsr ; 2 + sta note_a+NOTE_ONOFF,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide delay ; 5 + iny ; 2 + + sta note_a+NOTE_TONE_SLIDE_DELAY,X ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide step low ; 5 + iny ; 2 + sta note_a+NOTE_TONE_SLIDE_STEP_L,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as slide step high ; 5 + iny ; 2 + sta note_a+NOTE_TONE_SLIDE_STEP_H,X ; 5 + + jmp no_effect ; 3 + + ;============================== + ; Effect #2 -- Portamento + ;============================== +effect_2: + cmp #$2 ; 2 + beq effect_2_small ; 3 + ; -1 + jmp effect_3 ; 3 +effect_2_small: ; FIXME: make smaller + lda #0 ; 2 + sta note_a+NOTE_SIMPLE_GLISS,X ; 5 + sta note_a+NOTE_ONOFF,X ; 5 + + lda (PATTERN_L),Y ; load byte, set as delay ; 5 + iny ; 2 + + sta note_a+NOTE_TONE_SLIDE_DELAY,X ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; 5 + + iny ; 2 + iny ; 2 + iny ; 2 + + lda (PATTERN_L),Y ; load byte, set as slide_step high ; 5 + php ; 3 + + ; 16-bit absolute value + bpl slide_step_positive1 ; 3 + ;-1 + eor #$ff ; 2 + +slide_step_positive1: + sta note_a+NOTE_TONE_SLIDE_STEP_H,X ; 5 + dey ; 2 + lda (PATTERN_L),Y ; load byte, set as slide_step low ; 5 + plp ; 4 + clc ; 2 + bpl slide_step_positive2 ; 3 + ;-1 + eor #$ff ; 2 + sec ; 2 + +slide_step_positive2: + adc #$0 ; 2 + sta note_a+NOTE_TONE_SLIDE_STEP_L,X ; 5 + bcc skip_step_inc1 ; 3 + inc note_a+NOTE_TONE_SLIDE_STEP_H,X ; 7 +skip_step_inc1: + + + iny ; moved here as it messed with flags ; 2 + iny ; 2 + + +; a->tone_delta=GetNoteFreq(a->note,pt3)- +; GetNoteFreq(prev_note,pt3); + + sty PT3_TEMP ; save Y +prev_note_smc: + ldy #$d1 + lda NoteTable_low,Y ; GetNoteFreq + sta temp_word_l2_smc+1 + lda NoteTable_high,Y ; GetNoteFreq + sta temp_word_h2_smc+1 + + ldy note_a+NOTE_NOTE,X + lda NoteTable_low,Y ; GetNoteFreq + + sec +temp_word_l2_smc: + sbc #$d1 + sta note_a+NOTE_TONE_DELTA_L,X + lda NoteTable_high,Y ; GetNoteFreq +temp_word_h2_smc: + sbc #$d1 + sta note_a+NOTE_TONE_DELTA_H,X + + ; a->slide_to_note=a->note; + lda note_a+NOTE_NOTE,X + sta note_a+NOTE_SLIDE_TO_NOTE,X + + ldy PT3_TEMP ; restore Y + + ; a->note=prev_note; + lda prev_note_smc+1 + sta note_a+NOTE_NOTE,X + + ; implement file version 6 and above slide behavior + ; this is done by SMC at song init time +version_smc: + jmp weird_version ; (JMP to BIT via smc) ; 3 + +prev_sliding_l_smc: + lda #$d1 + sta note_a+NOTE_TONE_SLIDING_L,X +prev_sliding_h_smc: + lda #$d1 + sta note_a+NOTE_TONE_SLIDING_H,X + +weird_version: + + ; annoying 16-bit subtract, only care if negative + ; if ((a->tone_delta - a->tone_sliding) < 0) { + sec + lda note_a+NOTE_TONE_DELTA_L,X + sbc note_a+NOTE_TONE_SLIDING_L,X + lda note_a+NOTE_TONE_DELTA_H,X + sbc note_a+NOTE_TONE_SLIDING_H,X + bpl no_effect + + ; a->tone_slide_step = -a->tone_slide_step; + + lda note_a+NOTE_TONE_SLIDE_STEP_L,X + eor #$ff + clc + adc #$1 + sta note_a+NOTE_TONE_SLIDE_STEP_L,X + lda note_a+NOTE_TONE_SLIDE_STEP_H,X + eor #$ff + adc #$0 + sta note_a+NOTE_TONE_SLIDE_STEP_H,X + + jmp no_effect + + ;============================== + ; Effect #3 -- Sample Position + ;============================== +effect_3: + cmp #$3 + bne effect_4 + + lda (PATTERN_L),Y ; load byte, set as sample position + iny + sta note_a+NOTE_SAMPLE_POSITION,X + + bne no_effect ; branch always + + ;============================== + ; Effect #4 -- Ornament Position + ;============================== +effect_4: + cmp #$4 + bne effect_5 + + lda (PATTERN_L),Y ; load byte, set as ornament position + iny + sta note_a+NOTE_ORNAMENT_POSITION,X + + bne no_effect ; branch always + + ;============================== + ; Effect #5 -- Vibrato + ;============================== +effect_5: + cmp #$5 + bne effect_8 + + lda (PATTERN_L),Y ; load byte, set as onoff delay + iny + sta note_a+NOTE_ONOFF_DELAY,X + sta note_a+NOTE_ONOFF,X + + lda (PATTERN_L),Y ; load byte, set as offon delay + iny + sta note_a+NOTE_OFFON_DELAY,X + + lda #0 + sta note_a+NOTE_TONE_SLIDE_COUNT,X + sta note_a+NOTE_TONE_SLIDING_L,X + sta note_a+NOTE_TONE_SLIDING_H,X + + beq no_effect ; branch always + + ;============================== + ; Effect #8 -- Envelope Down + ;============================== +effect_8: + cmp #$8 + bne effect_9 + + ; delay + lda (PATTERN_L),Y ; load byte, set as speed + iny + sta pt3_envelope_delay_smc+1 + sta pt3_envelope_delay_orig_smc+1 + + ; low value + lda (PATTERN_L),Y ; load byte, set as low + iny + sta pt3_envelope_slide_add_l_smc+1 + + ; high value + lda (PATTERN_L),Y ; load byte, set as high + iny + sta pt3_envelope_slide_add_h_smc+1 + + bne no_effect ; branch always + + ;============================== + ; Effect #9 -- Set Speed + ;============================== +effect_9: + cmp #$9 + bne no_effect + + lda (PATTERN_L),Y ; load byte, set as speed + iny + sta pt3_speed_smc+1 + +no_effect: + + ;================================ + ; add y into the address pointer + + clc + tya + adc note_a+NOTE_ADDR_L,X + sta note_a+NOTE_ADDR_L,X + lda #0 + adc note_a+NOTE_ADDR_H,X + sta note_a+NOTE_ADDR_H,X + sta PATTERN_H + + rts + + + ;======================================= + ; Set Envelope + ;======================================= + ; pulls out common code from $1X and $BX + ; commands + + ; A = new envelope type + +set_envelope: + + sta pt3_envelope_type_smc+1 ; 4 + +; give fake old to force update? maybe only needed if printing? +; pt3->envelope_type_old=0x78; + + lda #$78 ; 2 + sta pt3_envelope_type_old_smc+1 ; 4 + + ; get next byte + iny ; 2 + lda (PATTERN_L),Y ; 5+ + sta pt3_envelope_period_h_smc+1 ; 4 + + iny ; 2 + lda (PATTERN_L),Y ; 5+ + sta pt3_envelope_period_l_smc+1 ; 4 + + lda #1 ; 2 + sta note_a+NOTE_ENVELOPE_ENABLED,X ; envelope_enabled=1 ; 5 + lsr ; 2 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + sta pt3_envelope_delay_smc+1 ; envelope_delay=0 ; 4 + sta pt3_envelope_slide_l_smc+1 ; envelope_slide=0 ; 4 + sta pt3_envelope_slide_h_smc+1 ; 4 + + rts ; 6 + ;=========== + ; 64 + + ;======================== + ; reset note + ;======================== + ; common code from the decode note code + +reset_note: + lda #0 ; 2 + sta note_a+NOTE_SAMPLE_POSITION,X ; sample_position=0 ; 5 + sta note_a+NOTE_AMPLITUDE_SLIDING,X ; amplitude_sliding=0 ; 5 + sta note_a+NOTE_NOISE_SLIDING,X ; noise_sliding=0 ; 5 + sta note_a+NOTE_ENVELOPE_SLIDING,X ; envelope_sliding=0 ; 5 + sta note_a+NOTE_ORNAMENT_POSITION,X ; ornament_position=0 ; 5 + sta note_a+NOTE_TONE_SLIDE_COUNT,X ; tone_slide_count=0 ; 5 + sta note_a+NOTE_TONE_SLIDING_L,X ; tone_sliding=0 ; 5 + sta note_a+NOTE_TONE_SLIDING_H,X ; 5 + sta note_a+NOTE_TONE_ACCUMULATOR_L,X ; tone_accumulator=0 ; 5 + sta note_a+NOTE_TONE_ACCUMULATOR_H,X ; 5 + sta note_a+NOTE_ONOFF,X ; onoff=0; ; 5 + + rts ; 6 + ;============ + ; 69 + + + + + + + ;===================================== + ; Set Pattern + ;===================================== + ; FIXME: inline this? we do call it from outside + ; in the player note length code + +is_done: + ; done with song, set it to non-zero + sta DONE_SONG ; 3 + rts ; 6 + +pt3_set_pattern: + + ; Lookup current pattern in pattern table +current_pattern_smc: + ldy #$d1 ; 2 + lda PT3_LOC+PT3_PATTERN_TABLE,Y ; 4+ + + ; if value is $FF we are at the end of the song + cmp #$ff ; 2 + beq is_done ; 2/3 + + ;============ + ; 20 if end + +not_done: + + ; set up the three pattern address pointers + + asl ; mul pattern offset by two, as word sized ; 2 + tay ; 2 + + ; point PATTERN_H/PATTERN_L to the pattern address table + + clc ; 2 + lda PT3_LOC+PT3_PATTERN_LOC_L ; 4 + sta PATTERN_L ; 3 + lda PT3_LOC+PT3_PATTERN_LOC_H ; 4 + adc #>PT3_LOC ; assume page boundary ; 2 + sta PATTERN_H ; 3 + + ; First 16-bits points to the Channel A address + lda (PATTERN_L),Y ; 5+ + sta note_a+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_a+NOTE_ADDR_H ; 4 + iny ; 2 + + ; Next 16-bits points to the Channel B address + lda (PATTERN_L),Y ; 5+ + sta note_b+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_b+NOTE_ADDR_H ; 4 + iny ; 2 + + ; Next 16-bits points to the Channel C address + lda (PATTERN_L),Y ; 5+ + sta note_c+NOTE_ADDR_L ; 4 + iny ; 2 + lda (PATTERN_L),Y ; 5+ + adc #>PT3_LOC ; assume page boundary ; 2 + sta note_c+NOTE_ADDR_H ; 4 + + ; clear out the noise channel + lda #0 ; 2 + sta pt3_noise_period_smc+1 ; 4 + + ; Set all three channels as active + ; FIXME: num_channels, may need to be 6 if doing 6-channel pt3? + lda #3 ; 2 + sta pt3_pattern_done_smc+1 ; 4 + + rts ; 6 + + + + ;===================================== + ; pt3 make frame + ;===================================== + ; update pattern or line if necessary + ; then calculate the values for the next frame + + ;========================== + ; pattern done early! + +early_end: + inc current_pattern_smc+1 ; increment pattern ; 6 + sta current_line_smc+1 ; 4 + sta current_subframe_smc+1 ; 4 + +check_subframe: + lda current_subframe_smc+1 ; 4 + bne pattern_good ; 2/3 + + ; load a new pattern in + jsr pt3_set_pattern ;6+? + + lda DONE_SONG ; 3 + beq pattern_good ; 2/3 + rts ; 6 + +pt3_make_frame: + + ; see if we need a new pattern + ; we do if line==0 and subframe==0 + ; allow fallthrough where possible +current_line_smc: + lda #$d1 ; 2 + beq check_subframe ; 2/3 + +pattern_good: + + ; see if we need a new line + +current_subframe_smc: + lda #$d1 ; 2 + bne line_good ; 2/3 + + ; decode a new line + jsr pt3_decode_line ; 6+? + + ; check if pattern done early +pt3_pattern_done_smc: + lda #$d1 ; 2 + beq early_end ; 2/3 + +line_good: + + ; Increment everything + + inc current_subframe_smc+1 ; subframe++ ; 6 + lda current_subframe_smc+1 ; 4 + + ; if we hit pt3_speed, move to next +pt3_speed_smc: + eor #$d1 ; 2 + bne do_frame ; 2/3 + +next_line: + sta current_subframe_smc+1 ; reset subframe to 0 ; 4 + + inc current_line_smc+1 ; and increment line ; 6 + lda current_line_smc+1 ; 4 + + eor #64 ; always end at 64. ; 2 + bne do_frame ; is this always needed? ; 2/3 + +next_pattern: + sta current_line_smc+1 ; reset line to 0 ; 4 + + inc current_pattern_smc+1 ; increment pattern ; 6 + +do_frame: + ; AY-3-8910 register summary + ; + ; R0/R1 = A period low/high + ; R2/R3 = B period low/high + ; R4/R5 = C period low/high + ; R6 = Noise period + ; R7 = Enable XX Noise=!CBA Tone=!CBA + ; R8/R9/R10 = Channel A/B/C amplitude M3210, M=envelope enable + ; R11/R12 = Envelope Period low/high + ; R13 = Envelope Shape, 0xff means don't write + ; R14/R15 = I/O (ignored) + + ldx #0 ; needed ; 2 + stx PT3_MIXER_VAL ; 3 + stx pt3_envelope_add_smc+1 ; 4 + + ;;ldx #(NOTE_STRUCT_SIZE*0) ; Note A ; 2 + jsr calculate_note ; 6+? + ldx #(NOTE_STRUCT_SIZE*1) ; Note B ; 2 + jsr calculate_note ; 6+? + ldx #(NOTE_STRUCT_SIZE*2) ; Note C ; 2 + jsr calculate_note ; 6+? + +convert_177_smc1: + sec ; 2 + + ; Load up the Frequency Registers + + lda note_a+NOTE_TONE_L ; Note A Period L ; 4 + sta AY_REGISTERS+0 ; into R0 ; 3 + + lda note_a+NOTE_TONE_H ; Note A Period H ; 4 + sta AY_REGISTERS+1 ; into R1 ; 3 + lda note_a+NOTE_TONE_L ; Note A Period L ; 4 + bcc no_scale_a ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; conversion costs 100 cycles! + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + asl ; 2 + rol AY_REGISTERS+1 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_a+NOTE_TONE_L ; 4 + sta AY_REGISTERS+0 ; 3 + lda note_a+NOTE_TONE_H ; 4 + adc AY_REGISTERS+1 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + ror ; 2 + ror AY_REGISTERS+0 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+1 ; 3 + +no_scale_a: + +convert_177_smc2: + sec ; 2 + + lda note_b+NOTE_TONE_L ; Note B Period L ; 4 + sta AY_REGISTERS+2 ; into R2 ; 3 + + lda note_b+NOTE_TONE_H ; Note B Period H ; 4 + sta AY_REGISTERS+3 ; into R3 ; 3 + lda note_b+NOTE_TONE_L ; Note B Period L ; 4 + bcc no_scale_b ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + asl ; 2 + rol AY_REGISTERS+3 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_b+NOTE_TONE_L ; 4 + sta AY_REGISTERS+2 ; 3 + lda note_b+NOTE_TONE_H ; 4 + adc AY_REGISTERS+3 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + ror ; 2 + ror AY_REGISTERS+2 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+3 ; 3 + +no_scale_b: + +convert_177_smc3: + sec ; 2 + + lda note_c+NOTE_TONE_L ; Note C Period L ; 4 + sta AY_REGISTERS+4 ; into R4 ; 3 + lda note_c+NOTE_TONE_H ; Note C Period H ; 4 + sta AY_REGISTERS+5 ; into R5 ; 3 + lda note_c+NOTE_TONE_L ; Note C Period L ; 4 + bcc no_scale_c ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + asl ; 2 + rol AY_REGISTERS+5 ; 5 + + ; add in original to get 9 + clc ; 2 + adc note_c+NOTE_TONE_L ; 4 + sta AY_REGISTERS+4 ; 3 + lda note_c+NOTE_TONE_H ; 4 + adc AY_REGISTERS+5 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + ror ; 2 + ror AY_REGISTERS+4 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+5 ; 3 + +no_scale_c: + + + ; Noise + ; frame[6]= (pt3->noise_period+pt3->noise_add)&0x1f; + clc ; 2 +pt3_noise_period_smc: + lda #$d1 ; 2 +pt3_noise_add_smc: + adc #$d1 ; 2 + and #$1f ; 2 + sta AY_REGISTERS+6 ; 3 + +convert_177_smc4: + sec ; 2 + bcc no_scale_n ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + ; first multiply by 8 + asl ; 2 + asl ; 2 + asl ; 2 + + ; add in original to get 9 + adc AY_REGISTERS+6 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror ; 2 + ror ; 2 + ror ; 2 + and #$1f ; 2 + +no_scale_n: + sta AY_REGISTERS+6 ; 3 + + ;======================= + ; Mixer + + ; PT3_MIXER_VAL is already in AY_REGISTERS+7 + + ;======================= + ; Amplitudes + + lda note_a+NOTE_AMPLITUDE ; 3 + sta AY_REGISTERS+8 ; 3 + lda note_b+NOTE_AMPLITUDE ; 3 + sta AY_REGISTERS+9 ; 3 + lda note_c+NOTE_AMPLITUDE ; 3 + sta AY_REGISTERS+10 ; 3 + + ;====================================== + ; Envelope period + ; result=period+add+slide (16-bits) + clc ; 2 +pt3_envelope_period_l_smc: + lda #$d1 ; 2 +pt3_envelope_add_smc: + adc #$d1 ; 2 + tay ; 2 +pt3_envelope_period_h_smc: + lda #$d1 ; 2 + adc #0 ; 2 + tax ; 2 + + clc ; 2 + tya ; 2 +pt3_envelope_slide_l_smc: + adc #$d1 ; 2 + sta AY_REGISTERS+11 ; 3 + txa ; 2 +pt3_envelope_slide_h_smc: + adc #$d1 ; 2 + sta AY_REGISTERS+12 ; 3 + +convert_177_smc5: + sec + bcc no_scale_e ; 2/3 + + ; Convert from 1.77MHz to 1MHz by multiplying by 9/16 + + tay ; 2 + ; first multiply by 8 + lda AY_REGISTERS+11 ; 3 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + asl ; 2 + rol AY_REGISTERS+12 ; 5 + + ; add in original to get 9 + clc ; 2 + adc AY_REGISTERS+11 ; 3 + sta AY_REGISTERS+11 ; 3 + tya ; 2 + adc AY_REGISTERS+12 ; 3 + + ; divide by 16 to get proper value + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + ror ; 2 + ror AY_REGISTERS+11 ; 5 + and #$0f ; 2 + sta AY_REGISTERS+12 ; 3 + +no_scale_e: + + ;======================== + ; Envelope shape + +pt3_envelope_type_smc: + lda #$d1 ; 2 +pt3_envelope_type_old_smc: + cmp #$d1 ; 2 + sta pt3_envelope_type_old_smc+1; copy old to new ; 4 + bne envelope_diff ; 2/3 +envelope_same: + lda #$ff ; if same, store $ff ; 2 +envelope_diff: + sta AY_REGISTERS+13 ; 3 + + + + ;============================== + ; end-of-frame envelope update + ;============================== + +pt3_envelope_delay_smc: + lda #$d1 ; 2 + beq done_do_frame ; assume can't be negative? ; 2/3 + ; do this if envelope_delay>0 + dec pt3_envelope_delay_smc+1 ; 6 + bne done_do_frame ; 2/3 + ; only do if we hit 0 +pt3_envelope_delay_orig_smc: + lda #$d1 ; reset envelope delay ; 2 + sta pt3_envelope_delay_smc+1 ; 4 + + clc ; 16-bit add ; 2 + lda pt3_envelope_slide_l_smc+1 ; 4 +pt3_envelope_slide_add_l_smc: + adc #$d1 ; 2 + sta pt3_envelope_slide_l_smc+1 ; 4 + lda pt3_envelope_slide_h_smc+1 ; 4 +pt3_envelope_slide_add_h_smc: + adc #$d1 ; 2 + sta pt3_envelope_slide_h_smc+1 ; 4 + +done_do_frame: + + rts ; 6 + + +; note, you might have slightly better performance if these are aligned +; so that loads don't have to cross page boundaries + +NoteTable_high: + .res 96,0 +NoteTable_low: + .res 96,0 + +VolumeTable: + .res 256,0 + + +pt3_lib_end: diff --git a/demos/second/pt3_lib_detect_model.s b/demos/second/pt3_lib_detect_model.s new file mode 100644 index 00000000..31c1b8dc --- /dev/null +++ b/demos/second/pt3_lib_detect_model.s @@ -0,0 +1,63 @@ + ;=========================== + ; Check Apple II model + ;=========================== + ; this is mostly for IIc support + ; as it does interrupts differently + + ; ' ' ($20) = Apple II + ; '+' ($2B) = Apple II+ + ; 'E' ($45) = Apple IIe + ; 'C' ($43) = Apple IIc + ; 'G' ($47) = Apple IIgs + + +detect_appleii_model: + lda #' ' + + ldx $FBB3 + ; II is $38 + ; J-plus is $C9 + ; II+ is $EA (so is III) + ; IIe and newer is $06 + + cpx #$38 + beq done_apple_detect + + lda #'+' + cpx #$EA + beq done_apple_detect + + ; TODO: check for J-plus or III? + + cpx #$06 + bne done_apple_detect + +apple_iie_or_newer: + + + + ldx $FBC0 ; $EA on a IIe + ; $E0 on a IIe enhanced + ; $00 on a IIc/IIc+ + + ; $FE1F = $60, IIgs + + beq apple_iic + + lda #'E' + cpx #$EA + beq done_apple_detect + cpx #$E0 + beq done_apple_detect + + ; assume GS? + + lda #'G' + bne done_apple_detect + +apple_iic: + lda #'C' + +done_apple_detect: + sta APPLEII_MODEL + rts diff --git a/demos/second/pt3_lib_init.s b/demos/second/pt3_lib_init.s new file mode 100644 index 00000000..037b1ade --- /dev/null +++ b/demos/second/pt3_lib_init.s @@ -0,0 +1,575 @@ +; pt3_lib_init.s + +; Initialize a song + +; this is done before song starts playing so it is not +; as performance / timing critical + + ;==================================== + ; pt3_init_song + ;==================================== + ; +pt3_init_song: + + lda #$0 + sta DONE_SONG ; 3 + ldx #(end_vars-begin_vars) +zero_song_structs_loop: + dex + sta note_a,X + bne zero_song_structs_loop + + sta pt3_noise_period_smc+1 ; 4 + sta pt3_noise_add_smc+1 ; 4 + + sta pt3_envelope_period_l_smc+1 ; 4 + sta pt3_envelope_period_h_smc+1 ; 4 + sta pt3_envelope_slide_l_smc+1 ; 4 + sta pt3_envelope_slide_h_smc+1 ; 4 + sta pt3_envelope_slide_add_l_smc+1 ; 4 + sta pt3_envelope_slide_add_h_smc+1 ; 4 + sta pt3_envelope_add_smc+1 ; 4 + sta pt3_envelope_type_smc+1 ; 4 + sta pt3_envelope_type_old_smc+1 ; 4 + sta pt3_envelope_delay_smc+1 ; 4 + sta pt3_envelope_delay_orig_smc+1 ; 4 + + sta PT3_MIXER_VAL ; 3 + + sta current_pattern_smc+1 ; 4 + sta current_line_smc+1 ; 4 + sta current_subframe_smc+1 ; 4 + + lda #$f ; 2 + sta note_a+NOTE_VOLUME ; 4 + sta note_b+NOTE_VOLUME ; 4 + sta note_c+NOTE_VOLUME ; 4 + + ; default ornament/sample in A + ; X is zero coming in here + ;ldx #(NOTE_STRUCT_SIZE*0) ; 2 + jsr load_ornament0_sample1 ; 6+93 + + ; default ornament/sample in B + ldx #(NOTE_STRUCT_SIZE*1) ; 2 + jsr load_ornament0_sample1 ; 6+93 + + ; default ornament/sample in C + ldx #(NOTE_STRUCT_SIZE*2) ; 2 + jsr load_ornament0_sample1 ; 6+93 + + ;======================= + ; load default speed + + lda PT3_LOC+PT3_SPEED ; 4 + sta pt3_speed_smc+1 ; 4 + + ;======================= + ; load loop + + lda PT3_LOC+PT3_LOOP ; 4 + sta pt3_loop_smc+1 ; 4 + + + ;======================== + ;======================== + ; set up note/freq table + ; this saves some space and makes things marginally faster longrun + ;======================== + ;======================== + ; note (heh) that there are separate tables if version 3.3 + ; but we are going to assume we are only going to be playing + ; newer 3.4+ version files so only need the newer tables + + ldx PT3_LOC+PT3_HEADER_FREQUENCY ; 4 + beq use_freq_table_0 + dex + beq use_freq_table_1 + dex + beq use_freq_table_2 + ; fallthrough (freq table 3) + +use_freq_table_3: + ;================================================= + ; Create Table #3, v4+, "PT3NoteTable_REAL_34_35" + ;================================================= + + ldy #11 ; !2 +freq_table_3_copy_loop: + ; note, high lookup almost same as 2v4, just need to adjust one value + + lda base2_v4_high,Y ; !3 + sta NoteTable_high,Y ; !3 + lda base3_low,Y ; !3 + sta NoteTable_low,Y ; !3 + dey ; !1 + bpl freq_table_3_copy_loop ; !2 + + dec NoteTable_high ; adjust to right value + + jsr NoteTablePropogate ; !3 + + lda #table3_v4_adjust + sta note_table_adjust_smc+2 + + jsr NoteTableAdjust + + jmp done_set_freq_table + + + +use_freq_table_2: + ;================================================= + ; Create Table #2, v4+, "PT3NoteTable_ASM_34_35" + ;================================================= + + ldy #11 +freq_table_2_copy_loop: + lda base2_v4_high,Y + sta NoteTable_high,Y + lda base2_v4_low,Y + sta NoteTable_low,Y + dey + bpl freq_table_2_copy_loop + + jsr NoteTablePropogate ; !3 + + lda #table2_v4_adjust + sta note_table_adjust_smc+2 + + jsr NoteTableAdjust + + jmp done_set_freq_table + +use_freq_table_1: + ;================================================= + ; Create Table #1, "PT3NoteTable_ST" + ;================================================= + + ldy #11 +freq_table_1_copy_loop: + lda base1_high,Y + sta NoteTable_high,Y + lda base1_low,Y + sta NoteTable_low,Y + dey + bpl freq_table_1_copy_loop + + jsr NoteTablePropogate ; !3 + + ; last adjustments + lda #$FD ; Tone[23]=$3FD + sta NoteTable_low+23 + dec NoteTable_low+46 ; Tone[46]-=1; + + + jmp done_set_freq_table + + +use_freq_table_0: + ;================================================= + ; Create Table #0, "PT3NoteTable_PT_34_35" + ;================================================= + + ldy #11 +freq_table_0_copy_loop: + lda base0_v4_high,Y + sta NoteTable_high,Y + lda base0_v4_low,Y + sta NoteTable_low,Y + dey + bpl freq_table_0_copy_loop + + jsr NoteTablePropogate ; !3 + + lda #table0_v4_adjust + sta note_table_adjust_smc+2 + + jsr NoteTableAdjust + + +done_set_freq_table: + + + ;====================== + ; calculate version + ldx #6 ; 2 + lda PT3_LOC+PT3_VERSION ; 4 + sec ; 2 + sbc #'0' ; 2 + cmp #9 ; 2 + bcs not_ascii_number ; bge ; 2/3 + tax ; 2 + +not_ascii_number: + + ; adjust version<6 SMC code in the slide code + + ; FIXME: I am sure there's a more clever way to do this + + lda #$2C ; BIT ; 2 + cpx #$6 ; 2 + bcs version_greater_than_or_equal_6 ; bgt ; 3 + ; less than 6, jump + ; also carry is known to be clear + adc #$20 ; BIT->JMP 2C->4C ; 2 +version_greater_than_or_equal_6: + sta version_smc ; 4 + +pick_volume_table: + + ;======================= + ; Pick which volume number, based on version + + ; if (PlParams.PT3.PT3_Version <= 4) + + cpx #5 ; 2 + + ; carry clear = 3.3/3.4 table + ; carry set = 3.5 table + + ;========================== + ; VolTableCreator + ;========================== + ; Creates the appropriate volume table + ; based on z80 code by Ivan Roshin ZXAYHOBETA/VTII10bG.asm + ; + + ; Called with carry==0 for 3.3/3.4 table + ; Called with carry==1 for 3.5 table + + ; 177f-1932 = 435 bytes, not that much better than 512 of lookup + + +VolTableCreator: + + ; Init initial variables + lda #$0 + sta z80_d_smc+1 + ldy #$11 + + ; Set up self modify + + ldx #$2A ; ROL for self-modify + bcs vol_type_35 + +vol_type_33: + + ; For older table, we set initial conditions a bit + ; different + + dey + tya + + ldx #$ea ; NOP for self modify + +vol_type_35: + sty z80_l_smc+1 ; l=16 or 17 + sta z80_e_smc+1 ; e=16 or 0 + stx vol_smc ; set the self-modify code + + ldy #16 ; skip first row, all zeros + ldx #16 ; c=16 +vol_outer: + clc ; add HL,DE +z80_l_smc: + lda #$d1 +z80_e_smc: + adc #$d1 + sta z80_e_smc+1 + lda #0 +z80_d_smc: + adc #$d1 + sta z80_d_smc+1 ; carry is important + + ; sbc hl,hl + lda #0 + adc #$ff + eor #$ff + +vol_write: + sta z80_h_smc+1 + pha + +vol_inner: + pla + pha + +vol_smc: + nop ; nop or ROL depending + +z80_h_smc: + lda #$d1 + + adc #$0 ; a=a+carry; + + sta VolumeTable,Y + iny + + pla ; add HL,DE + adc z80_e_smc+1 + pha + lda z80_h_smc+1 + adc z80_d_smc+1 + sta z80_h_smc+1 + + inx ; inc C + txa ; a=c + and #$f + bne vol_inner + + + pla + + lda z80_e_smc+1 ; a=e + cmp #$77 + bne vol_m3 + + inc z80_e_smc+1 + +vol_m3: + txa ; a=c + bne vol_outer + +vol_done: + rts + + + ;========================================= + ; copy note table seed to proper location + ;========================================= + +; faster inlined + +;NoteTableCopy: + +; ldy #11 ; !2 +;note_table_copy_loop: +;ntc_smc1: +; lda base1_high,Y ; !3 +; sta NoteTable_high,Y ; !3 +;ntc_smc2: +; lda base1_low,Y ; !3 +; sta NoteTable_low,Y ; !3 +; dey ; !1 +; bpl note_table_copy_loop ; !2 +; rts ; !1 + + + ;========================================== + ; propogate the freq down, dividing by two + ;========================================== +NoteTablePropogate: + + ldy #0 +note_table_propogate_loop: + clc + lda NoteTable_high,Y + ror + sta NoteTable_high+12,Y + + lda NoteTable_low,Y + ror + sta NoteTable_low+12,Y + + iny + cpy #84 + bne note_table_propogate_loop + + rts + + + ;================================================ + ; propogation isn't enough, various values + ; are often off by one, so adjust using a bitmask + ;================================================ +NoteTableAdjust: + + ldx #0 +note_table_adjust_outer: + +note_table_adjust_smc: + lda table0_v4_adjust,X + sta PT3_TEMP + + ; reset smc + lda #NoteTable_low + sta ntl_smc+2 + + + ldy #7 +note_table_adjust_inner: + ror PT3_TEMP + bcc note_table_skip_adjust + +ntl_smc: + inc NoteTable_low,X + +note_table_skip_adjust: + clc + lda #12 + adc ntl_smc+1 + sta ntl_smc+1 + lda #0 + adc ntl_smc+2 ; unnecessary if aligned + sta ntl_smc+2 + +skip_adjust_done: + dey + bpl note_table_adjust_inner + + inx + cpx #12 + bne note_table_adjust_outer + + rts + + +;base0_v3_high: +;.byte $0C,$0B,$0A,$0A,$09,$09,$08,$08,$07,$07,$06,$06 +;base0_v3_low: +;.byte $21,$73,$CE,$33,$A0,$16,$93,$18,$A4,$36,$CE,$6D + +; note: same as base0_v3_high +base0_v4_high: +.byte $0C,$0B,$0A,$0A,$09,$09,$08,$08,$07,$07,$06,$06 +base0_v4_low: +.byte $22,$73,$CF,$33,$A1,$17,$94,$19,$A4,$37,$CF,$6D + +base1_high: +.byte $0E,$0E,$0D,$0C,$0B,$0B,$0A,$09,$09,$08,$08,$07 +base1_low: +.byte $F8,$10,$60,$80,$D8,$28,$88,$F0,$60,$E0,$58,$E0 + +;base2_v3_high: +;.byte $0D,$0C,$0B,$0B,$0A,$09,$09,$08,$08,$07,$07,$07 +;base2_v3_low: +;.byte $3E,$80,$CC,$22,$82,$EC,$5C,$D6,$58,$E0,$6E,$04 + +; note almost same as above +base2_v4_high: +.byte $0D,$0C,$0B,$0A,$0A,$09,$09,$08,$08,$07,$07,$06 +base2_v4_low: +.byte $10,$55,$A4,$FC,$5F,$CA,$3D,$B8,$3B,$C5,$55,$EC + +; note almost same as above +;base3_high: +;.byte $0C,$0C,$0B,$0A,$0A,$09,$09,$08,$08,$07,$07,$06 +base3_low: +.byte $DA,$22,$73,$CF,$33,$A1,$17,$94,$19,$A4,$37,$CF + + +; Adjustment factors +table0_v4_adjust: +.byte $40,$e6,$9c,$66,$40,$2c,$20,$30,$48,$6c,$1c,$5a + +table2_v4_adjust: +.byte $20,$a8,$40,$f8,$bc,$90,$78,$70,$74,$08,$2a,$50 + +table3_v4_adjust: +.byte $B4,$40,$e6,$9c,$66,$40,$2c,$20,$30,$48,$6c,$1c + + +; Table #1 of Pro Tracker 3.3x - 3.5x +;PT3NoteTable_ST_high: +;.byte $0E,$0E,$0D,$0C,$0B,$0B,$0A,$09 +;.byte $09,$08,$08,$07,$07,$07,$06,$06 +;.byte $05,$05,$05,$04,$04,$04,$04,$03 +;.byte $03,$03,$03,$03,$02,$02,$02,$02 +;.byte $02,$02,$02,$01,$01,$01,$01,$01 +;.byte $01,$01,$01,$01,$01,$01,$01,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 + +;PT3NoteTable_ST_low: +;.byte $F8,$10,$60,$80,$D8,$28,$88,$F0 +;.byte $60,$E0,$58,$E0,$7C,$08,$B0,$40 +;.byte $EC,$94,$44,$F8,$B0,$70,$2C,$FD +;.byte $BE,$84,$58,$20,$F6,$CA,$A2,$7C +;.byte $58,$38,$16,$F8,$DF,$C2,$AC,$90 +;.byte $7B,$65,$51,$3E,$2C,$1C,$0A,$FC +;.byte $EF,$E1,$D6,$C8,$BD,$B2,$A8,$9F +;.byte $96,$8E,$85,$7E,$77,$70,$6B,$64 +;.byte $5E,$59,$54,$4F,$4B,$47,$42,$3F +;.byte $3B,$38,$35,$32,$2F,$2C,$2A,$27 +;.byte $25,$23,$21,$1F,$1D,$1C,$1A,$19 +;.byte $17,$16,$15,$13,$12,$11,$10,$0F + + +; Table #2 of Pro Tracker 3.4x - 3.5x +;PT3NoteTable_ASM_34_35_high: +;.byte $0D,$0C,$0B,$0A,$0A,$09,$09,$08 +;.byte $08,$07,$07,$06,$06,$06,$05,$05 +;.byte $05,$04,$04,$04,$04,$03,$03,$03 +;.byte $03,$03,$02,$02,$02,$02,$02,$02 +;.byte $02,$01,$01,$01,$01,$01,$01,$01 +;.byte $01,$01,$01,$01,$01,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 +;.byte $00,$00,$00,$00,$00,$00,$00,$00 + +;PT3NoteTable_ASM_34_35_low: +;.byte $10,$55,$A4,$FC,$5F,$CA,$3D,$B8 +;.byte $3B,$C5,$55,$EC,$88,$2A,$D2,$7E +;.byte $2F,$E5,$9E,$5C,$1D,$E2,$AB,$76 +;.byte $44,$15,$E9,$BF,$98,$72,$4F,$2E +;.byte $0F,$F1,$D5,$BB,$A2,$8B,$74,$60 +;.byte $4C,$39,$28,$17,$07,$F9,$EB,$DD +;.byte $D1,$C5,$BA,$B0,$A6,$9D,$94,$8C +;.byte $84,$7C,$75,$6F,$69,$63,$5D,$58 +;.byte $53,$4E,$4A,$46,$42,$3E,$3B,$37 +;.byte $34,$31,$2F,$2C,$29,$27,$25,$23 +;.byte $21,$1F,$1D,$1C,$1A,$19,$17,$16 +;.byte $15,$14,$12,$11,$10,$0F,$0E,$0D + + +;PT3VolumeTable_33_34: +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1 +;.byte $0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$2,$2,$2,$2,$2 +;.byte $0,$0,$0,$0,$1,$1,$1,$1,$2,$2,$2,$2,$3,$3,$3,$3 +;.byte $0,$0,$0,$0,$1,$1,$1,$2,$2,$2,$3,$3,$3,$4,$4,$4 +;.byte $0,$0,$0,$1,$1,$1,$2,$2,$3,$3,$3,$4,$4,$4,$5,$5 +;.byte $0,$0,$0,$1,$1,$2,$2,$3,$3,$3,$4,$4,$5,$5,$6,$6 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$5,$5,$6,$6,$7,$7,$8 +;.byte $0,$0,$1,$1,$2,$3,$3,$4,$5,$5,$6,$6,$7,$8,$8,$9 +;.byte $0,$0,$1,$2,$2,$3,$4,$4,$5,$6,$6,$7,$8,$8,$9,$A +;.byte $0,$0,$1,$2,$3,$3,$4,$5,$6,$6,$7,$8,$9,$9,$A,$B +;.byte $0,$0,$1,$2,$3,$4,$4,$5,$6,$7,$8,$8,$9,$A,$B,$C +;.byte $0,$0,$1,$2,$3,$4,$5,$6,$7,$7,$8,$9,$A,$B,$C,$D +;.byte $0,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E,$F + +;PT3VolumeTable_35: +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 +;.byte $0,$0,$0,$0,$0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1 +;.byte $0,$0,$0,$0,$1,$1,$1,$1,$1,$1,$1,$1,$2,$2,$2,$2 +;.byte $0,$0,$0,$1,$1,$1,$1,$1,$2,$2,$2,$2,$2,$3,$3,$3 +;.byte $0,$0,$1,$1,$1,$1,$2,$2,$2,$2,$3,$3,$3,$3,$4,$4 +;.byte $0,$0,$1,$1,$1,$2,$2,$2,$3,$3,$3,$4,$4,$4,$5,$5 +;.byte $0,$0,$1,$1,$2,$2,$2,$3,$3,$4,$4,$4,$5,$5,$6,$6 +;.byte $0,$0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7 +;.byte $0,$1,$1,$2,$2,$3,$3,$4,$4,$5,$5,$6,$6,$7,$7,$8 +;.byte $0,$1,$1,$2,$2,$3,$4,$4,$5,$5,$6,$7,$7,$8,$8,$9 +;.byte $0,$1,$1,$2,$3,$3,$4,$5,$5,$6,$7,$7,$8,$9,$9,$A +;.byte $0,$1,$1,$2,$3,$4,$4,$5,$6,$7,$7,$8,$9,$A,$A,$B +;.byte $0,$1,$2,$2,$3,$4,$5,$6,$6,$7,$8,$9,$A,$A,$B,$C +;.byte $0,$1,$2,$3,$3,$4,$5,$6,$7,$8,$9,$A,$A,$B,$C,$D +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$7,$8,$9,$A,$B,$C,$D,$E +;.byte $0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E,$F diff --git a/demos/second/pt3_lib_irq_handler.s b/demos/second/pt3_lib_irq_handler.s new file mode 100644 index 00000000..851a22bf --- /dev/null +++ b/demos/second/pt3_lib_irq_handler.s @@ -0,0 +1,116 @@ + + +pt3_irq_handler: + +pt3_irq_smc1: + bit MOCK_6522_T1CL ; clear 6522 interrupt by reading T1C-L ; 4 + + lda DONE_PLAYING ; 3 + beq pt3_play_music ; if song done, don't play music ; 3/2nt + jmp done_pt3_irq_handler ; 3 + ;============ + ; 13 + +pt3_play_music: + + ; decode a frame of music + + jsr pt3_make_frame + + ; handle song over condition + lda DONE_SONG + beq mb_write_frame ; if not done, continue + + lda LOOP ; see if looping + beq move_to_next + +pt3_loop_smc: + lda #$d1 ; looping, move to loop location + ; non-zero to avoid the temptation + ; to merge with following lda #$0 + sta current_pattern_smc+1 + lda #$0 + sta current_line_smc+1 + sta current_subframe_smc+1 + sta DONE_SONG ; undo the next song + + beq done_pt3_irq_handler ; branch always + +move_to_next: + ; same as "press right" + ldx #$20 + jmp quiet_exit + + ;====================================== + ; Write frames to Mockingboard + ;====================================== + ; for speed could merge this into + ; the decode code + +mb_write_frame: + + + tax ; set up reg count ; 2 + ;============ + ; 2 + + ;================================== + ; loop through the 14 registers + ; reading the value, then write out + ;================================== + +mb_write_loop: + lda AY_REGISTERS,X ; load register value ; 4 + + ; 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 mb_skip_13 ; 3/2nt + ;============ + ; typ 5 +mb_not_13: + + + ; address +pt3_irq_smc2: + stx MOCK_6522_ORA1 ; put address on PA1 ; 4 + stx MOCK_6522_ORA2 ; put address on PA2 ; 4 + ldy #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2 +pt3_irq_smc3: + sty MOCK_6522_ORB1 ; latch_address on PB1 ; 4 + sty MOCK_6522_ORB2 ; latch_address on PB2 ; 4 + ldy #MOCK_AY_INACTIVE ; go inactive ; 2 +pt3_irq_smc4: + sty MOCK_6522_ORB1 ; 4 + sty MOCK_6522_ORB2 ; 4 + + ; value +pt3_irq_smc5: + sta MOCK_6522_ORA1 ; put value on PA1 ; 4 + sta MOCK_6522_ORA2 ; put value on PA2 ; 4 + lda #MOCK_AY_WRITE ; ; 2 +pt3_irq_smc6: + sta MOCK_6522_ORB1 ; write on PB1 ; 4 + sty MOCK_6522_ORB1 ; 4 +pt3_irq_smc7: + sta MOCK_6522_ORB2 ; write on PB2 ; 4 + sty MOCK_6522_ORB2 ; 4 + ;=========== + ; 56 +mb_no_write: + inx ; point to next register ; 2 + cpx #14 ; if 14 we're done ; 2 + bmi mb_write_loop ; otherwise, loop ; 3/2nt + ;============ + ; 7 +mb_skip_13: + + + ;================================= + ; Finally done with this interrupt + ;================================= + +done_pt3_irq_handler: diff --git a/demos/second/pt3_lib_mockingboard.inc b/demos/second/pt3_lib_mockingboard.inc new file mode 100644 index 00000000..80a8fdd1 --- /dev/null +++ b/demos/second/pt3_lib_mockingboard.inc @@ -0,0 +1,54 @@ +; Mockingboad programming: +; + Has two 6522 I/O chips connected to two AY-3-8910 chips +; + Optionally has some speech chips controlled via the outport on the AY +; + Often in slot 4 +; TODO: how to auto-detect? +; References used: +; http://macgui.com/usenet/?group=2&id=8366 +; 6522 Data Sheet +; AY-3-8910 Data Sheet + +;======================== +; Mockingboard card +; Essentially two 6522s hooked to the Apple II bus +; Connected to AY-3-8910 chips +; PA0-PA7 on 6522 connected to DA0-DA7 on AY +; PB0 on 6522 connected to BC1 +; PB1 on 6522 connected to BDIR +; PB2 on 6522 connected to RESET + + +; left speaker +MOCK_6522_ORB1 = $C400 ; 6522 #1 port b data +MOCK_6522_ORA1 = $C401 ; 6522 #1 port a data +MOCK_6522_DDRB1 = $C402 ; 6522 #1 data direction port B +MOCK_6522_DDRA1 = $C403 ; 6522 #1 data direction port A +MOCK_6522_T1CL = $C404 ; 6522 #1 t1 low order latches +MOCK_6522_T1CH = $C405 ; 6522 #1 t1 high order counter +MOCK_6522_T1LL = $C406 ; 6522 #1 t1 low order latches +MOCK_6522_T1LH = $C407 ; 6522 #1 t1 high order latches +MOCK_6522_T2CL = $C408 ; 6522 #1 t2 low order latches +MOCK_6522_T2CH = $C409 ; 6522 #1 t2 high order counters +MOCK_6522_SR = $C40A ; 6522 #1 shift register +MOCK_6522_ACR = $C40B ; 6522 #1 auxilliary control register +MOCK_6522_PCR = $C40C ; 6522 #1 peripheral control register +MOCK_6522_IFR = $C40D ; 6522 #1 interrupt flag register +MOCK_6522_IER = $C40E ; 6522 #1 interrupt enable register +MOCK_6522_ORANH = $C40F ; 6522 #1 port a data no handshake + + +; right speaker +MOCK_6522_ORB2 = $C480 ; 6522 #2 port b data +MOCK_6522_ORA2 = $C481 ; 6522 #2 port a data +MOCK_6522_DDRB2 = $C482 ; 6522 #2 data direction port B +MOCK_6522_DDRA2 = $C483 ; 6522 #2 data direction port A + +; AY-3-8910 commands on port B +; RESET BDIR BC1 +MOCK_AY_RESET = $0 ; 0 0 0 +MOCK_AY_INACTIVE = $4 ; 1 0 0 +MOCK_AY_READ = $5 ; 1 0 1 +MOCK_AY_WRITE = $6 ; 1 1 0 +MOCK_AY_LATCH_ADDR = $7 ; 1 1 1 + + diff --git a/demos/second/pt3_lib_mockingboard_detect.s b/demos/second/pt3_lib_mockingboard_detect.s new file mode 100644 index 00000000..cd36df72 --- /dev/null +++ b/demos/second/pt3_lib_mockingboard_detect.s @@ -0,0 +1,222 @@ +;=================================================================== +; code to detect mockingboard +;=================================================================== +; this isn't always easy +; my inclination is to just assume slot #4 but that isn't always realistic + +; code below based on "hw.mockingboard.a" from "Total Replay" + +;license:MIT +; By Andrew Roughan +; in the style of 4am for Total Replay +; +; Mockingboard support functions +; + +;------------------------------------------------------------------------------ +; HasMockingboard +; detect Mockingboard card by searching for 6522 timers across all slots +; access 6522 timers with deterministic cycle counts +; +; based on prior art in Mockingboard Developers Toolkit +; with optimisation from deater/french touch +; also takes into account FastChip //e clock difference +; +; in: none +; accelerators should be off +; out: C set if Mockingboard found in any slot +; if card was found, X = #$Cn where n is the slot number of the card +; C clear if no Mockingboard found +; other flags clobbered +; A/Y clobbered +;------------------------------------------------------------------------------ + +mockingboard_detect: + + ; activate Mockingboard IIc + ; + the Mockingboard has to take over Slot#4 (IIc has no slots) + ; in theory any write to the firmware area in $C400 will + ; activate it, but that might not be fast enough when detecting + ; so writing $FF to $C403/$C404 is official way to enable + ; + Note this disables permanently the mouse firmware in $C400 + ; so "normal" interrupts are broken :( The hack to fix things + ; is to switch in RAM for $F000 and just replace the IRQ + ; vectors at $FFFE/$FFFF instead of $3FE/$3FF but that makes + ; it difficult if you actually wanted to use any + ; Applesoft/Monitor ROM routines + +.ifdef PT3_ENABLE_APPLE_IIC + lda APPLEII_MODEL + cmp #'C' + bne not_iic + + lda #$ff + + ; don't bother patching these, IIc mockingboard always slot 4 + + sta MOCK_6522_DDRA1 ; $C403 + sta MOCK_6522_T1CL ; $C404 +.endif + +not_iic: + lda #$00 + sta MB_ADDR_L + ldx #$C7 ; start at slot #7 +mb_slot_loop: + stx MB_ADDR_H + ldy #$04 ; 6522 #1 $Cx04 + jsr mb_timer_check + bne mb_next_slot + ldy #$84 ; 6522 #2 $Cx84 + jsr mb_timer_check + bne mb_next_slot +mb_found: + sec ; found + rts + +mb_next_slot: + dex + cpx #$C0 + bne mb_slot_loop + + clc ; not found + rts + +mb_timer_check: + lda (MB_ADDR_L),Y ; read 6522 timer low byte + sta MB_VALUE + lda (MB_ADDR_L),Y ; second time + sec + sbc MB_VALUE + cmp #$F8 ; looking for (-)8 cycles between reads + beq mb_timer_check_done + cmp #$F7 ; FastChip //e clock is different +mb_timer_check_done: + rts + + + +.if 0 + + + ;======================================= + ; Detect a Mockingboard card + ;======================================= + ; Based on code from the French Touch "Pure Noise" Demo + ; Attempts to time an instruction sequence with a 6522 + ; + ; If found, puts in bMB + ; MB_ADDRL:MB_ADDRH has address of Mockingboard + ; returns X=0 if not found, X=1 if found + +mockingboard_detect: + lda #0 + sta MB_ADDRL + +mb_detect_loop: ; self-modifying + lda #$07 ; we start in slot 7 ($C7) and go down to 0 ($C0) + ora #$C0 ; make it start with C + sta MB_ADDRH + ldy #04 ; $CX04 + ldx #02 ; 2 tries? +mb_check_cycle_loop: + lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) + ; count down + sta PT3_TEMP ; 3 cycles + lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles + ; between the two accesses to the timer + sec + sbc PT3_TEMP ; subtract to see if we had 8 cycles + cmp #$f8 ; -8 + bne mb_not_in_this_slot + dex ; decrement, try one more time + bne mb_check_cycle_loop ; loop detection + inx ; Mockingboard found (X=1) +done_mb_detect: + ;stx bMB ; store result to bMB + rts ; return + +mb_not_in_this_slot: + dec mb_detect_loop+1 ; decrement the "slot" (self_modify) + bne mb_detect_loop ; loop down to one + ldx #00 + beq done_mb_detect + +;alternative MB detection from Nox Archaist +; lda #$04 +; sta MB_ADDRL +; ldx #$c7 +; +;find_mb: +; stx MB_ADDRH +; +; ;detect sound I +; +; sec +; ldy #$00 +; lda (MB_ADDRL), y +; sbc (MB_ADDRL), y +; cmp #$05 +; beq found_mb +; dex +; cpx #$c0 +; bne find_mb +; ldx #$00 ;no mockingboard found +; rts +; +;found_mb: +; ldx #$01 ;mockingboard found +; rts +; +; ;optionally detect sound II +; +; sec +; ldy #$80 +; lda (MB_ADDRL), y +; sbc (MB_ADDRL), y +; cmp #$05 +; beq found_mb + + + ;======================================= + ; Detect a Mockingboard card in Slot4 + ;======================================= + ; Based on code from the French Touch "Pure Noise" Demo + ; Attempts to time an instruction sequence with a 6522 + ; + ; MB_ADDRL:MB_ADDRH has address of Mockingboard + ; returns X=0 if not found, X=1 if found + +mockingboard_detect_slot4: + lda #0 + sta MB_ADDRL + +mb4_detect_loop: ; self-modifying + lda #$04 ; we're only looking in Slot 4 + ora #$C0 ; make it start with C + sta MB_ADDRH + ldy #04 ; $CX04 + ldx #02 ; 2 tries? +mb4_check_cycle_loop: + lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) + ; count down + sta PT3_TEMP ; 3 cycles + lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles + ; between the two accesses to the timer + sec + sbc PT3_TEMP ; subtract to see if we had 8 cycles + cmp #$f8 ; -8 + bne mb4_not_in_this_slot + dex ; decrement, try one more time + bne mb4_check_cycle_loop ; loop detection + inx ; Mockingboard found (X=1) +done_mb4_detect: + rts ; return + +mb4_not_in_this_slot: + ldx #00 + beq done_mb4_detect + + + +.endif diff --git a/demos/second/pt3_lib_mockingboard_patch.s b/demos/second/pt3_lib_mockingboard_patch.s new file mode 100644 index 00000000..89665c64 --- /dev/null +++ b/demos/second/pt3_lib_mockingboard_patch.s @@ -0,0 +1,120 @@ + +;=================================================================== +; code to patch mockingboard if not in slot#4 +;=================================================================== +; this is the brute force version, we have to patch 39 locations +; see further below if you want to try a smaller, more dangerous, patch + +.if 0 +mockingboard_patch: + + lda MB_ADDR_H + + sta pt3_irq_smc1+2 ; 1 + + sta pt3_irq_smc2+2 ; 2 + sta pt3_irq_smc2+5 ; 3 + + sta pt3_irq_smc3+2 ; 4 + sta pt3_irq_smc3+5 ; 5 + + sta pt3_irq_smc4+2 ; 6 + sta pt3_irq_smc4+5 ; 7 + + sta pt3_irq_smc5+2 ; 8 + sta pt3_irq_smc5+5 ; 9 + + sta pt3_irq_smc6+2 ; 10 + sta pt3_irq_smc6+5 ; 11 + + sta pt3_irq_smc7+2 ; 12 + sta pt3_irq_smc7+5 ; 13 + + sta mock_init_smc1+2 ; 14 + sta mock_init_smc1+5 ; 15 + + sta mock_init_smc2+2 ; 16 + sta mock_init_smc2+5 ; 17 + + sta reset_ay_smc1+2 ; 18 + sta reset_ay_smc2+2 ; 19 + sta reset_ay_smc3+2 ; 20 + sta reset_ay_smc4+2 ; 21 + + sta write_ay_smc1+2 ; 22 + sta write_ay_smc1+5 ; 23 + + sta write_ay_smc2+2 ; 24 + sta write_ay_smc2+5 ; 25 + + sta write_ay_smc3+2 ; 26 + sta write_ay_smc3+5 ; 27 + + sta write_ay_smc4+2 ; 28 + sta write_ay_smc4+5 ; 29 + + sta write_ay_smc5+2 ; 30 + sta write_ay_smc5+5 ; 31 + + sta write_ay_smc6+2 ; 32 + sta write_ay_smc6+5 ; 33 + + sta setup_irq_smc1+2 ; 34 + sta setup_irq_smc2+2 ; 35 + sta setup_irq_smc3+2 ; 36 + sta setup_irq_smc4+2 ; 37 + sta setup_irq_smc5+2 ; 38 + sta setup_irq_smc6+2 ; 39 + + rts +.endif + +;=================================================================== +; dangerous code to patch mockingboard if not in slot#4 +;=================================================================== +; this code patches any $C4 value to the proper slot# if not slot4 +; this can be dangerous, it might over-write other important values +; that should be $C4 + +; safer ways to do this: +; only do this if 2 bytes after a LDA/STA/LDX/STX +; count total and if not 39 then print error message + +mockingboard_patch: + ; from mockingboard_init $1BBF + ; to done_pt3_irq_handler $1D85 + + ldx MB_ADDR_H + ldy #0 + + lda #mockingboard_init + sta MB_ADDR_H + +mb_patch_loop: + lda (MB_ADDR_L),Y + cmp #$C4 + bne mb_patch_nomatch + + txa + sta (MB_ADDR_L),Y +mb_patch_nomatch: + + ; 16-bit increment + + inc MB_ADDR_L + bne mb_patch_oflo + inc MB_ADDR_H + +mb_patch_oflo: + lda MB_ADDR_H + cmp #>done_pt3_irq_handler + bne mb_patch_loop + lda MB_ADDR_L + cmp # Latch Address -> Inactive -> Write Data -> Inactive + + ;========================================= + ; Write Right/Left to save value AY-3-8910 + ;========================================= + ; register in X + ; value in MB_VALUE + +write_ay_both: + ; address + +write_ay_smc1: + stx MOCK_6522_ORA1 ; put address on PA1 ; 4 + stx MOCK_6522_ORA2 ; put address on PA2 ; 4 + lda #MOCK_AY_LATCH_ADDR ; latch_address on PB1 ; 2 +write_ay_smc2: + sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4 + sta MOCK_6522_ORB2 ; latch_address on PB2 ; 4 + ldy #MOCK_AY_INACTIVE ; go inactive ; 2 +write_ay_smc3: + sty MOCK_6522_ORB1 ; 4 + sty MOCK_6522_ORB2 ; 4 + ;=========== + ; 28 + ; value + lda MB_VALUE ; 3 +write_ay_smc4: + sta MOCK_6522_ORA1 ; put value on PA1 ; 4 + sta MOCK_6522_ORA2 ; put value on PA2 ; 4 + lda #MOCK_AY_WRITE ; ; 2 +write_ay_smc5: + sta MOCK_6522_ORB1 ; write on PB1 ; 4 + sta MOCK_6522_ORB2 ; write on PB2 ; 4 +write_ay_smc6: + sty MOCK_6522_ORB1 ; 4 + sty MOCK_6522_ORB2 ; 4 + ;=========== + ; 29 + + rts ; 6 + ;=========== + ; 63 +write_ay_both_end: +;.assert >write_ay_both = >write_ay_both_end, error, "write_ay_both crosses page" + + ;======================================= + ; clear ay -- clear all 14 AY registers + ; should silence the card + ;======================================= + ; 7+(74*14)+5=1048 +clear_ay_both: + ldx #13 ; 2 + lda #0 ; 2 + sta MB_VALUE ; 3 +clear_ay_left_loop: + jsr write_ay_both ; 6+63 + dex ; 2 + bpl clear_ay_left_loop ; 3 + ; -1 + rts ; 6 + +clear_ay_end: +;.assert >clear_ay_both = >clear_ay_end, error, "clear_ay_both crosses page" + + ;============================= + ; Setup + ;============================= +mockingboard_setup_interrupt: + + + ; for this game with things in language card including + ; irq handler, always force IIc mode (where RAM swapped in + ; and we put the irq handler address directly up at $FFFE) + + lda #interrupt_handler + sta $ffff + + ; nop out the "lda $45" since we are bypassing the ROM irq handler + ; that puts A in $45 + lda #$EA + sta interrupt_smc + sta interrupt_smc+1 + + + ;========================= + ; Setup Interrupt Handler + ;========================= + ; Vector address goes to 0x3fe/0x3ff + ; FIXME: should chain any existing handler + +; lda #interrupt_handler +; sta $03ff + + ;============================ + ; Enable 50Hz clock on 6522 + ;============================ + + + ; Note, on Apple II the clock isn't 1MHz but is actually closer to + ; roughly 1.023MHz, and every 65th clock is stretched (it's complicated) + + ; 4fe7 / 1.023e6 = .020s, 50Hz + ; 9c40 / 1.023e6 = .040s, 25Hz + ; 411a / 1.023e6 = .016s, 60Hz + + ; French Touch uses + ; 4e20 / 1.000e6 = .020s, 50Hz, which assumes 1MHz clock freq + + sei ; disable interrupts just in case + + lda #$40 ; Continuous interrupts, don't touch PB7 +setup_irq_smc1: + sta MOCK_6522_ACR ; ACR register + lda #$7F ; clear all interrupt flags +setup_irq_smc2: + sta MOCK_6522_IER ; IER register (interrupt enable) + + lda #$C0 +setup_irq_smc3: + sta MOCK_6522_IFR ; IFR: 1100, enable interrupt on timer one oflow +setup_irq_smc4: + sta MOCK_6522_IER ; IER: 1100, enable timer one interrupt + + lda #$E7 +; lda #$20 +setup_irq_smc5: + sta MOCK_6522_T1CL ; write into low-order latch + lda #$4f +; lda #$4E +setup_irq_smc6: + sta MOCK_6522_T1CH ; write into high-order latch, + ; load both values into counter + ; clear interrupt and start counting + + rts + + + + ;============================= + ; Disable Interrupt + ;============================= +mockingboard_disable_interrupt: + + sei ; disable interrupts just in case + + lda #$40 ; Continuous interrupts, don't touch PB7 +disable_irq_smc1: + sta MOCK_6522_ACR ; ACR register + lda #$7F ; clear all interrupt flags +disable_irq_smc2: + sta MOCK_6522_IER ; IER register (interrupt enable) + + rts + diff --git a/demos/second/qboot_sector.s b/demos/second/qboot_sector.s new file mode 100644 index 00000000..2b3901b1 --- /dev/null +++ b/demos/second/qboot_sector.s @@ -0,0 +1,244 @@ +; fast seek/multi-read +; copyright (c) Peter Ferrie 2015-16 + + ; Paramaters for loading QLOAD + + sectors = 14 ; user-defined + firsttrk = 1 ; user-defined, first track to read + firstsec = 0 ; user-defined, first sector to read + address = $12 ; user-defined + entry = $1200 ; user-defined + version = 1 + + ;memory usage: + ;256 bytes ($200-2ff) static table + grouped = $200 + + ; stay away from interrupt vectors at $3fe !!! + + ;106 bytes ($300-369) static table + preshift = $300 + zvalue = $fd ; only during init + znibble = $fe ; only during init + zmask = $ff ; only during init + + WHICH_SLOT = $DA + +; $26/$27 sector read location (ROM) +; $3D sector number (ROM) + + +; at entry (at least on AppleWin) A=1, X=60 (slot<<4), Y=0 +; qkumba says cffa cards leave Y at $10 +; 26/27 = 00/09 +; 3D = 1 + + ; For Disk II booting, the firmware loads track0/sector0 + ; to $800 and then jumps to $801 + +.org $800 + .byte 1 ; number of sectors for ROM to load + +boot_entry: + ; this code loads two sectors up to $10/$11 + + ; assume A=1 coming in here + + lsr ; check sector number + ; A=0, carry=1 + tay ; Y=0 + adc #$0f ; A=$10 (destintation) + + sta $27 ; set or update address as needed + cmp #$12 + ; 10 11 12 (1 1 1) + ; be, bf, c0 (1011 1011 1100) + ; so if hit $c000 we are done + + beq done_load_2 ; branch if loaded 2 + + inc $3d ; increment sector (faster to find) + + ; call to the read routine in proper slot + ; using rts to jump indirect to + ; $CX5C + + ; this routine reads sector in $3D on track in $41 + ; to address in $26/$27 + ; when it's done it jumps back to $801 + stx WHICH_SLOT ; save for later + + txa ; x is slot# << 4 + lsr + lsr + lsr + lsr + ora #$c0 ; slot to PROM base + pha + lda #$5b ;read-1 + pha + rts ; return used to call $CX5C in DISK II ROM + +done_load_2: + + ; patch self modifying code for Q6L read + + txa + ora #$8c ; slot to Q6L + ; Q6L? + ; if slot 6, after this A is $EC + ; Y should be 2 here +patch_loop: + iny + ldx patchtbl-3, Y + sta code_begin, X ; replace placeholders with Q6L + ; BE02 = EC? lda c0ec + ; so sets to c08c (Q6L) + + bne patch_loop + + ; patch self-modifying code for turning motor off + + and #$f8 ; MOTOROFF (c088) -> c0e8 + sta slotpatch7+1 + + ; patch self-modifying code for turning motor on + clc + adc #1 ; MOTORON (c089) -> c0e9 + sta slotpatch9+1 + + ; patch self-modifying code for phase off + + eor #9 ; PHASEOFF (c080) + sta slotpatch8+1 + + ldx #$3f + stx zmask + inx + ldy #$7f + + bne skip_ahead ; branch always + + ; pad with zeros until $839 + ; $839 is the entry point + ; adjusts address at $8FE to be entry point + ; jumps to boot 2 +;.res $839-* + +; lda #>(entry-1) +; pha +; lda #<(entry-1) +; pha +; jsr preread +; jmp $1000 ; stage2 entry point + +patchtbl: + .byte <(slotpatch1+1), <(slotpatch2+1), <(slotpatch3+1) + .byte <(slotpatch4+1), <(slotpatch5+1), <(slotpatch6+1) +indextbl: ;the 0 also terminates the patchtbl list! + .byte 0, 2, 1, 3 + + + ;construct denibbilisation table + ;pre-shifted for interleave read + +skip_ahead: +loopaa: + sty znibble + tya + asl + bit znibble + beq loopz + ora znibble + eor #$ff + and #$7e +loopa: + bcs loopz + lsr + bne loopa + dex + txa + asl + asl + sta preshift-$16, Y +loopz: + dey + bne loopaa + + ;construct 2-bit group table + + sty zvalue +loopbb: + lsr zmask + lsr zmask +loopb: + lda indextbl, X + sta grouped, Y + inc zvalue + lda zvalue + and zmask + bne loopy + inx + txa + and #3 + tax +loopy: + iny + iny + iny + iny + cpy #3 + bcs loopb + iny + cpy #3 + bcc loopbb + lda #>(entry-1) + pha + lda #<(entry-1) + pha + jsr preread + + ; seek backward support +; sty startsec+1 +; sta tmpadr+1 +; stx total+1 + + jmp seekread + +preread: + +;copy post-read if necessary +;push post-read address here +; pla +; tax +; pla +; tay +; lda #>(postread-1) +; pha +; lda #<(postread-1) +; pha +; tya +; pha +; txa +; pha + + lda #<(firsttrk*2) + sta phase+1 + ldx #sectors + lda #address + ldy #firstsec + rts + + + +end_code: + +.res $8fe-* + +; traditionally, entry point to jump to at end of loading +; $1000 in this case +;*=$8fe + .byte $10, $00 + + +.include "qboot_stage2.s" diff --git a/demos/second/qboot_stage2.s b/demos/second/qboot_stage2.s new file mode 100644 index 00000000..6a38148f --- /dev/null +++ b/demos/second/qboot_stage2.s @@ -0,0 +1,382 @@ +; the following lives on sectors $0E and $0D +; why? +; request sector 2 and 4, and the interleave is + +; beneath apple dos (3-23) +; Physical (firmware) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +; DOS33 mapping : 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 + + +; Beneath Apple DOS +; p86 (dos reference) +; + +;WAIT = $FCA8 ;; delay 1/2(26+27A+5A^2) us + +WAIT = norom_wait + +.org $1000 + +code_begin: + + .byte version + +readnib: +slotpatch1: ; smc + lda $c0d1 ; gets set to C08C (Q6L) read + bpl readnib + rts + + ;fill address array for one track +seekread: + sty startsec+1 + sta tmpadr+1 + stx total+1 + +inittrk: + sec + lda #$10 + sbc startsec+1 + cmp total+1 + bcs it_skip + + tax + +it_skip: + stx partial1 + stx partial2 + jsr seek + +startsec: + ldy #$d1 + +tmpadr: +tmpadr_loop: + lda #$d1 + sta addrtbl, y + inc tmpadr+1 + iny + dec partial1 + bne tmpadr_loop + + ;==================================== + ; read a sector + ;==================================== + ; first address field + ;==================================== + ; starts with $D5 $AA $96 + ; then XX YY volume + ; then XX YY track + ; then XX YY sector + ; then XX YY checksum + ; then ends with $DE $AA $EB + ;==================================== + ; data field + ;==================================== + ; starts with $D5 $AA $AD + ; 342 bytes of data + ; XX checksum + ; ends with $DE $AA $EB +read: + +outer_read: + jsr readnib +inner_read: + cmp #$d5 ; look for $D5 part of addr field + bne outer_read + + jsr readnib ; look for $D5 $AA + cmp #$aa + bne inner_read + + ; look for $D5 $AA $AD + + tay ; we need Y=#$AA later + jsr readnib + eor #$ad ; zero A if match + beq check_mode + + ; if not #$AD, then #$96 is assumed + ; so in address field + + ldy #2 ; volume, track, sector +another: + jsr readnib + rol ; set carry + sta sector+1 + jsr readnib + and sector+1 + dey + bpl another + + tay + ldx addrtbl, Y ; fetch corresponding address + beq read ; done? + + sta sector+1 ; store index for later + + stx adrpatch1+2 + stx adrpatch8+2 + stx adrpatch2+2 + stx adrpatch3+2 + stx adrpatch5+2 + stx adrpatch7+2 + + inx + stx adrpatch9+2 + dex + + dex + stx adrpatch4+2 + stx adrpatch6+2 + + ldy #$fe + +loop2: +adrpatch1: + lda $d102, Y + pha + iny + bne loop2 + +branch_read: + bcs read ; branch always + +check_mode: + cpx #0 + beq read ; loop if not expecting #$AD + +loop33: + sta tmpval+1 ; zero rolling checksum +slotpatch2: +loop4: + ldx $c0d1 + bpl loop4 + lda preshift-$96, X +adrpatch2: + sta $d102, Y ; store 2-bit array + +tmpval: + eor #$d1 + iny + bne loop33 + ldy #$aa +slotpatch3: +loop5: + ldx $c0d1 + bpl loop5 + eor preshift-$96, X +adrpatch3: + ldx $d102, Y ; bit2tbl + eor grouped+2, X ; first 86 nibbles use group bits 0-1 +adrpatch4: + sta $d156, y + iny + bne loop5 + and #$fc + ldy #$aa +slotpatch4: +loop6: + ldx $c0d1 + bpl loop6 + eor preshift-$96, X +adrpatch5: + ldx $d102, Y ; bit2tbl + eor grouped+1, X ; second 86 nibbles use group bits 2-3 +adrpatch6: + sta $d1ac, Y + iny + bne loop6 + and #$fc + ldx #$ac +slotpatch5: +loop7: + ldy $c0d1 + bpl loop7 + eor preshift-$96, Y +adrpatch7: + ldy $d100, X ; bit2tbl + eor grouped, Y ; last 84 nibbles use group bits 4-5 +adrpatch8: + sta $d100, x + inx + bne loop7 + and #$fc +slotpatch6: +loop8: + ldy $c0d1 + bpl loop8 + eor preshift-$96, Y + cmp #1 ; carry = !zero + ldy #1 +loop9: + pla +adrpatch9: + sta $d100, Y + dey + bpl loop9 +branch_read2: + bcs branch_read ; branch if checksum failure + +sector: + ldy #$d1 + txa + sta addrtbl, Y ; zero corresponding address + dec total+1 + dec partial2 ; adjust remaining count + ; (faster than looping over array) + sec + bne branch_read2 ; read all requested sectors in one track + + sta startsec+1 ; this was missing from original code + ; leading to trouble on wrap around + ; it not starting at sector0 +total: + ldx #$d1 + beq driveoff + inc phase+1 + inc phase+1 ; update current track + jmp inittrk + +driveoff: +slotpatch7: + lda $c0d1 + +seekret: + rts + +seek: + ldx #0 + stx step+1 +copy_cur: +curtrk: + lda #0 + sta tmpval+1 + sec +phase: + sbc #$d1 + beq seekret + + ; if seek backwards + bcs sback + + eor #$ff + inc curtrk+1 + + bcc ssback +sback: + adc #$fe + dec curtrk+1 +ssback: + cmp step+1 + bcc loop10 +step: + lda #$d1 +loop10: + cmp #8 + bcs loop11 + tay + sec +loop11: + lda curtrk+1 + ldx step1, Y + bne loop12 +loopmmm: + clc + lda tmpval+1 + ldx step2, Y +loop12: + stx sector+1 + and #3 + rol + tax +slotpatch8: + sta $c0d1, X +loopmm: + ldx #$13 +loopm: + dex + bne loopm + dec sector+1 + bne loopmm + lsr + bcs loopmmm + inc step+1 + bne copy_cur + +step1: .byte 1, $30, $28, $24, $20, $1e, $1d, $1c +step2: .byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c +addrtbl: .res 16 + +partial1: .byte $00 +partial2: .byte $00 +code_end: + + +;========================== +; enable drive motor +;========================== + +driveon: + +slotpatch9: + lda $c0d1 + + ; wait 1s + + ldx #6 +wait_1s: + lda #255 + jsr WAIT + dex + bne wait_1s + + rts + +load_new: + + jsr driveon + + lda load_track + asl ; track to start*2 + sta phase+1 + + lda load_sector + tay ; sector to start + + lda load_length ; length + tax + + lda load_address ; address to load + + jsr seekread + + rts + +load_address: + .byte $00 +load_track: + .byte $00 +load_sector: + .byte $00 +load_length: + .byte $00 + + + +; copy of ROM wait +; because we might disable ROM + +norom_wait: + sec +wait2: + pha +wait3: + sbc #$01 + bne wait3 + pla + sbc #$01 + bne wait2 + rts +wait_end: + diff --git a/demos/second/qload.s b/demos/second/qload.s new file mode 100644 index 00000000..8646d4a8 --- /dev/null +++ b/demos/second/qload.s @@ -0,0 +1,194 @@ +; Loader + +.include "zp.inc" +.include "hardware.inc" + +;.include "common_defines.inc" +.include "qboot.inc" + +qload_start: + + ; init the write code +; lda WHICH_SLOT +; jsr popwr_init + + ; first time entry + ; start by loading text title + + lda #0 ; load ZW engine + sta WHICH_LOAD + + lda #1 + sta CURRENT_DISK ; current disk number + + jsr load_file + + jmp $6000 ; jump to ZW + + ;==================================== + ; loads file specified by WHICH_LOAD + ;==================================== +load_file: + ldx WHICH_LOAD + + lda which_disk_array,X + cmp CURRENT_DISK + bne change_disk + +load_file_no_diskcheck: + lda load_address_array,X + sta load_address + + lda track_array,X + sta load_track + + lda sector_array,X + sta load_sector + + lda length_array,X + sta load_length + + jsr load_new + + rts + + ;=================================================== + ;=================================================== + ; change disk + ;=================================================== + ;=================================================== + +change_disk: +.if 0 + ; turn off disk drive light + + jsr driveoff + + jsr TEXT + jsr HOME + + lda #error_string + sta OUTH + + ldx WHICH_LOAD + lda which_disk_array,X + clc + adc #48 + + ldy #19 + sta (OUTL),Y + + ldy #0 + +quick_print: + lda (OUTL),Y + beq quick_print_done + jsr COUT1 + iny + jmp quick_print + +quick_print_done: + +fnf_keypress: + lda KEYPRESS + bpl fnf_keypress + bit KEYRESET + + ;============================================== + ; actually verify proper disk is there + ; read T0:S0 and verify proper disk + + lda WHICH_LOAD + pha + + ldx #LOAD_FIRST_SECTOR ; load track 0 sector 0 + stx WHICH_LOAD + + jsr load_file_no_diskcheck + + pla + sta WHICH_LOAD + tax + + ; first sector now in $c00 + ; offset 59 + ; disk1 = $0a + ; disk2 = $32 ('2') + ; disk3 = $33 ('3') + + lda $c59 + cmp #$0a + beq is_disk1 + cmp #$32 + beq is_disk2 + cmp #$33 + beq is_disk3 + bne change_disk ; unknown disk + +is_disk1: + lda #1 + bne disk_compare + +is_disk2: + lda #2 + bne disk_compare + +is_disk3: + lda #3 + +disk_compare: + cmp which_disk_array,X + bne change_disk ; disk mismatch + + ;============================================== + ; all good, retry original load + + jsr HOME + + ldx WHICH_LOAD + lda which_disk_array,X + sta CURRENT_DISK + + jmp load_file + +; offset for disk number is 19 +error_string: +.byte "PLEASE INSERT DISK 1, PRESS RETURN",0 + +.endif + +which_disk_array: + .byte 1,1,1,1 ; ZW, MUSIC, ?, ? + +load_address_array: + .byte $60,$D0,$90,$90 ; ZW, MUSIC, ?, ? + +track_array: + .byte 5, 3, 9,12 ; ZW, MUSIC, ?, ? + +sector_array: + .byte 0, 0, 0, 0 ; ZW, MUSIC, ?, ? + +length_array: + .byte 80, 32, 48, 48 ; ZW, MUSIC, ?, ? + + .include "lc_detect.s" + .include "wait.s" + .include "wait_a_bit.s" + .include "gr_fast_clear.s" + .include "text_print.s" + .include "gr_offsets.s" + +; .include "pt3_lib_mockingboard_patch.s" + .include "pt3_lib_detect_model.s" +; .include "pt3_lib_core.s" +; .include "pt3_lib_init.s" +; .include "pt3_lib_mockingboard_setup.s" +; .include "interrupt_handler.s" + .include "pt3_lib_mockingboard_detect.s" + +qload_end: + +.assert (>qload_end - >qload_start) < $e , error, "loader too big" diff --git a/demos/second/second.s b/demos/second/second.s new file mode 100644 index 00000000..f489c7fc --- /dev/null +++ b/demos/second/second.s @@ -0,0 +1,358 @@ +; Unwisely messing with Second Reality + +; +; by deater (Vince Weaver) + +.include "zp.inc" +.include "hardware.inc" +.include "qload.inc" +.include "music.inc" + +second_start: + ;===================== + ; initializations + ;===================== + + ;===================== + ; detect model + ;===================== + + jsr detect_appleii_model + + ;===================== + ; Machine workarounds + ;===================== + ; mostly IIgs + ; thanks to 4am for this code from total replay + + lda ROM_MACHINEID + cmp #$06 + bne not_a_iigs + sec + jsr $FE1F ; check for IIgs + bcs not_a_iigs + + ; gr/text page2 handling broken on early IIgs models + ; this enables the workaround + + jsr ROM_TEXT2COPY ; set alternate display mode on IIgs + cli ; enable VBL interrupts + + ; also set background color to black instead of blue + lda NEWVIDEO + and #%00011111 ; bit 7 = 0 -> IIgs Apple II-compat video modes + ; bit 6 = 0 -> IIgs 128K memory map same as IIe + ; bit 5 = 0 -> IIgs DHGR is color, not mono + ; bits 0-4 unchanged + sta NEWVIDEO + lda #$F0 + sta TBCOLOR ; white text on black background + lda #$00 + sta CLOCKCTL ; black border + sta CLOCKCTL ; set twice for VidHD + +not_a_iigs: + + + ;=================== + ; restart? + ;=================== +restart: + lda #0 + sta DRAW_PAGE + + ;=================== + ; show title screen + ;=================== + + jsr show_title + + + ;=================== + ; print config + ;=================== + + jsr set_normal + + lda #config_string + sta OUTH + + jsr move_and_print + + ; print detected model + + lda APPLEII_MODEL + ora #$80 + sta $7d0+8 ; 23,8 + + ; if GS print the extra S + cmp #'G'|$80 + bne not_gs + lda #'S'|$80 + sta $7d0+9 + +not_gs: + + ;========================================= + ; detect if we have a language card (64k) + ;=================================== + ; we might want to later load sound high, + ; for now always enable sound + + + lda #0 + sta SOUND_STATUS ; clear out, sound enabled + + jsr detect_language_card + bcs no_language_card + +yes_language_card: + ; update status on title screen + lda #'6'|$80 + sta $7d0+11 ; 23,11 + lda #'4'|$80 + sta $7d0+12 ; 23,12 + + ; update sound status + lda SOUND_STATUS + ora #SOUND_IN_LC + sta SOUND_STATUS + +; jmp done_language_card + +no_language_card: + +done_language_card: + + ;=================================== + ; Detect Mockingboard + ;=================================== + + ; detect mockingboard + jsr mockingboard_detect + + bcc mockingboard_notfound + +mockingboard_found: + ; print detected location + + lda #'S'+$80 ; change NO to slot + sta $7d0+30 + + lda MB_ADDR_H ; $C4 = 4, want $B4 1100 -> 1011 + and #$87 + ora #$30 + + sta $7d0+31 ; 23,31 + + + ; for now, don't require language card + lda SOUND_STATUS + and #SOUND_IN_LC + beq dont_enable_mc + + lda SOUND_STATUS + ora #SOUND_MOCKINGBOARD + sta SOUND_STATUS + + ;================================== + ; load sound into the language card + ; into $D000 set 1 + ;================================== + + ; read/write RAM, use $d000 bank1 + bit $C083 + bit $C083 + + lda #1 + sta WHICH_LOAD + + jsr load_file + + lda #0 + sta DONE_PLAYING + + lda #1 + sta LOOP + + ; patch mockingboard + + jsr mockingboard_patch ; patch to work in slots other than 4? + + ;======================= + ; Set up 50Hz interrupt + ;======================== + + jsr mockingboard_init + jsr mockingboard_setup_interrupt + + ;============================ + ; Init the Mockingboard + ;============================ + + jsr reset_ay_both + jsr clear_ay_both + + ;================== + ; init song + ;================== + + jsr pt3_init_song + + + + + +dont_enable_mc: + +mockingboard_notfound: + +skip_all_checks: + + + ;======================= + ; wait for keypress + ;======================= + +; jsr wait_until_keypress + + lda #25 + jsr wait_a_bit + + + + ;=================== + ; Load graphics + ;=================== +load_loop: + +; jsr HGR + bit SET_GR + bit HIRES + bit FULLGR + bit PAGE0 + + ;======================= + ; start music + ;======================= + + cli + + ;================================ + ; Logo + ;================================ + + jsr clear_bottom + + lda #fc_sr_logo_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + jsr wait_until_keypress + + + + ;================================ + ; MNTSCRL3 (gorilla looking guy) + ;================================ + + jsr clear_bottom + + lda #mntscrl3_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + jsr wait_until_keypress + + + ;================================ + ; FINAL3 (leaves) + ;================================ + + jsr clear_bottom + + lda #final3_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + jsr wait_until_keypress + + + + ;================================ + ; ICEKNGDM (lady on a polar bear) + ;================================ + + jsr clear_bottom + + lda #icekngdm_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + jsr wait_until_keypress + + + + + + + jmp load_loop + + + + +.align $100 + .include "wait_keypress.s" + .include "zx02_optim.s" +; .include "text_print.s" +; .include "gr_offsets.s" + + + +icekngdm_data: + .incbin "graphics/icekngdm.hgr.zx02" + +mntscrl3_data: + .incbin "graphics/mntscrl3.hgr.zx02" + +final3_data: + .incbin "graphics/final3.hgr.zx02" + +fc_sr_logo_data: + .incbin "graphics/fc_sr_logo.hgr.zx02" + + +.include "title.s" + +config_string: +; 0123456789012345678901234567890123456789 +.byte 0,23,"APPLE II?, 48K, MOCKINGBOARD: NO, SSI: N",0 + +.include "pt3_lib_mockingboard_patch.s" + diff --git a/demos/second/text_print.s b/demos/second/text_print.s new file mode 100644 index 00000000..34bae3db --- /dev/null +++ b/demos/second/text_print.s @@ -0,0 +1,93 @@ + + ;================================ + ; move_and_print + ;================================ + ; get X,Y from OUTL/OUTH + ; then print following string to that address + ; stop at NUL + ; convert to APPLE ASCII (or with 0x80) + ; leave OUTL/OUTH pointing to next string + +move_and_print: + ldy #0 + lda (OUTL),Y + sta CH + iny + lda (OUTL),Y + asl + tay + lda gr_offsets,Y ; lookup low-res memory address + clc + adc CH ; add in xpos + sta BASL ; store out low byte of addy + + lda gr_offsets+1,Y ; look up high byte + adc DRAW_PAGE ; + sta BASH ; and store it out + ; BASH:BASL now points at right place + + clc + lda OUTL + adc #2 + sta OUTL + lda OUTH + adc #0 + sta OUTH + + ;================================ + ; print_string + ;================================ + +print_string: + ldy #0 +print_string_loop: + lda (OUTL),Y + beq done_print_string +ps_smc1: + and #$3f ; make sure we are inverse + sta (BASL),Y + iny + bne print_string_loop +done_print_string: + iny + clc + tya + adc OUTL + sta OUTL + lda OUTH + adc #0 + sta OUTH + + rts + + ; set normal text +set_normal: + lda #$80 + sta ps_smc1+1 + + lda #09 ; ora + sta ps_smc1 + + rts + + ; restore inverse text +set_inverse: + lda #$29 + sta ps_smc1 + lda #$3f + sta ps_smc1+1 + + rts + + + ;================================ + ; move and print a list of lines + ;================================ + ; look for negative X meaning done +move_and_print_list: + jsr move_and_print + ldy #0 + lda (OUTL),Y + bpl move_and_print_list + + rts diff --git a/demos/second/title.s b/demos/second/title.s new file mode 100644 index 00000000..0e0fb409 --- /dev/null +++ b/demos/second/title.s @@ -0,0 +1,44 @@ + ;===================================== + ; print the title screen + ;===================================== + +show_title: + + ; clear text screen + + jsr clear_all + + ; print non-inverse + + jsr set_normal + + ; print messages + lda #title_text + sta OUTH + + ; print the text + + ldx #8 +title_loop: + + jsr move_and_print + + dex + bne title_loop + + jsr set_inverse + + rts + +; 01234567890123456789012345678901234567890 +title_text: +.byte 0, 0,"LOADING 2ND_REALITY V0.01 (15 AUG 2023)",0 +.byte 0, 5," APPLE II CODE: VINCE WEAVER",0 +.byte 0, 6," DISK : QKUMBA",0 +.byte 0, 7," ZX02 : DMSC",0 +.byte 0, 8," MUSIC: Z00M",0 +.byte 0,16," ______",0 +.byte 0,17," A \/\/\/ SOFTWARE PRODUCTION",0 +.byte 0,19," HTTP://WWW.DEATER.NET/WEAVE/VMWPROD",0 diff --git a/demos/second/wait.s b/demos/second/wait.s new file mode 100644 index 00000000..12c4319c --- /dev/null +++ b/demos/second/wait.s @@ -0,0 +1,18 @@ +; copy of ROM wait +; because we might disable ROM + + +wait: + sec +wait2: + pha +wait3: + sbc #$01 + bne wait3 + pla + sbc #$01 + bne wait2 + rts +wait_end: + +.assert (>wait_end - >wait) < 1 , error, "wait crosses page boundary" diff --git a/demos/second/wait_a_bit.s b/demos/second/wait_a_bit.s new file mode 100644 index 00000000..b953ba4a --- /dev/null +++ b/demos/second/wait_a_bit.s @@ -0,0 +1,37 @@ + ;==================================== + ; wait for keypress or a few seconds + ;==================================== + ; A is length to wait + +wait_a_bit: + + bit KEYRESET + tax + +keyloop: + lda #200 ; delay a bit + jsr wait + + lda KEYPRESS + bmi done_keyloop + + dex + bne keyloop +; beq no_escape + +done_keyloop: + +; and #$7f +; cmp #27 +; bne no_escape + +; inc ESC_PRESSED +;no_escape: + + bit KEYRESET + + rts + + + + diff --git a/demos/second/wait_keypress.s b/demos/second/wait_keypress.s new file mode 100644 index 00000000..444d2074 --- /dev/null +++ b/demos/second/wait_keypress.s @@ -0,0 +1,5 @@ +wait_until_keypress: + lda KEYPRESS ; 4 + bpl wait_until_keypress ; 3 + bit KEYRESET ; clear the keyboard buffer + rts ; 6 diff --git a/demos/second/zp.inc b/demos/second/zp.inc new file mode 100644 index 00000000..32ccffc3 --- /dev/null +++ b/demos/second/zp.inc @@ -0,0 +1,187 @@ +;; Zero Page + +;; ZX0 addresses + +ZX0_src = $00 +ZX0_dst = $02 +offset = $04 +bitr = $06 +pntr = $07 +WHICH_LOAD = $09 +CURRENT_DISK = $0A + +;; Zero page monitor routines addresses + +WNDLFT = $20 +WNDWDTH = $21 +WNDTOP = $22 +WNDBTM = $23 +CH = $24 +CV = $25 +GBASL = $26 +GBASH = $27 +BASL = $28 +BASH = $29 +H2 = $2C +V2 = $2D +MASK = $2E +COLOR = $30 + ;INVFLG = $32 + +; dos33 zero page = 26-2f, 35-38, 3e 3f 40-4d +; overlap applesoft 67-6a,6f,70,af,b0,ca-cd,d8 + + +; DOS33: Confirmed kills $68 + +RWTSL = $60 +RWTSH = $61 +DOSBUFL = $62 +DOSBUFH = $63 +FILEML = $64 +FILEMH = $65 + + +FRAME = $60 +FRAMEH = $61 +WAITING = $62 +LETTERL = $63 +LETTERH = $64 +LETTERX = $65 +LETTERY = $66 +LETTERD = $67 +LETTER = $68 +BLARGH = $69 + +; pt3 player registers +AY_REGISTERS = $70 +A_FINE_TONE = $70 +A_COARSE_TONE = $71 +B_FINE_TONE = $72 +B_COARSE_TONE = $73 +C_FINE_TONE = $74 +C_COARSE_TONE = $75 +NOISE = $76 +ENABLE = $77 +PT3_MIXER_VAL = $77 +A_VOLUME = $78 +B_VOLUME = $79 +C_VOLUME = $7A +ENVELOPE_FINE = $7B +ENVELOPE_COARSE = $7C +ENVELOPE_SHAPE = $7D +PATTERN_L = $7E +PATTERN_H = $7F + + +.if 0 +; ym player +CURRENT_FRAME_L = $70 +CURRENT_FRAME_H = $71 +BASE_FRAME_L = $72 +BASE_FRAME_H = $73 +CURRENT_CHUNK = $74 +TIME_MINUTES = $75 +TIME_SECONDS = $76 +CURSOR_X = $77 +CURSOR_Y = $78 +LEVEL_OVER = $7B + LEVEL_FAIL = 1 + LEVEL_WIN = 2 +DOOR_OPEN = $7C +CHUNK_NEXT_LOAD = $7D +CHUNK_NEXT_PLAY = $7E +LOAD_NEXT_CHUNK = $7F +.endif + + +; rest of pt3_player +; rest of pt3_player +PT3_TEMP = $80 +ORNAMENT_L = $81 +ORNAMENT_H = $82 +SAMPLE_L = $83 +SAMPLE_H = $84 +LOOP = $85 +MB_VALUE = $86 +MB_ADDR_L = $87 +MB_ADDR_H = $88 +DONE_PLAYING = $89 +DONE_SONG = $8A +APPLEII_MODEL = $8B +SOUND_STATUS = $8C + SOUND_DISABLED = $80 + SOUND_IN_LC = $01 ; $01 sound effects in language card + SOUND_MOCKINGBOARD = $02 ; mockingboard detected +DISP_PAGE = $8D +DRAW_PAGE = $8E + +;TIMER_COUNT = $86 +;WHICH_SLOT = $88 + + + +; More zero-page addresses +; we try not to conflict with anything DOS, MONITOR or BASIC related + + ;COLOR1 = $E0 + ;COLOR2 = $E1 + ;MATCH = $E2 +XX = $E3 +YY = $E4 +HGR_COLOR = $E4 + ;SHIPY = $E4 + ;YADD = $E5 + ;LOOP = $E6 + ;MEMPTRL = $E7 + ;MEMPTRH = $E8 + ;NAMEL = $E9 + ;NAMEH = $EA + ;NAMEX = $EB + ;CHAR = $EC +STATE = $ED +OFFSET = $EF + + ;FIRST = $F0 + +LASTKEY = $F1 +PADDLE_STATUS = $F2 + +SPRITETEMP = $F2 +XPOS = $F3 +YPOS = $F4 +TEMP = $FA +TEMPY = $FB +INL = $FC +INH = $FD +OUTL = $FE +OUTH = $FF + + + + + + +; read any file slot 6 version +; based on FASTLD6 and RTS copyright (c) Peter Ferrie 2011-2013,2018 + +; modified to assembled with ca64 -- vmw +; added code to patch it to run from current disk slot -- vmw + + + adrlo = $26 ; constant from boot prom + adrhi = $27 ; constant from boot prom + tmpsec = $3c ; constant from boot prom + reqsec = $3d ; constant from boot prom + sizelo = $44 + sizehi = $45 + secsize = $46 + + ldsizel = $f0 + ldsizeh = $f1 + namlo = $fb + namhi = $fc + step = $fd ; state for stepper motor + tmptrk = $fe ; temporary copy of current track + phase = $ff ; current phase for /seek + diff --git a/demos/second/zx02_optim.s b/demos/second/zx02_optim.s new file mode 100644 index 00000000..5eebc2e0 --- /dev/null +++ b/demos/second/zx02_optim.s @@ -0,0 +1,159 @@ +; De-compressor for ZX02 files +; ---------------------------- +; +; Decompress ZX02 data (6502 optimized format), optimized for speed and size +; 138 bytes code, 58.0 cycles/byte in test file. +; +; Compress with: +; zx02 input.bin output.zx0 +; +; (c) 2022 DMSC +; Code under MIT license, see LICENSE file. + + +;ZP=$80 + +;offset = ZP+0 +;ZX0_src = ZP+2 +;ZX0_dst = ZP+4 +;bitr = ZP+6 +;pntr = ZP+7 + + ; Initial values for offset, source, destination and bitr +;zx0_ini_block: +; .byte $00, $00, comp_data, out_addr, $80 + +;-------------------------------------------------- +; Decompress ZX0 data (6502 optimized format) + +zx02_full_decomp: +; ; Get initialization block +; ldy #7 +; +;copy_init: lda zx0_ini_block-1, y +; sta offset-1, y +; dey +; bne copy_init + + + sta ZX0_dst+1 ; page to output to in A +zx_src_l: + ldy #$dd + sty ZX0_src +zx_src_h: + ldy #$dd + sty ZX0_src+1 + ldy #$80 + sty bitr + ldy #0 + sty offset + sty offset+1 + sty ZX0_dst ; always on even page + +; Decode literal: Ccopy next N bytes from compressed file +; Elias(length) byte[1] byte[2] ... byte[N] +decode_literal: + jsr get_elias + +cop0: lda (ZX0_src), y + inc ZX0_src + bne plus1 + inc ZX0_src+1 +plus1: sta (ZX0_dst),y + inc ZX0_dst + bne plus2 + inc ZX0_dst+1 +plus2: dex + bne cop0 + + asl bitr + bcs dzx0s_new_offset + +; Copy from last offset (repeat N bytes from last offset) +; Elias(length) + jsr get_elias +dzx0s_copy: + lda ZX0_dst + sbc offset ; C=0 from get_elias + sta pntr + lda ZX0_dst+1 + sbc offset+1 + sta pntr+1 + +cop1: + lda (pntr), y + inc pntr + bne plus3 + inc pntr+1 +plus3: sta (ZX0_dst),y + inc ZX0_dst + bne plus4 + inc ZX0_dst+1 +plus4: dex + bne cop1 + + asl bitr + bcc decode_literal + +; Copy from new offset (repeat N bytes from new offset) +; Elias(MSB(offset)) LSB(offset) Elias(length-1) +dzx0s_new_offset: + ; Read elias code for high part of offset + jsr get_elias + beq exit ; Read a 0, signals the end + ; Decrease and divide by 2 + dex + txa + lsr ; @ + sta offset+1 + + ; Get low part of offset, a literal 7 bits + lda (ZX0_src), y + inc ZX0_src + bne plus5 + inc ZX0_src+1 +plus5: + ; Divide by 2 + ror ; @ + sta offset + + ; And get the copy length. + ; Start elias reading with the bit already in carry: + ldx #1 + jsr elias_skip1 + + inx + bcc dzx0s_copy + +; Read an elias-gamma interlaced code. +; ------------------------------------ +get_elias: + ; Initialize return value to #1 + ldx #1 + bne elias_start + +elias_get: ; Read next data bit to result + asl bitr + rol ; @ + tax + +elias_start: + ; Get one bit + asl bitr + bne elias_skip1 + + ; Read new bit from stream + lda (ZX0_src), y + inc ZX0_src + bne plus6 + inc ZX0_src+1 +plus6: ;sec ; not needed, C=1 guaranteed from last bit + rol ;@ + sta bitr + +elias_skip1: + txa + bcs elias_get + ; Got ending bit, stop reading +exit: + rts