diff --git a/Binary/Apps/Tunes/ReadMe.txt b/Binary/Apps/Tunes/ReadMe.txt index 366efefe..3c41d421 100644 --- a/Binary/Apps/Tunes/ReadMe.txt +++ b/Binary/Apps/Tunes/ReadMe.txt @@ -7,4 +7,4 @@ *********************************************************************** This directory contains some sample ProTracker and MYM sound -files that can be played by the TUNE application. \ No newline at end of file +files that can be played by the TUNE or VGMPLAY application. \ No newline at end of file diff --git a/Source/Apps/TEST/sound/Scales.asm b/Source/Apps/TEST/sound/Scales.asm new file mode 100644 index 00000000..bf91ea81 --- /dev/null +++ b/Source/Apps/TEST/sound/Scales.asm @@ -0,0 +1,145 @@ +; + + .ORG $0100 + +; SCALES ON ALL THREE CHANNELS + +; JR SKIP + + LD B,3 +NEXTCH0 LD A,B + DEC A + LD (CHANNEL),A + PUSH BC ; ACROSS + CALL SCALE ; ALL + POP BC ; CHANNELS + DJNZ NEXTCH0 + +; CONSTANT TONE ON ALL THREE CHANNELS, SCALE VOLUME +SKIP: + LD HL,332+48 ; TONE + LD (NOTE),HL +; + LD B,3 +NEXTCH1 LD A,B + DEC A + LD (CHANNEL),A + PUSH BC ; ACROSS + CALL TONE ; ALL + POP BC ; CHANNELS + DJNZ NEXTCH1 + + RET + +TONE: LD B,50H ; RESET + LD C,0 + RST 08 +; +NEXT1: LD B,51H ; VOLUME + LD C,0 + LD A,(VOLUME) + LD L,A + RST 08 +; + LD B,53H ; NOTE + LD C,0 + LD HL,(NOTE) + RST 08 +; + LD B,54H ; PLAY + LD C,0 + LD A,(CHANNEL) + LD D,A + RST 08 +; + CALL DELAY +; + LD A,(VOLUME) + DEC A + LD (VOLUME),A + JR NZ,NEXT1 +; + LD B,51H ; VOLUME + LD C,0 + LD L,00H + RST 08 +; + LD B,54H ; PLAY + LD C,0 + LD A,(CHANNEL) + LD D,A + RST 08 +; + RET +; +; +; +SCALE: LD B,50H ; RESET + LD C,0 + RST 08 +; + LD B,51H ; VOLUME + LD C,0 + LD L,80H + RST 08 +; + LD HL,380 + LD (NOTE),HL +; +NEXT0: LD B,53H ; NOTE + LD C,0 + LD HL,(NOTE) + RST 08 +; + LD B,54H ; PLAY + LD C,0 + LD A,(CHANNEL) + LD D,A + RST 08 +; + OR A + JR Z,NEXT2 + LD C,9 + LD DE,BADFLAG + CALL 5 + JR NEXT3 +; +NEXT2: CALL DELAY +; +NEXT3: LD HL,(NOTE) + DEC HL + LD A,L + LD (NOTE),A + LD A,H + LD (NOTE+1),A + OR L +; + JR NZ,NEXT0 +; + LD B,51H ; VOLUME + LD C,0 + LD L,00H + RST 08 +; + LD B,54H ; PLAY + LD C,0 + LD A,(CHANNEL) + LD D,A + RST 08 +; + RET +; +DELAY: LD HL,-1 +DELAY1: DEC HL + LD A,H + OR L + JR NZ,DELAY1 + RET +; +BADFLAG .DB '*', $0D, $0A, '$' +NOTE .DW 128 +VOLUME .DB 0 +CHANNEL .DB 0 +; + .END + diff --git a/Source/Apps/VGM/Build.cmd b/Source/Apps/VGM/Build.cmd index 07e354b1..7e2fe40e 100644 --- a/Source/Apps/VGM/Build.cmd +++ b/Source/Apps/VGM/Build.cmd @@ -6,6 +6,7 @@ set PATH=%TOOLS%\tasm32;%PATH% set TASMTABS=%TOOLS%\tasm32 tasm -t180 -g3 -fFF -dWBW vgmplay.asm vgmplay.com vgmplay.lst || exit /b +tasm -t180 -g3 -fFF -dWBW ym2612.asm ym2612.com ym2612.lst || exit /b copy /Y vgmplay.com ..\..\..\Binary\Apps\ || exit /b -copy /Y Tunes\*.* ..\..\..\Binary\Apps\Tunes\ || exit /b \ No newline at end of file +copy /Y Tunes\*.vgm ..\..\..\Binary\Apps\Tunes\ || exit /b diff --git a/Source/Apps/VGM/Makefile b/Source/Apps/VGM/Makefile index c410aec2..58cc9428 100644 --- a/Source/Apps/VGM/Makefile +++ b/Source/Apps/VGM/Makefile @@ -10,6 +10,9 @@ DEPS := vgmplay.asm $(shell find . -name '*.inc') vgmplay.com: $(DEPS) $(TASM) -dWBW vgmplay.asm vgmplay.com vgmplay.lst +ym2612.com: + $(TASM) -dWBW ym2612.asm ym2612.com ym2612.lst + all:: mkdir -p $(DEST)/Tunes cp Tunes/* $(DEST)/Tunes diff --git a/Source/Apps/VGM/Tunes/BGM.VGM b/Source/Apps/VGM/Tunes/BGM.VGM new file mode 100644 index 00000000..e71c431b Binary files /dev/null and b/Source/Apps/VGM/Tunes/BGM.VGM differ diff --git a/Source/Apps/VGM/Tunes/ENDING.VGM b/Source/Apps/VGM/Tunes/ENDING.VGM new file mode 100644 index 00000000..dcd349bc Binary files /dev/null and b/Source/Apps/VGM/Tunes/ENDING.VGM differ diff --git a/Source/Apps/VGM/Tunes/INCHINA.VGM b/Source/Apps/VGM/Tunes/INCHINA.VGM new file mode 100644 index 00000000..cb73e2c7 Binary files /dev/null and b/Source/Apps/VGM/Tunes/INCHINA.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/AGGRESS.VGM b/Source/Apps/VGM/Tunes/More/AGGRESS.VGM new file mode 100644 index 00000000..fd0a3924 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/AGGRESS.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/ANNA.VGM b/Source/Apps/VGM/Tunes/More/ANNA.VGM new file mode 100644 index 00000000..cf8f6a64 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/ANNA.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/BGM.VGM b/Source/Apps/VGM/Tunes/More/BGM.VGM new file mode 100644 index 00000000..e71c431b Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/BGM.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/DESCENT.VGM b/Source/Apps/VGM/Tunes/More/DESCENT.VGM new file mode 100644 index 00000000..0e72d802 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/DESCENT.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/FIELDMAP.VGM b/Source/Apps/VGM/Tunes/More/FIELDMAP.VGM new file mode 100644 index 00000000..efab70af Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/FIELDMAP.VGM differ diff --git a/Source/Apps/VGM/Tunes/itsgamov.vgm b/Source/Apps/VGM/Tunes/More/ITSGAMOV.VGM similarity index 100% rename from Source/Apps/VGM/Tunes/itsgamov.vgm rename to Source/Apps/VGM/Tunes/More/ITSGAMOV.VGM diff --git a/Source/Apps/VGM/Tunes/lemmin01.vgm b/Source/Apps/VGM/Tunes/More/LEMMIN01.VGM similarity index 100% rename from Source/Apps/VGM/Tunes/lemmin01.vgm rename to Source/Apps/VGM/Tunes/More/LEMMIN01.VGM diff --git a/Source/Apps/VGM/Tunes/pengui03.vgm b/Source/Apps/VGM/Tunes/More/PENGUI03.VGM similarity index 100% rename from Source/Apps/VGM/Tunes/pengui03.vgm rename to Source/Apps/VGM/Tunes/More/PENGUI03.VGM diff --git a/Source/Apps/VGM/Tunes/pitfal02.vgm b/Source/Apps/VGM/Tunes/More/PITFAL02.VGM similarity index 100% rename from Source/Apps/VGM/Tunes/pitfal02.vgm rename to Source/Apps/VGM/Tunes/More/PITFAL02.VGM diff --git a/Source/Apps/VGM/Tunes/More/QIX.VGM b/Source/Apps/VGM/Tunes/More/QIX.VGM new file mode 100644 index 00000000..f3d46790 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/QIX.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/STARTDEM.VGM b/Source/Apps/VGM/Tunes/More/STARTDEM.VGM new file mode 100644 index 00000000..66b57817 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/STARTDEM.VGM differ diff --git a/Source/Apps/VGM/Tunes/More/TEDDY.VGM b/Source/Apps/VGM/Tunes/More/TEDDY.VGM new file mode 100644 index 00000000..4b30c562 Binary files /dev/null and b/Source/Apps/VGM/Tunes/More/TEDDY.VGM differ diff --git a/Source/Apps/VGM/Tunes/tiger02.vgm b/Source/Apps/VGM/Tunes/More/TIGER02.VGM similarity index 100% rename from Source/Apps/VGM/Tunes/tiger02.vgm rename to Source/Apps/VGM/Tunes/More/TIGER02.VGM diff --git a/Source/Apps/VGM/Tunes/SHIRAKAW.VGM b/Source/Apps/VGM/Tunes/SHIRAKAW.VGM new file mode 100644 index 00000000..c6cf01b6 Binary files /dev/null and b/Source/Apps/VGM/Tunes/SHIRAKAW.VGM differ diff --git a/Source/Apps/VGM/Tunes/STARTDEM.VGM b/Source/Apps/VGM/Tunes/STARTDEM.VGM new file mode 100644 index 00000000..66b57817 Binary files /dev/null and b/Source/Apps/VGM/Tunes/STARTDEM.VGM differ diff --git a/Source/Apps/VGM/Tunes/filthy01.vgm b/Source/Apps/VGM/Tunes/filthy01.vgm deleted file mode 100644 index c161e1f3..00000000 Binary files a/Source/Apps/VGM/Tunes/filthy01.vgm and /dev/null differ diff --git a/Source/Apps/VGM/YM2612.ASM b/Source/Apps/VGM/YM2612.ASM new file mode 100644 index 00000000..b2014b64 --- /dev/null +++ b/Source/Apps/VGM/YM2612.ASM @@ -0,0 +1,778 @@ +; +;------------------------------------------------------------------------------ +; Simple Z80 FM Music Driver. +; Adapted from https://github.com/michaelcmartin/bumbershoot/genesis/fm_mus.asm +;------------------------------------------------------------------------------ +; +; A song in this system is a series of records, where each record +; begins with a byte for the number of frames this record lasts, +; followed by a byte for the number of register writes to the first +; block of FM registers, followed by that many pairs of (register, +; value) bytes. +; When a zero byte is reached for a record length, the playback +; loops back to the "segno" label. +; +; Song data is created from a Music Macro Language score (mml) +; by the makebach.py script +; +;------------------------------------------------------------------------------ +; Device and system specific definitions +;------------------------------------------------------------------------------ +; +custom .equ 0 ; System configurations +sbcecb .equ 1 +MBC .equ 2 +; +plt_romwbw .equ 1 ; Build for ROMWBW? +plt_type .equ sbcecb ; Select build configuration +debug .equ 0 + +ctc_delay .equ 0 +; + .org 100H +; +BDOS .equ 0005h +; +YMSEL .equ $c0 +YMDAT .equ $c1 +ctcbase .equ $cc +; +;------------------------------------------------------------------------------ +; Initialize sound chip and ctc etc +;------------------------------------------------------------------------------ +; +init: +#IF (debug) + call ym_init +#ENDIF +#IF (ctc_delay) + call ctc_config +#ENDIF +; +;------------------------------------------------------------------------------ +; Main loop +;------------------------------------------------------------------------------ +; +mloop: LD C, 6 ; check for keypress + LD E, 0FFH + CALL 5 + OR A + JP NZ,0 +; + call ploop ; PLAY + jp z,0 +; + ld hl,$1000 ; DELAY +dlp: dec hl + ld a,h + or l + jr nz,dlp +; + jr mloop +; +;------------------------------------------------------------------------------ +; Play loop +;------------------------------------------------------------------------------ +; +ploop: ld hl, wait ; HAVE WE REACHED THE + dec (hl) ; LAST FRAME + ret nz + + ld hl, (ptr) ; POINT TO START OF SONG + ld a, (hl) ; GET NO OF FRAMES + and a ; + ret z +; jr nz, nolp +; +; ld a,'@' +; call PRTCHR +; +; ld hl, segno ; POINT TO CURRENT SEGMENT + ; ld a, (hl) ; GET FRAME COUNT +nolp: ld (wait), a ; AND SAVE IT + inc hl + call PRTHEX + call PRTDOT + + ld b, (hl) ; GET NUMBER OF REGISTER PAIRS TO WRITE + inc hl ; POINT TO REGISTER + ld a,b + call PRTHEX + call PRTDOT + +rlp: ld a, (hl) ; SELECT REGISTER + out (YMSEL),a + call PRTHEX + + inc hl ; GET VALUE + ld a, (hl) + call PRTHEX + + inc hl + + out (YMDAT),a ; WRITE THE VALUE + + djnz rlp ; DO ALL THE PAIRS IN THIS SEGMENT + + ld (ptr), hl ; SAVE WHERE WE ARE AT + call CRLF + + ret +; +;------------------------------------------------------------------------------ +; CTC initialization +;------------------------------------------------------------------------------ +; +ctc_config: +; ld b,4 ; 4 channels +; ld c,ctcbase ; first channel port +;ctc_lp: ld a,ctc_defcfg ; ctc default config +; out (c),a ; ctc command +; inc c ; next channel port +; djnz ctc_lp + +; ld hl,hb_timint ; TIMER INT HANDLER ADR +; ld (ivt(ctctivt)),hl +; +; ld a,int_ctc0a * 2 + out (ctcbase),a ; SETUP CTC BASE INT VECTOR +; +ctcch0 .equ ctcbase +ctcch1 .equ ctcbase+1 +ctcch2 .equ ctcbase+2 +ctcch3 .equ ctcbase+3 + +ctccfg0 .equ %01010011 +ctccfg1 .equ %01010111 +ctccfg2 .equ %01010111 +ctccfg3 .equ %01010111 + +ctcdiv0 .equ 1 ; 3.579545MHz input 60Hz timer tick +ctcdiv1 .equ 8 +ctcdiv2 .equ 0 +ctcdiv3 .equ 29 + +;ctcdiv0 .equ 1 ; 3.579545MHz input 50Hz timer tick +;ctcdiv1 .equ 8 +;ctcdiv2 .equ 0 +;ctcdiv3 .equ 34 + +;ctcdiv0 .equ 1 ; 3.579545MHz input 44100z timer tick +;ctcdiv1 .equ 1 +;ctcdiv2 .equ 1 +;ctcdiv3 .equ 81 + + ld a,ctccfg0 & $7f ; ; Channel 0 + out (ctcch0),a +; + ld a,ctccfg1 & $7f ; Channel 1 + out (ctcch1),a ; + ld a,ctcdiv1 & $ff ; + out (ctcch1),a ; +; + ld a,ctccfg2 & $7f ; Channel 2 + out (ctcch2),a ; + ld a,ctcdiv2 & $ff ; + out (ctcch2),a ; +; + ld a,ctccfg3 & $7f ; Channel 3 + out (ctcch3),a ; + ld a,ctcdiv3 & $ff ; + out (ctcch3),a ; +; + ret +; +ptr: .dw song +wait: .db $01 +; +;------------------------------------------------------------------------------ +; YM2612 initialization - not required if included in song data +;------------------------------------------------------------------------------ +; +#DEFINE setreg(reg,val) \ +#DEFCONT \ ld a,reg +#DEFCONT \ out (YMSEL),a +#DEFCONT \ ld a,val +#DEFCONT \ out (YMDAT),a +#DEFCONT \ ld b,0 +#DEFCONT \ in a,(YMSEL) +#DEFCONT \ rlca +#DEFCONT \ jp nc,$+5 +#DEFCONT \ djnz $-6 +; +ym_init: + setreg($22,$00) ; lfo off + setreg($27,$00) ; note off ch 0 + setreg($28,$01) ; note off ch 1 + setreg($28,$02) ; note off ch 2 + setreg($28,$03) ; note off ch 3 + setreg($28,$04) ; note off ch 4 + setreg($28,$05) ; note off ch 5 + setreg($28,$06) ; note off ch 6 + setreg($28,$01) ; note off ch 1 + setreg($2b,$00) ; dac off + setreg($30,$71) + setreg($34,$0d) + setreg($38,$33) + setreg($3c,$01) ; dt1/mul + setreg($40,$23) + setreg($44,$2d) + setreg($48,$26) + setreg($4c,$00) ; total level + setreg($50,$5f) + setreg($54,$99) + setreg($58,$5f) + setreg($5c,$94) ; rs/ar + setreg($60,$05) + setreg($64,$05) + setreg($68,$05) + setreg($6c,$07) ; am/dir + setreg($70,$02) + setreg($74,$02) + setreg($78,$02) + setreg($7c,$02) ; d2r + setreg($80,$11) + setreg($84,$11) + setreg($88,$11) + setreg($8c,$a6) ; d1l/rr + setreg($90,$00) + setreg($94,$00) + setreg($98,$00) + setreg($9c,$00) ; proprietary + setreg($b0,$32) ; feedback/algorithm + setreg($b4,$c0) ; both speakers on + setreg($28,$00) ; key off + setreg($a4,$22) + setreg($a0,$69) ; set frequency +; + ret +; +;------------------------------------------------------------------------------ +; Example breakdown of first section, which is initialization +;------------------------------------------------------------------------------ +; +; BYTE NUMBER OF FRAMES +; BYTE NUMBER OF REGISTER WRITES +; BYTE REGISTER +; BYTE VALUE +; +; CNT $0D 13 frames +; $42 66 register writes (132 BYTES) +; 2 $30,$71 dac +; 4 $34,$0D dac +; 6 $38,$33 dac +; 8 $3C,$01 dt1/mul +; 10 $40,$23 dt1/mul +; 12 $44,$2D dt1/mul +; 14 $48,$26 dt1/mul +; 16 $4C,$00 total level +; 18 $50,$5F total level +; 20 $54,$99 total level +; 22 $58,$5F total level +; 24 $5C,$94 rs/ar +; 26 $60,$05 rs/ar +; 28 $64,$05 rs/ar +; 30 $68,$05 rs/ar +; 32 $6C,$07 am/dir +; 34 $70,$02 am/dir +; 36 $74,$02 am/dir +; 38 $78,$02 am/dir +; 40 $7c,$02 d2r +; 42 $80,$11 d2r +; 44 $84,$11 d2r +; 46 $88,$11 d2r +; 48 $8C,$A6 +; 50 $90,$00 +; 52 $94,$00 +; 54 $98,$00 +; 56 $9C,$00 +; 58 $B0,$32 +; 60 $B4,$C0 +; 62 $31,$71 +; 64 $35,$0D +; 66 $39,$33 +; 68 $3D,$01 +; 70 $41,$23 +; 72 $45,$2D +; 74 $49,$26 +; 76 $4D,$00 +; 78 $51,$5F +; 80 $55,$99 +; 82 $59,$5F +; 84 $5D,$94 +; 86 $61,$05 +; 88 $65,$05 +; 90 $69,$05 +; 92 $6D,$07 +; 94 $71,$02 +; 96 $75,$02 +; 98 $79,$02 +; 100 $7D,$02 +; 102 $81,$11 +; 104 $85,$11 +; 106 $89,$11 +; 108 $8D,$A6 +; 110 $91,$00 +; 112 $95,$00 +; 114 $99,$00 +; 116 $9D,$00 +; 118 $B0,$32 +; 120 $B4,$C0 +; 122 $A4,$17 +; 124 $A0,$89 +; 126 $28,$F0 +; 128 $A5,$0F +; 130 $A1,$89 +; 132 $28,$F1 +; +;------------------------------------------------------------------------------ +; Song data created from Music Macro Language (mml) by makebach +;------------------------------------------------------------------------------ +; +song: +segno: .db $0D,$42,$30,$71,$34,$0D,$38,$33,$3C,$01,$40,$23,$44,$2D,$48,$26 + .db $4C,$00,$50,$5F,$54,$99,$58,$5F,$5C,$94,$60,$05,$64,$05,$68,$05 + .db $6C,$07,$70,$02,$74,$02,$78,$02,$7C,$02,$80,$11,$84,$11,$88,$11 + .db $8C,$A6,$90,$00,$94,$00,$98,$00,$9C,$00,$B0,$32,$B4,$C0,$31,$71 + .db $35,$0D,$39,$33,$3D,$01,$41,$23,$45,$2D,$49,$26,$4D,$00,$51,$5F + .db $55,$99,$59,$5F,$5D,$94,$61,$05,$65,$05,$69,$05,$6D,$07,$71,$02 + .db $75,$02,$79,$02,$7D,$02,$81,$11,$85,$11,$89,$11,$8D,$A6,$91,$00 + .db $95,$00,$99,$00,$9D,$00,$B0,$32,$B4,$C0,$A4,$17,$A0,$89,$28,$F0 + .db $A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF + .db $28,$F0,$02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01 + .db $28,$00,$07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C + .db $A0,$BF,$28,$F0,$02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0 + .db $02,$01,$28,$00,$07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07 + .db $A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C + .db $A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1E + .db $A0,$56,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$89,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0C + .db $A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$1D,$A0,$A5 + .db $28,$F0,$A5,$0F,$A1,$89,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1D,$A0,$A5,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0C,$A1,$3B,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0F,$A1,$1D + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$08,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56 + .db $28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0F,$A1,$1D,$28,$F1,$02,$01 + .db $28,$01,$0D,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0D,$03 + .db $A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$01,$03,$03,$A5,$0F,$A1,$1D + .db $28,$F1,$0A,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C + .db $A0,$BF,$28,$F0,$02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0 + .db $02,$01,$28,$00,$07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07 + .db $A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C + .db $A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17 + .db $A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03 + .db $A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5 + .db $28,$F0,$02,$01,$28,$00,$07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0 + .db $A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17 + .db $A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03 + .db $A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$1A,$06 + .db $A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$04,$02,$28,$00 + .db $28,$01,$0D,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0E,$A1,$56,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C,$A0,$3B,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0C + .db $A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$08 + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C + .db $A0,$BF,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C + .db $A0,$3B,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$17,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$08,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$02,$01,$28,$00 + .db $08,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$00,$06,$03,$A4,$1D + .db $A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$15 + .db $A0,$A5,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $1A,$06,$A4,$17,$A0,$1D,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$1A,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$04,$01,$28,$01,$1A,$03,$A5,$0D,$A1,$A5,$28,$F1,$04,$01 + .db $28,$01,$12,$03,$A5,$07,$A1,$89,$28,$F1,$08,$01,$28,$00,$04,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89,$28,$F1 + .db $02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$00 + .db $0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03,$A4,$1F + .db $A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C + .db $A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$01 + .db $0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$07,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D + .db $A1,$08,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$1E,$A0,$56 + .db $28,$F0,$A5,$0F,$A1,$89,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$A5,$28,$F0 + .db $A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$89 + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D,$A0,$08 + .db $28,$F0,$A5,$0C,$A1,$3B,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1D,$A0,$A5,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$01 + .db $0D,$03,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56,$28,$F1 + .db $02,$01,$28,$01,$03,$03,$A5,$0F,$A1,$1D,$28,$F1,$0A,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$07 + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0 + .db $02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00 + .db $07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0 + .db $A5,$0D,$A1,$08,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D + .db $A0,$A5,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1C,$A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0F + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$89,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$08,$06,$A4,$1C,$A0,$3B,$28,$F0 + .db $A5,$0D,$A1,$08,$28,$F1,$02,$01,$28,$00,$08,$03,$A4,$1C,$A0,$BF + .db $28,$F0,$02,$01,$28,$00,$06,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$1A,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$17,$A0,$1D + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06 + .db $A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$04,$01,$28,$01 + .db $1A,$03,$A5,$0D,$A1,$A5,$28,$F1,$04,$01,$28,$01,$12,$03,$A5,$07 + .db $A1,$89,$28,$F1,$08,$01,$28,$00,$04,$01,$28,$01,$0D,$06,$A4,$17 + .db $A0,$89,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1C,$A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$BF,$28,$F0,$A5,$0D,$A1,$FB,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1C,$A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$17,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$1A,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0E,$A1,$56,$28,$F1 + .db $04,$02,$28,$00,$28,$01,$1A,$06,$A4,$16,$A0,$56,$28,$F0,$A5,$0C + .db $A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$16,$A0,$56 + .db $28,$F0,$A5,$06,$A1,$56,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1F,$A0,$89,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1F,$A0,$1D,$28,$F0,$A5,$14,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$1E,$A0,$56,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$1D,$28,$F0,$A5,$0C,$A1,$BF + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$FB,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F + .db $A1,$1D,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$14,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0 + .db $A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$FB + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$1F,$A0,$89 + .db $28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F + .db $A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1E + .db $A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1F,$A0,$1D,$28,$F0,$A5,$14,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1E,$A0,$56,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1F,$A0,$1D,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$1A,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$14,$A1,$3B + .db $28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0 + .db $A5,$0F,$A1,$89,$28,$F1,$04,$02,$28,$00,$28,$01,$08,$06,$A4,$1F + .db $A0,$1D,$28,$F0,$A5,$14,$A1,$3B,$28,$F1,$02,$01,$28,$00,$08,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$00,$06,$03,$A4,$24,$A0,$3B + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1C,$A0,$BF + .db $28,$F0,$A5,$14,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06 + .db $A4,$1D,$A0,$FB,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00 + .db $28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0E,$A1,$56,$28,$F1 + .db $04,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$FB,$28,$F0,$02,$01,$28,$00 + .db $0D,$03,$A4,$1E,$A0,$56,$28,$F0,$02,$01,$28,$00,$12,$03,$A4,$1F + .db $A0,$1D,$28,$F0,$08,$01,$28,$01,$04,$01,$28,$00,$1A,$06,$A4,$1F + .db $A0,$89,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08 + .db $28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1E,$A0,$56,$28,$F0 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$A5 + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1D,$A0,$08 + .db $28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C + .db $A0,$BF,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D + .db $A0,$08,$28,$F0,$A5,$0C,$A1,$3B,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $0D,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$08,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$89,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$1A,$06,$A4,$17,$A0,$1D,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$16,$A0,$56,$28,$F0 + .db $A5,$0C,$A1,$3B,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$1D + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$15,$A0,$A5 + .db $28,$F0,$A5,$05,$A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01 + .db $0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0F + .db $A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$15,$A0,$A5,$28,$F0 + .db $A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1D,$A0,$08 + .db $28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06 + .db $A4,$1D,$A0,$A5,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$01 + .db $0D,$03,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56,$28,$F1 + .db $02,$01,$28,$01,$03,$03,$A5,$0F,$A1,$1D,$28,$F1,$0A,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$07 + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0 + .db $02,$01,$28,$00,$0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00 + .db $07,$03,$A4,$1F,$A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1 + .db $02,$01,$28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0 + .db $A5,$0D,$A1,$08,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D + .db $A0,$A5,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1C,$A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1D,$A0,$A5,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0F + .db $A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$89,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0 + .db $A5,$0D,$A1,$08,$28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF + .db $28,$F0,$02,$01,$28,$00,$16,$03,$A4,$15,$A0,$A5,$28,$F0,$04,$01 + .db $28,$01,$04,$01,$28,$00,$1A,$06,$A4,$17,$A0,$1D,$28,$F0,$A5,$0D + .db $A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$17,$A0,$89 + .db $28,$F0,$A5,$0F,$A1,$89,$28,$F1,$04,$01,$28,$01,$1A,$03,$A5,$0D + .db $A1,$A5,$28,$F1,$04,$01,$28,$01,$12,$03,$A5,$07,$A1,$89,$28,$F1 + .db $08,$01,$28,$00,$04,$01,$28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0 + .db $A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C,$A0,$3B + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$BF + .db $28,$F0,$A5,$0D,$A1,$FB,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C + .db $A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$17 + .db $A0,$89,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$17,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06 + .db $A4,$17,$A0,$89,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$04,$02,$28,$00 + .db $28,$01,$1A,$06,$A4,$16,$A0,$56,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1 + .db $04,$02,$28,$00,$28,$01,$1A,$06,$A4,$16,$A0,$56,$28,$F0,$A5,$06 + .db $A1,$56,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1F,$A0,$89 + .db $28,$F0,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F + .db $A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1E + .db $A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1F,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1F,$A0,$1D,$28,$F0,$A5,$14,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1E,$A0,$56,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $0D,$06,$A4,$1F,$A0,$1D,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0D,$A1,$FB,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$14,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$1D + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$FB,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$0D,$06,$A4,$1F,$A0,$89,$28,$F0,$A5,$0E + .db $A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$1D,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1E,$A0,$56,$28,$F0 + .db $A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F,$A0,$89 + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1F,$A0,$1D + .db $28,$F0,$A5,$14,$A1,$BF,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1E + .db $A0,$56,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1F + .db $A0,$1D,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $1A,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$14,$A1,$3B,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$04,$02,$28,$00,$28,$01,$08,$06,$A4,$1F,$A0,$1D,$28,$F0 + .db $A5,$14,$A1,$3B,$28,$F1,$02,$01,$28,$00,$08,$03,$A4,$1F,$A0,$89 + .db $28,$F0,$02,$01,$28,$00,$06,$03,$A4,$24,$A0,$3B,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$14 + .db $A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06,$A4,$1D,$A0,$FB + .db $28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$1A,$06 + .db $A4,$1E,$A0,$56,$28,$F0,$A5,$0E,$A1,$56,$28,$F1,$04,$01,$28,$00 + .db $0D,$03,$A4,$1D,$A0,$FB,$28,$F0,$02,$01,$28,$00,$0D,$03,$A4,$1E + .db $A0,$56,$28,$F0,$02,$01,$28,$00,$12,$03,$A4,$1F,$A0,$1D,$28,$F0 + .db $08,$01,$28,$01,$04,$01,$28,$00,$1A,$06,$A4,$1F,$A0,$89,$28,$F0 + .db $A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1F + .db $A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1E,$A0,$56,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$A5 + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0E + .db $A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C,$A0,$BF,$28,$F0 + .db $02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D,$A0,$08,$28,$F0 + .db $A5,$0C,$A1,$3B,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D + .db $A0,$08,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$08,$28,$F1,$02,$01,$28,$00 + .db $0B,$03,$A4,$17,$A0,$89,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00 + .db $1A,$06,$A4,$17,$A0,$1D,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$04,$02 + .db $28,$00,$28,$01,$0D,$06,$A4,$16,$A0,$56,$28,$F0,$A5,$0C,$A1,$3B + .db $28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$1D,$28,$F0,$02,$01 + .db $28,$01,$02,$01,$28,$00,$1A,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$05 + .db $A1,$A5,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1C,$A0,$3B + .db $28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D + .db $A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06,$A4,$15 + .db $A0,$A5,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01,$0B,$03 + .db $A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06 + .db $A4,$15,$A0,$A5,$28,$F0,$A5,$0F,$A1,$1D,$28,$F1,$02,$01,$28,$01 + .db $0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$1C,$A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0F,$A1,$89,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$0D,$06,$A4,$15,$A0,$A5,$28,$F0,$A5,$0F,$A1,$89 + .db $28,$F1,$02,$01,$28,$01,$0B,$03,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$02,$01,$28,$01,$1A,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0F + .db $A1,$1D,$28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$A5 + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D + .db $A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C + .db $A0,$BF,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1D,$A0,$08,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01 + .db $0D,$03,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0F + .db $A1,$1D,$28,$F1,$02,$01,$28,$01,$0D,$03,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0D,$03,$A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$01 + .db $03,$03,$A5,$0F,$A1,$1D,$28,$F1,$0A,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01 + .db $28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$00,$0D,$03 + .db $A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03,$A4,$1F,$A0,$89 + .db $28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B + .db $28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1F + .db $A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1F + .db $A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$01,$0B,$03 + .db $A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01,$0D,$06 + .db $A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$01 + .db $0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1 + .db $02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$00 + .db $0D,$03,$A4,$1D,$A0,$A5,$28,$F0,$02,$01,$28,$00,$07,$03,$A4,$1F + .db $A0,$89,$28,$F0,$06,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C + .db $A0,$3B,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01,$28,$00,$0B,$03 + .db $A4,$1F,$A0,$1D,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06 + .db $A4,$1F,$A0,$89,$28,$F0,$A5,$07,$A1,$89,$28,$F1,$02,$01,$28,$01 + .db $0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00,$02,$01,$28,$01 + .db $0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$01,$0B,$03,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$02,$01 + .db $28,$01,$0D,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $02,$01,$28,$01,$0B,$03,$A5,$0C,$A1,$BF,$28,$F1,$02,$01,$28,$00 + .db $02,$01,$28,$01,$1A,$06,$A4,$1E,$A0,$56,$28,$F0,$A5,$0D,$A1,$08 + .db $28,$F1,$04,$02,$28,$00,$28,$01,$0D,$06,$A4,$1D,$A0,$A5,$28,$F0 + .db $A5,$0E,$A1,$56,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1D,$A0,$08 + .db $28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$BF + .db $28,$F0,$A5,$0F,$A1,$89,$28,$F1,$02,$01,$28,$00,$0B,$03,$A4,$1C + .db $A0,$3B,$28,$F0,$02,$01,$28,$01,$02,$01,$28,$00,$1A,$06,$A4,$1D + .db $A0,$A5,$28,$F0,$A5,$0C,$A1,$BF,$28,$F1,$04,$02,$28,$00,$28,$01 + .db $0D,$06,$A4,$1D,$A0,$08,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1,$02,$01 + .db $28,$00,$0B,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01,$28,$01,$02,$01 + .db $28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0F,$A1,$89,$28,$F1 + .db $02,$01,$28,$00,$0B,$03,$A4,$17,$A0,$89,$28,$F0,$02,$01,$28,$01 + .db $02,$01,$28,$00,$0D,$06,$A4,$1C,$A0,$3B,$28,$F0,$A5,$0D,$A1,$08 + .db $28,$F1,$02,$01,$28,$00,$0D,$03,$A4,$1C,$A0,$BF,$28,$F0,$02,$01 + .db $28,$00,$16,$03,$A4,$15,$A0,$A5,$28,$F0,$04,$01,$28,$01,$04,$01 + .db $28,$00,$1A,$06,$A4,$17,$A0,$1D,$28,$F0,$A5,$0D,$A1,$A5,$28,$F1 + .db $04,$02,$28,$00,$28,$01,$1A,$06,$A4,$17,$A0,$89,$28,$F0,$A5,$0F + .db $A1,$89,$28,$F1,$04,$01,$28,$01,$1A,$03,$A5,$0D,$A1,$A5,$28,$F1 + .db $04,$01,$28,$01,$12,$03,$A5,$07,$A1,$89,$28,$F1,$08,$01,$28,$00 + .db $04,$01,$28,$01,$00 + ;; 7045 bytes in song + +#include "printing.inc" + + .end diff --git a/Source/Apps/VGM/vgmplay.asm b/Source/Apps/VGM/vgmplay.asm index e4581e1d..eb2a7f82 100644 --- a/Source/Apps/VGM/vgmplay.asm +++ b/Source/Apps/VGM/vgmplay.asm @@ -9,122 +9,175 @@ ; YM2151 support from Ed Brindley ; ; YM2162/YM3484, GD3 support, VGM Chip identification, -; default file type, basic file size checking added by Phil Summers +; default file type, basic file size checking, polled CTC mode +; added by Phil Summers ; ; Bugs: YM2151 playback untested & no mute. +; CTC polled timing - predicted 44100 divider is too slow ; ; Assemble with: ; ; TASM -80 -b VGMPLAY.ASM VGMPLAY.COM ; +; +; A VGM file can play 44100 samples a second. This may be sound chip +; register commands or PCM data. This player does not support PCM playback +; due to the high processor speed and file size required. Typical VGM files +; available use a much lower sample rate and are playable. Where the processor +; speed is low and the sample rate is high, the playback overhead will cause +; playback speed to be inaccurate. + ;------------------------------------------------------------------------------ ; Device and system specific definitions ;------------------------------------------------------------------------------ ; -P8X180 .EQU 0 ; System configuration -RC2014 .EQU 0 -SBCECB .EQU 1 -MBC .EQU 0 -; - .IF P8X180 -RSEL .EQU 82H ; Primary AY-3-8910 Register selection -RDAT .EQU 83H ; Primary AY-3-8910 Register data -RSEL2 .EQU 88H ; Secondary AY-3-8910 Register selection -RDAT2 .EQU 89H ; Secondary AY-3-8910 Register data -PSG1REG .EQU 84H ; Primary SN76489 -PSG2REG .EQU 8AH ; Secondary SN76489 -YM2151_SEL1 .EQU 0B0H ; Primary YM2151 register selection -YM2151_DAT1 .EQU 0B1H ; Primary YM2151 register data -YM2151_SEL2 .EQU 0B2H ; Secondary YM2151 register selection -YM2151_DAT2 .EQU 0B3H ; Secondary YM2151 register data -FRAME_DLY .EQU 48 ; Frame delay (~ 1/44100) - .ENDIF -; - .IF RC2014 -RSEL .EQU 0D8H ; Primary AY-3-8910 Register selection -RDAT .EQU 0D0H ; Primary AY-3-8910 Register data -RSEL2 .EQU 0A0H ; Secondary AY-3-8910 Register selection -RDAT2 .EQU 0A1H ; Secondary AY-3-8910 Register data -PSG1REG .EQU 0FFH ; Primary SN76489 -PSG2REG .EQU 0FBH ; Secondary SN76489 -YM2151_SEL1 .EQU 0FEH ; Primary YM2151 register selection -YM2151_DAT1 .EQU 0FFH ; Primary YM2151 register data -YM2151_SEL2 .EQU 0D0H ; Secondary YM2151 register selection -YM2151_DAT2 .EQU 0D1H ; Secondary YM2151 register data -FRAME_DLY .EQU 15 ; Frame delay (~ 1/44100) - .ENDIF -; - .IF SBCECB -RSEL .EQU 0D8H ; Primary AY-3-8910 Register selection -RDAT .EQU 0D0H ; Primary AY-3-8910 Register data -RSEL2 .EQU 0A0H ; Secondary AY-3-8910 Register selection -RDAT2 .EQU 0A1H ; Secondary AY-3-8910 Register data -YMSEL .EQU 0C0H ; Primary YM2162 11000000 a1=0 a0=0 -YMDAT .EQU 0C1H ; Primary YM2162 11000001 a1=0 a0=1 -YM2SEL .EQU 0C2H ; Secondary YM2162 11000010 a1=1 a0=0 -YM2DAT .EQU 0C3H ; Secondary YM2162 11000011 a1=1 a0=1 -PSG1REG .EQU 0C6H ; Primary SN76489 -PSG2REG .EQU 0C7H ; Secondary SN76489 -YM2151_SEL1 .EQU 0FEH ; Primary YM2151 register selection -YM2151_DAT1 .EQU 0FFH ; Primary YM2151 register data -YM2151_SEL2 .EQU 0FEH ; Secondary YM2151 register selection -YM2151_DAT2 .EQU 0FFH ; Secondary YM2151 register data -FRAME_DLY .EQU 8 ; Frame delay (~ 1/44100) - .ENDIF -; - .IF MBC -RSEL .EQU 0A0H ; Primary AY-3-8910 Register selection -RDAT .EQU 0A1H ; Primary AY-3-8910 Register data -RSEL .EQU 0D8H ; Secondary AY-3-8910 Register selection -RDAT .EQU 0D0H ; Secondary AY-3-8910 Register data -YMSEL .EQU 0C0H ; 11000000 a1=0 a0=0 -YMDAT .EQU 0C1H ; 11000001 a1=0 a0=1 -YM2SEL .EQU 0C2H ; 11000010 a1=1 a0=0 -YM2DAT .EQU 0C3H ; 11000011 a1=1 a0=1 -PSGREG .EQU 0C6H ; Primary SN76489 -PSG2REG .EQU 0C7H ; Secondary SN76489 -YM2151_SEL1 .EQU 0FEH ; Primary YM2151 register selection -YM2151_DAT1 .EQU 0FFH ; Primary YM2151 register data -YM2151_SEL2 .EQU 0FEH ; Secondary YM2151 register selection -YM2151_DAT2 .EQU 0FFH ; Secondary YM2151 register data -FRAME_DLY .EQU 10 ; Frame delay (~ 1/44100) - .ENDIF -; -;------------------------------------------------------------------------------ -; Your customer overrides can go in here i.e. ports -;------------------------------------------------------------------------------ -; -;RSEL .SET 09AH ; Primary AY-3-8910 Register selection -;RDAT .SET 09BH ; Primary AY-3-8910 Register data -; -;------------------------------------------------------------------------------ -; Frame delay overide values for different processor speeds. -;------------------------------------------------------------------------------ -; -;FRAME_DLY .SET 10 ; 1Mhz ; not -;FRAME_DLY .SET 10 ; 2Mhz ; implemented -;FRAME_DLY .SET 10 ; 4Mhz ; yet -;FRAME_DLY .SET 15 ; 8Mhz -;FRAME_DLY .SET 10 ; 10Mhz -;FRAME_DLY .SET 20 ; 12Mhz -; -;------------------------------------------------------------------------------ -; Frame delay values for pal/ntsc -;------------------------------------------------------------------------------ -; -D60 .EQU 735 -D50 .EQU 882 +custom .equ 0 ; System configurations +P8X180 .equ 1 +RC2014 .equ 2 +sbcecb .equ 3 +MBC .equ 4 +; +plt_romwbw .equ 1 ; Build for ROMWBW? +plt_type .equ sbcecb ; Select build configuration +debug .equ 0 + +#IF (plt_type=custom) +RSEL .equ 0D8H ; Primary AY-3-8910 Register selection +RDAT .equ 0D0H ; Primary AY-3-8910 Register data +RSEL .SET 09AH ; Primary AY-3-8910 Register selection +RDAT .SET 09BH ; Primary AY-3-8910 Register data +RSEL2 .equ 88H ; Secondary AY-3-8910 Register selection +RDAT2 .equ 89H ; Secondary AY-3-8910 Register data +VGMBASE .equ $C0 +YMSEL .equ VGMBASE+00H ; Primary YM2162 11000000 a1=0 a0=0 +YMDAT .equ VGMBASE+01H ; Primary YM2162 11000001 a1=0 a0=1 +YM2SEL .equ VGMBASE+02H ; Secondary YM2162 11000010 a1=1 a0=0 +YM2DAT .equ VGMBASE+03H ; Secondary YM2162 11000011 a1=1 a0=1 +PSG1REG .equ VGMBASE+08H ; Primary SN76489 +PSG2REG .equ VGMBASE+09H ; Secondary SN76489 +ctcbase .equ VGMBASE+0CH ; CTC base address +YM2151_SEL1 .equ 0FEH ; Primary YM2151 register selection +YM2151_DAT1 .equ 0FFH ; Primary YM2151 register data +YM2151_SEL2 .equ 0FEH ; Secondary YM2151 register selection +YM2151_DAT2 .equ 0FFH ; Secondary YM2151 register data +FRAME_DLY .equ 10 ; Frame delay (~ 1/44100) +plt_cpuspd .equ 6 ; Non ROMWBW cpu speed default +#ENDIF +; +#IF (plt_type=P8X180) +RSEL .equ 82H ; Primary AY-3-8910 Register selection +RDAT .equ 83H ; Primary AY-3-8910 Register data +RSEL2 .equ 88H ; Secondary AY-3-8910 Register selection +RDAT2 .equ 89H ; Secondary AY-3-8910 Register data +PSG1REG .equ 84H ; Primary SN76489 +PSG2REG .equ 8AH ; Secondary SN76489 +YM2151_SEL1 .equ 0B0H ; Primary YM2151 register selection +YM2151_DAT1 .equ 0B1H ; Primary YM2151 register data +YM2151_SEL2 .equ 0B2H ; Secondary YM2151 register selection +YM2151_DAT2 .equ 0B3H ; Secondary YM2151 register data +ctcbase .equ 000H ; CTC base address +YMSEL .equ 000H ; Primary YM2162 11000000 a1=0 a0=0 +YMDAT .equ 000H ; Primary YM2162 11000001 a1=0 a0=1 +YM2SEL .equ 000H ; Secondary YM2162 11000010 a1=1 a0=0 +YM2DAT .equ 000H ; Secondary YM2162 11000011 a1=1 a0=1 +FRAME_DLY .equ 48 ; Frame delay (~ 1/44100) +plt_cpuspd .equ 20 ; Non ROMWBW cpu speed default +#ENDIF +; +#IF (plt_type=RC2014) +RSEL .equ 0D8H ; Primary AY-3-8910 Register selection +RDAT .equ 0D0H ; Primary AY-3-8910 Register data +RSEL2 .equ 0A0H ; Secondary AY-3-8910 Register selection +RDAT2 .equ 0A1H ; Secondary AY-3-8910 Register data +PSG1REG .equ 0FFH ; Primary SN76489 +PSG2REG .equ 0FBH ; Secondary SN76489 +YM2151_SEL1 .equ 0FEH ; Primary YM2151 register selection +YM2151_DAT1 .equ 0FFH ; Primary YM2151 register data +YM2151_SEL2 .equ 0D0H ; Secondary YM2151 register selection +YM2151_DAT2 .equ 0D1H ; Secondary YM2151 register data +ctcbase .equ 000H ; CTC base address +YMSEL .equ 000H ; Primary YM2162 11000000 a1=0 a0=0 +YMDAT .equ 000H ; Primary YM2162 11000001 a1=0 a0=1 +YM2SEL .equ 000H ; Secondary YM2162 11000010 a1=1 a0=0 +YM2DAT .equ 000H ; Secondary YM2162 11000011 a1=1 a0=1 +FRAME_DLY .equ 12 ; Frame delay (~ 1/44100) +plt_cpuspd .equ 7 ; Non ROMWBW cpu speed default +#ENDIF +; +#IF (plt_type=sbcecb) +RSEL .equ 0D8H ; Primary AY-3-8910 Register selection +RDAT .equ 0D0H ; Primary AY-3-8910 Register data +RSEL2 .equ 0A0H ; Secondary AY-3-8910 Register selection +RDAT2 .equ 0A1H ; Secondary AY-3-8910 Register data +VGMBASE .equ $C0 +YMSEL .equ VGMBASE+00H ; Primary YM2162 11000000 a1=0 a0=0 +YMDAT .equ VGMBASE+01H ; Primary YM2162 11000001 a1=0 a0=1 +YM2SEL .equ VGMBASE+02H ; Secondary YM2162 11000010 a1=1 a0=0 +YM2DAT .equ VGMBASE+03H ; Secondary YM2162 11000011 a1=1 a0=1 +PSG1REG .equ VGMBASE+06H ; Primary SN76489 +PSG2REG .equ VGMBASE+07H ; Secondary SN76489 +ctcbase .equ VGMBASE+0CH ; CTC base address +YM2151_SEL1 .equ 0FEH ; Primary YM2151 register selection +YM2151_DAT1 .equ 0FFH ; Primary YM2151 register data +YM2151_SEL2 .equ 0FEH ; Secondary YM2151 register selection +YM2151_DAT2 .equ 0FFH ; Secondary YM2151 register data +FRAME_DLY .equ 13 ; Frame delay (~ 1/44100) +plt_cpuspd .equ 8 ; Non ROMWBW cpu speed default +#ENDIF +; +#IF (plt_type=MBC) +RSEL .equ 0A0H ; Primary AY-3-8910 Register selection +RDAT .equ 0A1H ; Primary AY-3-8910 Register data +RSEL2 .equ 0D8H ; Secondary AY-3-8910 Register selection +RDAT2 .equ 0D0H ; Secondary AY-3-8910 Register data +YMSEL .equ 0C0H ; 11000000 a1=0 a0=0 +YMDAT .equ 0C1H ; 11000001 a1=0 a0=1 +YM2SEL .equ 0C2H ; 11000010 a1=1 a0=0 +YM2DAT .equ 0C3H ; 11000011 a1=1 a0=1 +PSG1REG .equ 0C6H ; Primary SN76489 +PSG2REG .equ 0C7H ; Secondary SN76489 +ctcbase .equ 000H ; CTC base address +YM2151_SEL1 .equ 0FEH ; Primary YM2151 register selection +YM2151_DAT1 .equ 0FFH ; Primary YM2151 register data +YM2151_SEL2 .equ 0FEH ; Secondary YM2151 register selection +YM2151_DAT2 .equ 0FFH ; Secondary YM2151 register data +FRAME_DLY .equ 13 ; Frame delay (~ 1/44100) +plt_cpuspd .equ 8 ; Non ROMWBW cpu speed default +#ENDIF +; +;------------------------------------------------------------------------------ +; Configure timing loop +;------------------------------------------------------------------------------ +; +cpu_loop: .equ 0 +ctc_poll: .equ 1 +ctc_int: .equ 2 ; not implemented +; +delay_type: .equ cpu_loop ; cpu timed loop or utilize ctc +delay_wait .equ 0 ; funny wait mode for ctc +; +D60 .equ 735 ; 735x60=44100 Frame delay values for ntsc +D50 .equ 882 ; 882x50=44100 Frame delay values for pal +; +;------------------------------------------------------------------------------ +; CTC Defaults +;------------------------------------------------------------------------------ +; +ctcdiv0 .equ 1 ; Divider chain for 3.579545MHz input +ctcdiv1 .equ 1 ; Ctc with 3 step divider base address +ctcdiv2 .equ 16 +ctcdiv3 .equ 3 ; 3579545 / 1 / 2 / 41 = 43653 = 1% error ; ;------------------------------------------------------------------------------ ; Processor speed control for SBCV2004+ ;------------------------------------------------------------------------------ ; ;#DEFINE SBCV2004 ; My SBC board at 12Mhz needs this to switch to -HB_RTCVAL .EQU 0FFEEH ; 6MHz for it to work with the ECB-VGM reliably. -RTCIO .EQU 070H - +HB_RTCVAL .equ 0FFEEH ; 6MHz for it to work with the ECB-VGM reliably. +RTCIO .equ 070H +; ;------------------------------------------------------------------------------ -; YM2162 Register write macros +; YM2162 Register write macros - with wait and timeout ;------------------------------------------------------------------------------ ; #DEFINE setreg(reg,val) \ @@ -132,53 +185,57 @@ RTCIO .EQU 070H #DEFCONT \ out (YMSEL),a #DEFCONT \ ld a,val #DEFCONT \ out (YMDAT),a +#DEFCONT \ ld b,0 #DEFCONT \ in a,(YMSEL) #DEFCONT \ rlca -#DEFCONT \ jp c,$-3 +#DEFCONT \ jp nc,$+5 +#DEFCONT \ djnz $-6 ; #DEFINE setreg2(reg,val) \ #DEFCONT \ ld a,reg #DEFCONT \ out (YM2SEL),a #DEFCONT \ ld a,val #DEFCONT \ out (YM2DAT),a +#DEFCONT \ ld b,0 #DEFCONT \ in a,(YMSEL) #DEFCONT \ rlca -#DEFCONT \ jp c,$-3 +#DEFCONT \ jp nc,$+5 +#DEFCONT \ djnz $-6 ;------------------------------------------------------------------------------ ; VGM Codes ;------------------------------------------------------------------------------ -VGM_GG_W .EQU 04FH ; GAME GEAR PSG STEREO. WRITE DD TO PORT 0X06 -VGM_PSG1_W .EQU 050H ; PSG (SN76489/SN76496) #1 WRITE VALUE DD -VGM_PSG2_W .EQU 030H ; PSG (SN76489/SN76496) #2 WRITE VALUE DD -VGM_YM26121_W .EQU 052H ; YM2612 #1 WRITE VALUE DD -VGM_YM26122_W .EQU 053H ; YM2612 #2 WRITE VALUE DD -VGM_WNS .EQU 061H ; WAIT N SAMPLES -VGM_W735 .EQU 062H ; WAIT 735 SAMPLES (1/60TH SECOND) -VGM_W882 .EQU 063H ; WAIT 882 SAMPLES (1/50TH SECOND) -VGM_ESD .EQU 066H ; END OF SOUND DATA -VGM_YM21511_W .EQU 054H ; YM2612 #1 WRITE VALUE DD -VGM_YM21512_W .EQU 0A4H ; YM2612 #2WRITE VALUE DD +VGM_GG_W .equ 04FH ; GAME GEAR PSG STEREO. WRITE DD TO PORT 0X06 +VGM_PSG1_W .equ 050H ; PSG (SN76489/SN76496) #1 WRITE VALUE DD +VGM_PSG2_W .equ 030H ; PSG (SN76489/SN76496) #2 WRITE VALUE DD +VGM_YM26121_W .equ 052H ; YM2612 #1 WRITE VALUE DD +VGM_YM26122_W .equ 053H ; YM2612 #2 WRITE VALUE DD +VGM_WNS .equ 061H ; WAIT N SAMPLES +VGM_W735 .equ 062H ; WAIT 735 SAMPLES (1/60TH SECOND) +VGM_W882 .equ 063H ; WAIT 882 SAMPLES (1/50TH SECOND) +VGM_ESD .equ 066H ; END OF SOUND DATA +VGM_YM21511_W .equ 054H ; YM2612 #1 WRITE VALUE DD +VGM_YM21512_W .equ 0A4H ; YM2612 #2 WRITE VALUE DD ;------------------------------------------------------------------------------ ; Generic CP/M definitions ;------------------------------------------------------------------------------ -BOOT .EQU 0000H ; boot location -BDOS .EQU 0005H ; bdos entry point -FCB .EQU 005CH ; file control block -FCBCR .EQU FCB + 20H ; fcb current record -BUFF .EQU 0080H ; DMA buffer -TOPM .EQU 0002H ; Top of memory +BOOT .equ 0000H ; boot location +BDOS .equ 0005H ; bdos entry point +FCB .equ 005CH ; file control block +FCBCR .equ FCB + 20H ; fcb current record +BUFF .equ 0080H ; DMA buffer +TOPM .equ 0002H ; Top of memory -PRINTF .EQU 9 ; BDOS print string function -OPENF .EQU 15 ; BDOS open file function -CLOSEF .EQU 16 ; BDOS close file function -READF .EQU 20 ; BDOS sequential read function +PRINTF .equ 9 ; BDOS print string function +OPENF .equ 15 ; BDOS open file function +CLOSEF .equ 16 ; BDOS close file function +READF .equ 20 ; BDOS sequential read function -CR .EQU 0DH ; carriage return -LF .EQU 0AH ; line feed +CR .equ 0DH ; carriage return +LF .equ 0AH ; line feed ;------------------------------------------------------------------------------ ; Program Start @@ -188,12 +245,29 @@ LF .EQU 0AH ; line feed LD (OLDSTACK),SP ; save old stack pointer LD SP,STACK ; set new stack pointer - - LD DE,MSG_WELC ; Welcome Message - CALL PRTSTR - +; +#IF (delay_type==cpu_loop) + call setfdelay ; Setup the frame delay based on cpu speed +#ENDIF +; +#IF (delay_type==ctc_poll) + call cfgctc_poll ; If building for polled ctc, initialize it +#ENDIF +; +#IF (delay_type==ctc_int) ; If building for interrupt driven ctc, initialize it + call cfgctc_int +#ENDIF +; +#IF (debug) +; LD A,0 ; tone to validate presence +;TST: LD C,PSG1REG +; OUT (C),A +; LD C,PSG2REG +; OUT (C),A +; JR TST +#ENDIF + call welcome ; Welcome message and build debug info CALL READVGM ; Read in the VGM file - CALL VGMINFO ; Check and display VGM Information LD HL, (VGMDATA + 34H) ; Determine start of VGM @@ -209,21 +283,50 @@ _S1 LD DE, VGMDATA + 34H LD (VGMDLY), HL MAINLOOP CALL PLAY ; Play one frame - - LD C,6 ; Check for keypress +; + LD HL,KEYCHK ; Check for keypress + DEC (HL) + JR NZ,NO_CHK + LD C,6 ; Every 256 commands LD E,0FFH CALL BDOS OR A JR NZ,EXIT +NO_CHK: +#IF (delay_type==cpu_loop) + LD HL,(VGMDLY) ; Frame delay +fdelay: .equ $+1 +lp1: LD B,FRAME_DLY ; 44100 one frame = 0.0000226757 seconds + DJNZ $ + DEC HL + LD A,H + OR L + JR NZ,lp1 +#ENDIF - LD HL,(VGMDLY) ; Frame delay -L1 LD B,FRAME_DLY - DJNZ $ - DEC HL - LD A,H - OR L - JR NZ,L1 - +#IF (delay_type==ctc_poll) + LD HL,(VGMDLY) ; Frame delay +lp1: in a,(ctcch3) ; wait for counter to reach zero + dec a + jr nz,lp1 +#IF (delay_wait) +lp2: in a,(ctcch3) ; wait for counter to pass zero + dec a + jr z,lp2 + +lp3: in a,(ctcch3) ; wait for counter to reach zero + dec a + jr nz,lp3 +#ENDIF + DEC HL + LD A,H + OR L + JR NZ,lp1 +#ENDIF +; +#IF (delay_type==ctc_int) +#ENDIF +; JR MAINLOOP ; ;------------------------------------------------------------------------------ @@ -240,6 +343,194 @@ EXIT: CALL VGMDEVICES ; Display devices used EXIT_ERR: CALL PRTSTR ; Generic message or error LD SP, (OLDSTACK) ; Exit to CP/M RST 00H + DI + HALT +; +;------------------------------------------------------------------------------ +; Welcome +;------------------------------------------------------------------------------ +; +welcome: LD DE,MSG_WELC ; Welcome Message + CALL PRTSTR +; +#IF (plt_romwbw) + LD DE,MSG_ROMWBW ; display system type + CALL PRTSTR +#ENDIF +; + LD A,delay_type ; display build type + LD DE,MSG_CPU + CALL PRTIDXDEA +; + LD A,plt_type ; display system type + LD DE,MSG_CUSTOM + CALL PRTIDXDEA + call CRLF +; +#IF (debug) +#IF (delay_type==cpu_loop) + ld a,'f' ; Display frame rate delay + call PRTCHR + call PRTDOT + ld a,(fdelay) + call PRTDECB + LD A,' ' +#ENDIF + CALL PRTCHR + ld a,'c' + call PRTCHR + call PRTDOT + ld a,ctcdiv0 ; Display ctc divider values + call PRTDECB + CALL PRTDOT + ld a,ctcdiv1 + call PRTDECB + CALL PRTDOT + ld a,ctcdiv2 + call PRTDECB + CALL PRTDOT + ld a,ctcdiv3 + call PRTDECB +; +#IF (delay_wait) + ld a,' ' + CALL PRTCHR + LD A,'w' ; Display if using double wait + CALL PRTCHR +#ENDIF +#ENDIF + CALL CRLF + ret +; +;------------------------------------------------------------------------------ +; Setup frame delay value - Loop count for DJNZ $ loop +;------------------------------------------------------------------------------ +; +setfdelay: +#IF (delay_type==cpu_loop) +#IF (plt_romwbw) + LD BC,$F8F0 ; GET CPU SPEED + RST 08 ; FROM HBIOS + LD A,L ; +#ELSE + ld a,plt_cpuspd ; USE STANDALONE CPU SPEED +#ENDIF + LD HL,CLKTBL-1 ; CPU SPEED + ADD A,L ; INDEXES + LD L,A ; INTO + ADC A,H ; TABLE + SUB L + LD H,A ; LOOK IT UP IN THE + LD A,(HL) ; CLOCK TABLE + + LD (fdelay),A ; SAVE LOOP COUNTER FOR CPU SPEED + RET + +;------------------------------------------------------------------------------ +; Frame delay values for different processor speeds. +;------------------------------------------------------------------------------ +; +; 1/44100hz = 22676ns +; 16Mhz = 62.5ns : DJNZ $ = 1 frame delay= 22676ns/13*62.5ns = 27.91 +; 12Mhz = 83.3ns : DJNZ $ = 1 frame delay= 22676ns/13*83.3ns = 20.94 +; 10Mhz = 100ns : DJNZ $ = 1 frame delay= 22676ns/13*100ns = 17.44 +; 8Mhz = 125ns : DJNZ $ = 1 frame delay= 22676ns/13*125ns = 13.95 +; 7.3728Mhz = 135.6ns : DJNZ $ = 1 frame delay= 22676ns/13*135.6ns = 12.86 +; 6Mhz = 166.6s : DJNZ $ = 1 frame delay= 22676ns/13*166.6ns = 10.47 +; 4Mhz = 250ns : DJNZ $ = 1 frame delay= 22676ns/13*250ns = 6.98 +; 2Mhz = 500ns : DJNZ $ = 1 frame delay= 22676ns/13*500ns = 3.49 +; 1Mhz = 1000ns : DJNZ $ = 1 frame delay= 22676ns/13*1000ns = 1.74 +; +CLKTBL: .DB 1 ; 1Mhz ; none of these + .DB 3 ; 2Mhz ; have been + .DB 0 ; 3Mhz ; validated + .DB 6 ; 4Mhz + .DB 0 ; 5Mhz + .DB 10 ; 6Mhz + .DB 12 ; 7Mhz 7.3728Mhz + .DB 13 ; 8Mhz + .DB 0 ; 9Mhz + .DB 17 ; 10Mhz + .DB 0 ; 11Mhz + .DB 20 ; 12Mhz + .DB 0 ; 13Mhz + .DB 0 ; 14Mhz + .DB 0 ; 15Mhz + .DB 27 ; 16Mhz + .DB 0 ; 17Mhz + .DB 0 ; 18Mhz + .DB 0 ; 19Mhz + .DB 0 ; 20Mhz +#ENDIF +; +;------------------------------------------------------------------------------ +; Initialize CTC +;------------------------------------------------------------------------------ +; +; %01010011 ; CTC DEFAULT CONFIG +; %01010111 ; CTC COUNTER MODE CONFIG +; %11010111 ; CTC COUNTER INTERRUPT MODE CONFIG +; |||||||+-- CONTROL WORD FLAG +; ||||||+--- SOFTWARE RESET +; |||||+---- TIME CONSTANT FOLLOWS +; ||||+----- AUTO TRIGGER WHEN TIME CONST LOADED +; |||+------ RISING EDGE TRIGGER +; ||+------- TIMER MODE PRESCALER (0=16, 1=256) +; |+-------- COUNTER MODE +; +--------- INTERRUPT ENABLE +; +cfgctc_poll: +; +ctcch0 .equ ctcbase +ctcch1 .equ ctcbase+1 +ctcch2 .equ ctcbase+2 +ctcch3 .equ ctcbase+3 +; +ctccfg0 .equ %01010011 +ctccfg1 .equ %01010111 +ctccfg2 .equ %01010111 +ctccfg3 .equ %01010111 +; + ld a,ctccfg0 & $7f ; ; Channel 0 + out (ctcch0),a +; + ld a,ctccfg1 & $7f ; Channel 1 + out (ctcch1),a ; + ld a,ctcdiv1 & $ff ; + out (ctcch1),a ; +; + ld a,ctccfg2 & $7f ; Channel 2 + out (ctcch2),a ; + ld a,ctcdiv2 & $ff ; + out (ctcch2),a ; +; + ld a,ctccfg3 & $7f ; Channel 3 + out (ctcch3),a ; + ld a,ctcdiv3 & $ff ; + out (ctcch3),a ; +; + ret +; +#IF (debug) +ctctest: + ld b,0 + +ctclp1: in a,(ctcch3) ; wait for counter to reach zero + dec a + jr nz,ctclp1 + +ctclp2: in a,(ctcch3) ; wait for counter to pass zero + dec a + jr z,ctclp2 + + call PRTDOT +; + djnz ctclp1 +#ENDIF + ret +; +cfgctc_int: + ret ; ;------------------------------------------------------------------------------ ; Read VGM file into memory @@ -406,18 +697,19 @@ NEXT LD A, (HL) LD HL, (VGMDATA + 1CH) ; Loop offset LD A, H OR L - JP Z, EXIT + JP Z, EXIT LD DE, VGMDATA + 1CH ADD HL, DE LD (VGMPOS), HL JR NEXT -NEXT1 CP VGM_GG_W ; Game Gear SN76489 stereo. Ignored - JR NZ, PSG - LD IX,VGM_DEV - SET 0,(IX+1) - INC HL - JR NEXT +NEXT1: +; CP VGM_GG_W ; Game Gear SN76489 stereo. Ignored +; JR NZ, PSG +; LD IX,VGM_DEV +; SET 0,(IX+1) +; INC HL +; JR NEXT ; SN76489 SECTION @@ -426,7 +718,6 @@ PSG CP VGM_PSG1_W ; Write byte to SN76489. LD A, (HL) INC HL OUT (PSG1REG), A - LD IX,VGM_DEV SET 0,(IX+0) JR NEXT @@ -435,7 +726,6 @@ PSG2 CP VGM_PSG2_W ; Write byte to second SN76489. LD A, (HL) INC HL OUT (PSG2REG), A - LD IX,VGM_DEV SET 1,(IX+0) JR NEXT @@ -452,14 +742,12 @@ AY CP 0A0H LD A, (HL) INC HL OUT (RDAT2), A - LD IX,VGM_DEV SET 2,(IX+0) JR NEXT AY1 OUT (RSEL), A LD A, (HL) INC HL OUT (RDAT), A - LD IX,VGM_DEV SET 3,(IX+0) JR NEXT @@ -473,7 +761,6 @@ YM2162_1 CP VGM_YM26121_W LD A,(HL) OUT (YMDAT),A INC HL - LD IX,VGM_DEV SET 4,(IX+0) JP NEXT ; @@ -485,7 +772,6 @@ YM2162_2 CP VGM_YM26122_W LD A,(HL) OUT (YM2DAT),A INC HL - LD IX,VGM_DEV SET 4,(IX+0) ; 2nd channel JP NEXT @@ -499,7 +785,6 @@ YM2151_1 CP VGM_YM21511_W LD A,(HL) OUT (YM2151_DAT1),A INC HL - LD IX,VGM_DEV SET 6,(IX+0) JP NEXT ; @@ -511,7 +796,6 @@ YM2151_2 CP VGM_YM21512_W LD A,(HL) OUT (YM2151_DAT2),A INC HL - LD IX,VGM_DEV SET 7,(IX+0) JP NEXT ; @@ -551,8 +835,7 @@ WAIT1 CP 70H ; WAIT 0-15 SAMPLES LD (VGMDLY), HL RET ; -UNK LD IX,VGM_DEV ; Set flag for - SET 0,(IX+1) ; unknown device +UNK: SET 0,(IX+1) ; unknown device INC HL ; Try and skip JP NEXT ; @@ -609,12 +892,6 @@ CHKDEV: AND %00000011 ; Display CALL PRTCHR ; Skip if not CALL PRTSTR ; used. RET - -DEBUG: PUSH AF - LD A,'*' - CALL PRTCHR - POP AF - RET ; ;------------------------------------------------------------------------------ ; Mute Devices. @@ -939,6 +1216,28 @@ FASTIO: RET ; ;------------------------------------------------------------------------------ +; PRINT THE nTH STRING IN A LIST OF STRINGS WHERE EACH IS TERMINATED BY 0 +; A REGISTER DEFINES THE nTH STRING IN THE LIST TO PRINT AND DE POINTS +; TO THE START OF THE STRING LIST. +;------------------------------------------------------------------------------ +; +PRTIDXDEA: + LD C,A + OR A +PRTIDXDEA1: + JR Z,PRTIDXDEA3 ; FOUND TARGET SO EXIT +PRTIDXDEA2: + LD A,(DE) ; LOOP UNIT + INC DE ; WE REACH + OR A ; END OF STRING + JR NZ,PRTIDXDEA2 + DEC C ; AT STRING END. SO GO + JR PRTIDXDEA1 ; CHECK FOR INDEX MATCH +PRTIDXDEA3: + CALL PRTSTR ; DISPLAY THE STRING + RET +; +;------------------------------------------------------------------------------ ; External routines. ;------------------------------------------------------------------------------ ; @@ -948,8 +1247,8 @@ FASTIO: ; Strings and constants. ;------------------------------------------------------------------------------ ; -MSG_WELC: .DB "VGM Player for RomWBW v0.3, 2-Jul-2022",CR,LF -; .DB "J.B. Langston/Marco Maccaferri/Phil Summers",CR,LF +MSG_WELC: .DB "VGM Player v0.4, 11-Dec-2022" +; .DB CR,LF, "J.B. Langston/Marco Maccaferri/Ed Brindley/Phil Summers",CR,LF .DB 0 MSG_BADF: .DB "Not a VGM file",CR,LF,0 MSG_PO .DB "Played on : ",0 @@ -963,6 +1262,15 @@ MSG_NOFILE: .DB "File not found", CR, LF, 0 MSG_MEM: .DB "File to big", CR, LF, 0 MSG_TITLE: .DB " from: ",0 MSG_TRACK .DB "Playing: ",0 +MSG_CPU .DB "[cpu]",0 +MSG_CTCPOLL .DB "[ctc polled]",0 +MSG_CTCINT .DB "[ctc interrupts]",0 +MSG_ROMWBW .DB " [romwbw] ",0 +MSG_CUSTOM .DB " [custom] ",0 +MSG_P8X180 .DB " [p8x180] ",0 +MSG_RC2014 .DB " [rc2014] ",0 +MSG_SBCECB .DB " [sbc] ",0 +MSG_MBC .DB " [mbc] ",0 ; ;------------------------------------------------------------------------------ ; Variables @@ -970,10 +1278,17 @@ MSG_TRACK .DB "Playing: ",0 ; VGMPOS .DW 0 VGMDLY .DW 0 -VGMUNK_F .DB 0 ; Flag for unknown device -VGM_DEV .DB %00000000 ; yyYYAASS - .DB %00000000 ; Unimplemented device flags - +KEYCHK .DB 0 ; Counter for keypress checks +; +VGM_DEV .DB %00000000 ; IX+0 Flags for devices + ; xx...... ym2151 1 & 2 + ; ..x..... ym2612 2 (not supported) + ; ...x.... ym2612 1 + ; ....xx.. ay-3-8910 1 & 2 + ; ......xx sn76489 1 & 2 + + .DB %00000000 ; IX+1 Unimplemented device flags & future devices +; OLDSTACK .DW 0 ; original stack pointer .DS 40H ; space for stack STACK ; top of stack diff --git a/Source/Apps/VGM/vgmplay.txt b/Source/Apps/VGM/vgmplay.txt index 4b45ab72..28c81d83 100644 --- a/Source/Apps/VGM/vgmplay.txt +++ b/Source/Apps/VGM/vgmplay.txt @@ -5,7 +5,14 @@ Simple player for VGM (Video Game Music) files. Usage: - VGMPLAY MUSIC.VGM + VGMPLAY MUSIC[.VGM] + +Supported devices: + + SN76489 + AY-3-89810 + YM2612/YM3484 + YM2151 Default Ports: @@ -21,23 +28,29 @@ Note: The player should be compatible with VGM files up to version 1.51 but there are very few controls (if any) in the code, be sure to have a good VGM file that doesn't contain much extra data. These files can be very big, the player is limited to the available TPA space which is -typically around 54-55k, bigger files will overwrite the CP/M code and/or -wrap around the 64k limit. - -The played is designed to run on a standard RC2014 with a 7.3728 MHz clock, -if your system uses a different clock you need to adjust the frame delay accordingly. - +typically around 52k. Example Music Files =================== -LEMMIN01.VGM - SN76489 - Lemmings: Title Screen -PENGUI03.VGM - AY-3-8910 - Penguin Adventure: Forest Path -PITFAL02.VGM - 2xSN76489 - Pitfall II: Scene 1 -TIGER02.VGM - 2xAY-3-8910 - Tiger Hely: First Mission -WONDER01.VGM - 2xSN76489 - Wonder Boy in Monster Land -FILTHY01.VGM - YM3484 - Columns : Filthy -ITSGAMOV.VGM - YM3484+SN76489 - Puyo Puyo Tsuu : It's Game Over! - -Original Source by J.B Langston, Marco Maccaferri -ROMWBW + YM2612/YM3484 version by Phil Summers \ No newline at end of file +ENDING.VGM - AY-3-8910 * Puyo Puyo: Ending (Unused) : 24K +QIX.VGM - AY-3-8910 - Super Qix: Main BGM 2 : 28K +AGGRESS.VGM - AY-3-8910 - Rastan Saga: Aggressive World : 32K +PENGUI03.VGM - AY-3-8910 - Penguin Adventure: Forest Path : 44K +TIGER02.VGM - 2xAY-3-8910 - Tiger Hely: First Mission : 28K +BGM.VGM - 2xAY-3-8910 * SHM: BGM : 8K +LEMMIN01.VGM - SN76489 - Lemmings: Title Screen : 44K +TEDDY.VGM - 2xSN76489 - TeddyBoy Blues: Title ~ Main Theme : 52K +PITFAL02.VGM - 2xSN76489 - Pitfall II: Scene 1 : 16K +WONDER01.VGM - 2xSN76489 * Wonder Boy in Monster Land: Monster Land : 40K +DESCENT.VGM - SN76489+YM2612 - Flashback: The Quest for Identity: Descent into the Tunnels : 40K +SHIRAKAW.VGM - SN76489+YM2612 * Jantei Monogatari: St. Shirakawa University : 32K +ANNA.VGM - SN76489+YM2612 - Jantei Monogatari: Anna : 32K +FIELDMAP.VGM - SN76489+YM2612 - Taikou Risshiden: Field Map: Summer : 8K +ITSGAMOV.VGM - SN76489+YM2612 - Puyo Puyo Tsuu: It's Game Over! : 16K +STARTDEM.VGN - 2xSN76489+AY-3-8910 * Exed Exes / Savage Bees: Start Demo ~Main BGM : 32K +INCHINA.VGM - YM2612 * Double Dragon 3: The Rosetta Stone: In China : 44K + +* Included in disk images + +Original Source by J.B Langston, Marco Maccaferri, Ed Brindley. ROMWBW version by Phil Summers.