; 4 KB Bios
; can be assembled correctly now
; corrected and compatibilty added by Christopher Salomon
;
; assemble with comand line:
; .\ass\as09.exe -w200 -h0 -l -mcti bios.asm >error
;
; used the 6809 assembler:
; as09 [1.11].
; Copyright 1990-1994, Frank A. Vorstenbosch, Kingswood Software.
; Available at:
; http://www.falstaff.demon.co.uk/cross.html
;
                CODE
                ORG     $F000
                DATA
                ORG     $F000
                BSS
                ORG     $F000
                CODE
;-----------------------------------------------------------------------;
; This disassembly of the Vectrex ROM was done by Bruce Tomlin          ;
; (btomlin@aol.com), and is based in part on a disassembly done by      ;
; Fred Taft (fred@hp-pcd.cv.hp.com).                                    ;
;-----------------------------------------------------------------------;

                INCLUDE "VECTREX.INC"

;-----------------------------------------------------------------------;
;       F000    Start                                                   ;
;                                                                       ;
; Jump here to restart the Vectrex and re-initialize the OS.  If the    ;
; cold start flag is correct (it should be unless you just turned the   ;
; Vectrex on), the cold start code is skipped.                          ;
;                                                                       ;
; On cold start, the high score is cleared, and the power-on screen     ;
; is displayed with the power-on music.                                 ;
;-----------------------------------------------------------------------;

Start:          LDS     #Vec_Default_Stk ;Set up stack pointer
                JSR     Init_OS         ;Initialize system
                LDD     #$7321          ;Check cold start flag
                CMPD    Vec_Cold_Flag
                BEQ     Warm_Start      ;Branch if warm start
                STD     Vec_Cold_Flag   ;Initialize cold start flag
                INC     $C83B           ;Set high score invalid flag
                LDX     #Vec_High_Score ;Clear high score
                JSR     Clear_Score

;       First power-up loop.  This prints the "VECTREX"
;       power-on screen and plays the power-on music.

LF01C:          JSR     DP_to_C8        ;DP to RAM
                LDD     <Vec_Loop_Count ;When we have looped 257 times,
                CMPD    #$0101
                BNE     LF029
                STB     <Vec_Music_Flag ;start the intro music

;       Get the line pattern for the boundary box lines

LF029:          ASRB                    ;Get line pattern from table
                ANDB    #$03
                LDX     #DF0FD
                LDB     B,X
                STB     <Vec_Pattern    ;Store pattern

                LDB     #$02            ;Set up counter for two boxes
                STB     <$C824

;       Play the intro music

                LDU     #Intro_Music    ;Get address of music
                JSR     Init_Music_chk  ;Initialize the music
                JSR     Wait_Recal      ;Wait for next frame
                JSR     Do_Sound        ;Play music if active

;       Display power-up message

                JSR     Intensity_7F    ;Normal brightness
                LDA     $C826           ;Alternate size every 32 loops
                LDU     #Vec_Title     ;Load address of double high text
                BITA    #$20
                BEQ     LF052
                LEAU    <<(Vec_Title_2-Vec_Title),U  ;Skip double high text
LF052:          JSR     Print_List_hw   ;Print startup text

;       Draw the frame boxes

                LDX     #Intro_Boxes
LF058:          JSR     Moveto_ix_FF    ;Move to start of line
                LDA     #$03            ;Draw 4 lines
                JSR     Draw_Pat_VL_a
                DEC     $C824           ;Go back for next box
                BNE     LF058
                LDA     Vec_Loop_Count
                CMPA    #$01            ;Repeat for 512 counts
                BLS     LF01C

;-----------------------------------------------------------------------;
;       F06C    Warm_Start                                              ;
;                                                                       ;
; Jump here to restart the Vectrex without re-initializing the OS.      ;
;-----------------------------------------------------------------------;

;       Prepare for ROM check

Warm_Start:     JSR     DP_to_C8        ;DP to RAM
                LDA     #$CC            ;Set new line pattern
                STA     <Vec_Pattern
                LDD     #Copyright_Str  ;Save copyright string addr
                STD     <$C839
                CLR     <Vec_Loop_Count ;Clear loop counter
                CLR     <Vec_Loop_Count+1

;       Check for valid cartridge ROM

                LDU     #$0000          ;Look at address zero
                LDX     #Copyright_Str
                LDB     #$0B            ;11 bytes long
LF084:          LDA     ,U+             ;Compare next byte
                CMPA    ,X+
                BEQ     LF097           ;Okay if match
                CMPB    #$01            ;Not okay if last byte wrong
                BEQ     LF092
                CMPB    #$05            ;Okay if date wrong
                BLS     LF097
LF092:          LDU     #$E000          ;Bad cart; load Mine Storm addr
                BRA     LF09E

LF097:          DECB                    ;Go back for next byte
                BNE     LF084
                STB     <$C839          ;Store zero as address of
                STB     <$C83A          ;copyright string

;       Prepare to play game start-up music

LF09E:          INC     <Vec_Music_Flag ;Set music enable flag
                STU     <Vec_Run_Index  ;Save address of header
                LDU     ,U              ;Get address of music

;       Second power-up loop.  This prints the name of the
;       game, the copyright, and plays the start-up music

LF0A4:          JSR     DP_to_C8        ;DP to RAM
                LDD     #$F848          ;???
                STD     <Vec_Text_HW
                JSR     Init_Music_chk  ;Initialize the music
                JSR     Wait_Recal      ;Wait for next frame
                JSR     Do_Sound        ;Play the music if active

;       Display cartridge GCE copyright string

                JSR     Intensity_7F    ;Normal brightness
                LDD     #$C0C0          ;Print copyright string
                LDU     $C839
                JSR     Print_Str_d

;       Display current high score if any

                LDA     $C83B           ;Skip if no high score
                BNE     LF0D2
                DECA
                LDU     #Vec_High_Score
                STA     6,U
                LDD     #$68D0
                JSR     Print_Str_d

;       Display cartridge name

LF0D2:          LDU     Vec_Run_Index   ;Get cartridge header addr
                LEAU    2,U             ;Skip music addr
                JSR     Print_List_hw   ;Print it
                LDA     Vec_Music_Flag  ;Go back if music still playing
                BNE     LF0A4
                LDX     Vec_Loop_Count  ;Go back if count less than 126
                CMPX    #$007D
                BLS     LF0A4
                JMP     1,U             ;Jump into cartridge

;       Outer box (y,x)

Intro_Boxes:    FCB     $40,$D6
                FCB     $00,$56
                FCB     $81,$00
                FCB     $00,$A9
                FCB     $7E,$00

;       Inner box (y,x)

                FCB     $39,$DC
                FCB     $8E,$00
                FCB     $00,$4A
                FCB     $72,$00
                FCB     $00,$B6

;       Line patterns for boundary boxes

DF0FD:          FCB     %11100000
                FCB     %00111000
                FCB     %00001110
                FCB     %00000011

;       Copyright string

Copyright_Str:  FCC     "g GCE 1982"
                FCB     $80
here__:
Copyright_Len   EQU     here__-Copyright_Str

;       Title strings

Vec_Title:      FCB     $F1,$60         ;Height, width
                FCB     $27,$CF         ;Y,X
                FCC     "VECTREX"
                FCB     $80

Vec_Title_2:    FCB     $F3,$60         ;Height, width
                FCB     $26,$CF         ;Y,X
                FCC     "VECTREX"
                FCB     $80

                FCB     $FC,$60         ;Height, width
                FCB     $DF,$E9         ;Y,X
                FCC     "GCE"
                FCB     $80

                FCB     $FC,$38         ;Height, width
                FCB     $CC,$D1         ;Y,X
                FCC     "ENTERTAINING"
                FCB     $80

                FCB     $FC,$38         ;Height, width
                FCB     $BC,$DC         ;Y,X
                FCC     "NEW IDEAS"
                FCB     $80

                FCB     $00

;-----------------------------------------------------------------------;
;       F14C    Init_VIA                                                ;
;                                                                       ;
; This routine is invoked during powerup, to initialize the VIA chip.   ;
; Among other things, it initializes the scale factor to 0x7F, and      ;
; sets up the direction for the port A and B data lines.                ;
;                                                                       ;
; EXIT: DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Init_VIA:       BSR     DP_to_D0
                LDD     #$9FFF          ;Port A=all output
                STD     <VIA_DDR_b      ;Port B=OIIOOOOO
                LDD     #$0100          ;Port B sound BDIR=1
                STD     <VIA_port_b
                LDD     #$987F          ;ACR=$98 T1->PB7 enabled
                STA     <VIA_aux_cntl   ;auxiliary control register
                STB     <VIA_t1_cnt_lo  ;T1CL=$7F scale factor?
                JSR     Reset0Ref
                BRA     Set_Refresh

;-----------------------------------------------------------------------;
;       F164    Init_OS_RAM                                             ;
;                                                                       ;
; This routine first clears the block of RAM in the range $C800 to      ;
; $C87A, and then it initializes the dot dwell time, the refresh time,  ;
; and the joystick enable flags.                                        ;
;                                                                       ;
; EXIT: DP = $C8                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Init_OS_RAM:    BSR     DP_to_C8        ;DP to RAM
                LDB     #$7A            ;Clear $C800-$C87A
                LDX     #$C800
                JSR     Clear_x_b
                LDD     #Vec_Random_Seed;Point $C87B to $C87D
                STD     <Vec_Seed_Ptr
LF173:          INC     <Vec_Random_Seed;Make sure random number
                BEQ     LF173           ;seed is non-zero!
                LDA     #$05            ;Init dot dwell (brightness)
                STA     <Vec_Dot_Dwell
                LDD     #$3075          ;Init refresh time to $7530
                STD     <$C83D
                LDD     #$0103          ;Init joystick enable flags
                STD     <Vec_Joy_Mux_1_X
                LDD     #$0507
                STD     <Vec_Joy_Mux_2_X
                RTS

;-----------------------------------------------------------------------;
;       F18B    Init_OS                                                 ;
;                                                                       ;
; This routine is responsible for setting up the initial system state,  ;
; each time the system is either reset or powered up.  It will          ;
; initialize the OS RAM area, initialize the VIA chip, and then clear   ;
; all the registers on the sound chip.                                  ;
;                                                                       ;
; EXIT: DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Init_OS:        BSR     Init_OS_RAM
                BSR     Init_VIA
                JMP     Clear_Sound

;-----------------------------------------------------------------------;
;       F192    Wait_Recal                                              ;
;                                                                       ;
; Wait for t2 (the refresh timer) to timeout, then restart it using     ;
; the value in $C83D.  then, recalibrate the vector generators to the   ;
; origin (0,0).  This routine MUST be called once every refresh         ;
; cycle, or your vectors will get out of whack.  This routine calls     ;
; Reset0Ref, so the integrators are left in zero mode.                  ;
;                                                                       ;
; EXIT: DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Wait_Recal:     LDX     Vec_Loop_Count  ;Increment loop counter
                LEAX    1,X
                STX     Vec_Loop_Count
                BSR     DP_to_D0        ;DP to I/O
                LDA     #$20
LF19E:          BITA    <VIA_int_flags  ;Wait for timer t2
                BEQ     LF19E

;-----------------------------------------------------------------------;
;       F1A2    Set_Refresh                                             ;
;                                                                       ;
; This routine loads the refresh timer (t2) with the value in $C83D-    ;
; $C83E, and recalibrates the vector generators, thus causing the pen   ;
; to be left at the origin (0,0).  The high order byte for the timer    ;
; is loaded from $C83E, and the low order byte is loaded from $C83D.    ;
; The refresh rate is calculated as follows:                            ;
;                                                                       ;
;   rate = (C83E)(C83D) / 1.5 mhz                                       ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                           ;
;-----------------------------------------------------------------------;

Set_Refresh:    LDD     $C83D           ;Store refresh value
                STD     <VIA_t2_lo      ;into timer t2
                JMP     Recalibrate

;-----------------------------------------------------------------------;
;       F1AA    DP_to_D0                                                ;
;                                                                       ;
; Sets the DP register to $D0, so that all direct page addressing will  ;
; start at $D000 (the hardware I/O area).                               ;
;                                                                       ;
; EXIT: DP = $D0                                                        ;
;       A-reg = $D0                                                     ;
;-----------------------------------------------------------------------;

DP_to_D0:       LDA     #$D0
                TFR     A,DP
                RTS

;-----------------------------------------------------------------------;
;       F1AF    DP_to_C8                                                ;
;                                                                       ;
; Sets the DP register to $C8, so that all direct page addressing will  ;
; start at $C800 (OS RAM area).                                         ;
;                                                                       ;
;                                                                       ;
; EXIT: DP = $C8                                                        ;
;       A-reg = $C8                                                     ;
;-----------------------------------------------------------------------;

DP_to_C8:       LDA     #$C8
                TFR     A,DP
                RTS

;-----------------------------------------------------------------------;
;       F1B4    Read_Btns_Mask                                          ;
;       F1BA    Read_Btns                                               ;
;                                                                       ;
; Both of these routines read the button states on the two joysticks,   ;
; and return their state in the following RAM locations:                ;
;                                                                       ;
;       joystick 1, button 1:  $C812 = $01                              ;
;                   button 2:  $C813 = $02                              ;
;                   button 3:  $C814 = $04                              ;
;                   button 4:  $C815 = $08                              ;
;       joystick 2, button 1:  $C816 = $10                              ;
;                   button 2:  $C817 = $20                              ;
;                   button 3:  $C818 = $40                              ;
;                   button 4:  $C819 = $80                              ;
;                                                                       ;
;       C80F: Contains current state of all buttons;                    ;
;             1 = depressed, 0 = not depressed                          ;
;                                                                       ;
;       C810: Contains state of all buttons from LAST time these        ;
;             routines were called; if Read_Btns_Mask was called,       ;
;             then this is AND'ed with the passed in mask.              ;
;                                                                       ;
;       C811: Contains the same information as $C812-$C819              ;
;                                                                       ;
;        Bit 7                                     Bit 0                ;
;       +-----+-----+-----+-----+-----+-----+-----+-----+               ;
;       | 2.4 | 2.3 | 2.2 | 2.1 | 1.4 | 2.3 | 1.2 | 1.1 |               ;
;       +-----+-----+-----+-----+-----+-----+-----+-----+               ;
;                                                                       ;
; If Read_Btns is called, the result will be the same as Read_Btns_Mask ;
; with a mask of $FF, and a 1 will only be returned if the button       ;
; has transitioned to being pressed.                                    ;
;                                                                       ;
; If Read_Btns_Mask is called, then a mask, passed in in the A-reg      ;
; will be used to determine how the button state info is returned:      ;
;                                                                       ;
; If a bit is 0, then the current state of the button is to be returned ;
; in the appropriate RAM location; 0 = not pressed, and 1 = pressed.    ;
;                                                                       ;
; If a bit is 1, then the appropriate RAM location is set to 1 only     ;
; on the depression transition of the button; additional calls will     ;
; return 0, until the button is released and then depressed again.      ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = mask (for Read_Btns_Mask only)                          ;
;                                                                       ;
; Exit: A-reg = button transition state (same as $C811)                 ;
;                                                                       ;
;       B-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Read_Btns_Mask: ANDA    Vec_Btn_State   ;Mask out "always" buttons
                STA     Vec_Btn_State
Read_Btns:      LDX     #Vec_Button_1_1 ;Point to button flags
                LDA     -3,X            ;Save previous state
                STA     -2,X
                LDA     #$0E            ;Sound chip register 0E to port A
                STA     <VIA_port_a
                LDD     #$1901          ;sound BDIR on, BC1 on, mux off
                STA     <VIA_port_b
                NOP                     ;pause
                STB     <VIA_port_b     ;sound BDIR off, BC1 off, mux off
                CLR     <VIA_DDR_a      ;DDR A to input
                LDD     #$0901          ;sound BDIR off, BC1 on, mux off
                STA     <VIA_port_b
                NOP                     ;pause
                LDA     <VIA_port_a     ;Read buttons
                COMA                    ;Convert to active high
                STA     -3,X            ;Save buttons
                STB     <VIA_port_b     ;sound BDIR off, BC1 off, mux off
                LDB     #$FF
                STB     <VIA_DDR_a      ;DDR A to output
                COMA                    ;Check for transitions
                ORA     -2,X
                COMA
                STA     -1,X            ;Store transition result
                PSHS    A               ;Save result for return value
                LDB     #$01            ;Initialize bit position
LF1EA:          TFR     B,A             ;Mask out bit
                ANDA    ,S
                STA     ,X+             ;Store masked bit
                ASLB                    ;Go back for next bit
                BNE     LF1EA
                PULS    A,PC            ;Get back transition bits and return

;-----------------------------------------------------------------------;
;       F1F5    Joy_Analog                                              ;
;       F1F8    Joy_Digital                                             ;
;                                                                       ;
; These routines read the current positions of the two joysticks.       ;
;                                                                       ;
; The joystick enable flags (C81F-C822) must be initialized to one of   ;
; the following values:                                                 ;
;                                                                       ;
;       0 - ignore; return no value.                                    ;
;       1 - return state of console 1 left/right position.              ;
;       3 - return state of console 1 up/down position.                 ;
;       5 - return state of console 2 left/right position.              ;
;       7 - return state of console 2 up/down position.                 ;
;                                                                       ;
; The joystick values are returned in $C81B-$C81E, where the value      ;
; returned in $C81B corresponds to the mask set in in $C81F, and so     ;
; on and so forth.                                                      ;
;                                                                       ;
; The joystick conversion is dependent on which routine is called.      ;
; Results for each routine are:                                         ;
;                                                                       ;
;       Joy_Digital:                                                    ;
;               The return value will be:                               ;
;                 < 0 if joystick is left of down of center.            ;
;                 = 0 if joystick is centered.                          ;
;                 > 0 if joystick is right or up of center.             ;
;                                                                       ;
;       Joy_Analog:                                                     ;
;               A successive approximation algorithm is used to read    ;
;               the actual value of the joystick pot, a signed value.   ;
;               In this case, $C81A must be set to a power of 2, to     ;
;               to control conversion resolution; 0x80 is least         ;
;               accurate, and 0x00is most accurate.                     ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Joy_Analog:     DEC     $C823           ;Set analog mode flag
Joy_Digital:    LDX     #Vec_Joy_Mux_1_X;Point to first pot
LF1FB:          LDA     ,X+             ;Read it if enabled
                BNE     LF20B
LF1FF:          CMPX    #$C823          ;Go back untl all pots read
                BNE     LF1FB
                CLR     ,X              ;X points to $C823, clear it
                LDA     #$01
                STA     <VIA_port_b     ;disable mux
                RTS

LF20B:          STA     <VIA_port_b     ;enable mux and select pot
                CLR     <VIA_port_a     ;output $00 to D/A
                DEC     <VIA_port_b     ;disable mux
                LDB     #$60            ;delay and end up with B=$80
LF213:          INCB
                BPL     LF213
                LDA     $C823           ;check analog flag
                BMI     LF240           ;branch if analog pot
                LDA     #$20
                INC     <VIA_port_b     ;enable mux
                BITA    <VIA_port_b     ;test comparator
                BEQ     LF22D
                LDB     #$40            ;output $40 to D/A
                STB     <VIA_port_a
                BITA    <VIA_port_b     ;test comparator
                BNE     LF236
                BRA     LF235

LF22D:          LDB     #$C0            ;output $C0 to D/A
                STB     <VIA_port_a
                BITA    <VIA_port_b     ;test comparator
                BEQ     LF236
LF235:          CLRB
LF236:          STB     -5,X            ;store A/D result
                BRA     LF1FF           ;go back for next pot

LF23A:          TFR     B,A
                ORA     <VIA_port_a
                STA     <VIA_port_a
LF240:          LDA     #$20            ;test comparator
                BITA    <VIA_port_b
                BNE     LF24C           ;branch to go lower?
                TFR     B,A
                EORA    <VIA_port_a
                STA     <VIA_port_a
LF24C:          LSRB                    ;try next bit position
                CMPB    Vec_Joy_Resltn  ;check for accuracy threshold
                BNE     LF23A           ;go back if not finished
                LDB     <VIA_port_a     ;read D/A value
                BRA     LF236           ;go back to store it

;-----------------------------------------------------------------------;
;       F256    Sound_Byte                                              ;
;       F259    Sound_Byte_x                                            ;
;       F25B    Sound_Byte_raw                                          ;
;                                                                       ;
; All of these routines cause a byte of music data to be written to     ;
; the music chip.  Sound_Byte stores a shadow copy of the data into     ;
; $C800-$C80E, and Sound_Byte_x stores a shadow copy into a 15 byte     ;
; area pointed to by the X register.  Sound_Byte_raw does not store a   ;
; shadow copy of the data at all.                                       ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = which of the 15 sound chip registers to modify          ;
;       B-reg = the byte of sound data                                  ;
;       X-reg = 15 byte shadow area (Sound_Byte_x only)                 ;
;                                                                       ;
; EXIT: X-reg = $C800 (Sound_Byte only)                                 ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Sound_Byte:     LDX     #Vec_Snd_Shadow ;point to shadow memory
Sound_Byte_x:   STB     A,X
Sound_Byte_raw: STA     <VIA_port_a     ;store register select byte
                LDA     #$19            ;sound BDIR on, BC1 on, mux off
                STA     <VIA_port_b
                LDA     #$01            ;sound BDIR off, BC1 off, mux off
                STA     <VIA_port_b
                LDA     <VIA_port_a     ;read sound chip status (?)
                STB     <VIA_port_a     ;store data byte
                LDB     #$11            ;sound BDIR on, BC1 off, mux off
                STB     <VIA_port_b
                LDB     #$01            ;sound BDIR off, BC1 off, mux off
                STB     <VIA_port_b
                RTS

;-----------------------------------------------------------------------;
;       F272    Clear_Sound                                             ;
;                                                                       ;
; This routine clears the 15 registers on the music chip and the soft   ;
; copy of their values (C800-C80E), by writing a byte of 0 to each      ;
; register.  This causes the sound chip to not make any sounds.         ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Clear_Sound:    LDD     #$0E00
LF275:          BSR     Sound_Byte
                DECA
                BPL     LF275
                JMP     Init_Music_Buf

;-----------------------------------------------------------------------;
;       F27D    Sound_Bytes                                             ;
;       F284    Sound_Bytes_x? (apparently never used)                  ;
;                                                                       ;
; This routine copies a block of sound information into the sound       ;
; chip buffer (at $C800-$C80E) and into the registers on the music      ;
; chip.  The format for the block of sound data is as follows:          ;
;                                                                       ;
;   (register number), (music data),                                    ;
;   (register number), (music data),                                    ;
;         .                  .                                          ;
;         .                  .                                          ;
;       0xFF                                                            ;
;                                                                       ;
; As long as the register number is >= 0, then the music data will be   ;
; copied; however, as soon as a register number < 0 is encountered,     ;
; the copy will stop.                                                   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg = pointer to the block of sound data                      ;
;                                                                       ;
;       D-reg, X-reg, U-reg trashed                                     ;
;-----------------------------------------------------------------------;

Sound_Bytes:    LDX     #Vec_Snd_Shadow ;Point to shadow memory
                BRA     Sound_Bytes_x

LF282:          BSR     Sound_Byte_x    ;Update the sound register
Sound_Bytes_x:  LDD     ,U++            ;Get next next pair of bytes
                BPL     LF282           ;Go back if not end of list
                RTS

;-----------------------------------------------------------------------;
;       F289    Do_Sound                                                ;
;       F28C    Do_Sound_x? (apparently never used)                     ;
;                                                                       ;
; This routine will start/continue making the sound which was first     ;
; set up by your call to Init_Music.  This routine should normally      ;
; be called right after your call to Wait_Recal.  It takes the next     ;
; music information, contained in the music buffer $C83F-$C84C, and     ;
; updates only those registers which differ from the last data written  ;
; to the sound chip.                                                    ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg, U-reg trashed                                     ;
;-----------------------------------------------------------------------;

Do_Sound:       LDX     #Vec_Snd_Shadow ;point to shadow memory
Do_Sound_x:     LDU     #Vec_Music_Work ;point to sound buffer
                LDA     #$0D            ;init count for 14 registers
LF291:          LDB     ,U+             ;get next register
                CMPB    A,X             ;skip if unchanged
                BEQ     LF299
                BSR     Sound_Byte_x    ;else update register
LF299:          DECA                    ;go back for next register
                BPL     LF291
                RTS

;-----------------------------------------------------------------------;
;       F29D    Intensity_1F                                            ;
;       F2A1    Intensity_3F                                            ;
;       F2A5    Intensity_5F                                            ;
;       F2A9    Intensity_7F                                            ;
;       F2AB    Intensity_a                                             ;
;                                                                       ;
; Each of these routines are responsible for setting the vector/dot     ;
; intensity (commonly used to denote the z axis) to a specific value.   ;
; 0x00 is the lowest intensity, and 0xFF is the brightest intensity.    ;
; The intensity must be reset to the desired value after each call      ;
; to Wait_Recal; however, it can also be changed at any other time.     ;
; A copy of the new intensity value is saved in $C827.                  ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = intensity (Intensity_a only)                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Intensity_1F:   LDA     #$1F
                BRA     Intensity_a

Intensity_3F:   LDA     #$3F
                BRA     Intensity_a

Intensity_5F:   LDA     #$5F
                BRA     Intensity_a

Intensity_7F:   LDA     #$7F
Intensity_a:    STA     <VIA_port_a     ;Store intensity in D/A
                STA     Vec_Brightness  ;Save intensity in $C827
                LDD     #$0504          ;mux disabled channel 2
                STA     <VIA_port_b
                STB     <VIA_port_b     ;mux enabled channel 2
                STB     <VIA_port_b     ;do it again just because
                LDB     #$01
                STB     <VIA_port_b     ;turn off mux
                RTS

;-----------------------------------------------------------------------;
;       F2BE    Dot_ix_b                                                ;
;       F2C1    Dot_ix                                                  ;
;                                                                       ;
; These routines draw a dot at the relative y and relative x            ;
; position pointed to by the X register.  Afterwards, the X register    ;
; is incremented by 2.                                                  ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the (y,x) coordinate pair                       ;
;       B-reg contains the intensity (Dot_ix_b only)                    ;
;       $C828 contains the intensity (Dot_ix only)                      ;
;                                                                       ;
; EXIT  X-reg incremented by 2                                          ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Dot_ix_b:       STB     Vec_Dot_Dwell
Dot_ix:         LDD     ,X++

;-----------------------------------------------------------------------;
;       F2C3    Dot_d                                                   ;
;                                                                       ;
; This routine draws a dot at the relative y and relative x position    ;
; contained in the D register.  The intensity used is the value         ;
; already stored in $C828.                                              ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = relative Y coordinate                                   ;
;       B-reg = relative X coordinate                                   ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Dot_d:          BSR     Moveto_d

;-----------------------------------------------------------------------;
;       F2C5    Dot_here                                                ;
;                                                                       ;
; This routine draws a dot at the current pen position.                 ;
; The intensity used is the value already stored in $C828.              ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Dot_here:       LDA     #$FF            ;Set pattern to all 1's
                STA     <VIA_shift_reg  ;Store in VIA shift register
                LDB     Vec_Dot_Dwell   ;Get dot dwell (brightness)
LF2CC:          DECB                    ;Delay leaving beam in place
                BNE     LF2CC
                CLR     <VIA_shift_reg  ;Blank beam in VIA shift register
                RTS

;-----------------------------------------------------------------------;
;       F2D5    Dot_List                                                ;
;                                                                       ;
; This routine draws a series of dots, using the intensity already      ;
; set up in $C828.  The format for the dot list, which is pointed to    ;
; by the X register, is:                                                ;
;                                                                       ;
;     ( rel y, rel x), (rel y, rel x), .....                            ;
;                                                                       ;
; The number of dots to draw is specified in $C823.                     ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the list of dot coordinates                     ;
;       $C823 specifies the number of dots to draw                      ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;       $C823 cleared                                                   ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

LF2D2:          DEC     $C823           ;Decrement counter
Dot_List:       BSR     Dot_ix          ;Draw next dot
                LDA     $C823           ;Check counter
                BNE     LF2D2           ;Go back until finished
                BRA     Reset0Ref       ;Go to Reset0Ref

;-----------------------------------------------------------------------;
;       F2DE    Dot_List_Reset                                          ;
;                                                                       ;
; This routine draws a series of dots, specified by the list pointed    ;
; to by the X register.  The list has the following format:             ;
;                                                                       ;
;     mode, relative y, relative x,                                     ;
;     mode, relative y, relative x,                                     ;
;       .      .           .                                            ;
;       .      .           .                                            ;
;     mode, relative y, relative x                                      ;
;     0x01                                                              ;
;                                                                       ;
; This routine will continue to traverse the list, until a mode > 0     ;
; is encountered; at that point, it will reset the zero reference       ;
; (the integrators).                                                    ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the dot list                                    ;
;                                                                       ;
; EXIT: X-reg points to next byte after the terminator                  ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Dot_List_Reset: LDA     ,X+             ;get mode byte
                BGT     Reset0Ref       ;if >0 go to Reset0Ref
                BSR     Dot_ix          ;plot the dot
                BRA     Dot_List_Reset  ;dot_list@x_&_reset

;-----------------------------------------------------------------------;
;       F2E6    Recalibrate                                             ;
;                                                                       ;
;       Recalibrate the vector generators.                              ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Recalibrate:    LDX     #Recal_Points   ;$7F7F
                BSR     Moveto_ix_FF
                JSR     Reset0Int
                BSR     Moveto_ix       ;$8080
                BRA     Reset0Ref

;-----------------------------------------------------------------------;
;       F2F2    Moveto_x_7F                                             ;
;                                                                       ;
; This routine forces the scale factor to 0x7F, and then moves the      ;
; pen to the location pointed to by the X register.  The relative y     ;
; and relative x coordinates are both 2 byte quantities; however,       ;
; only the most signicant byte of each is of any interest.  The values  ;
; pointed to by the X register have the following format:               ;
;                                                                       ;
;     X => (rel y hi),(rel y lo), (rel x hi), (rel x lo)                ;
;                                                                       ;
; The position moved to is obtained by y=(0,x) & x=(2,x).               ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to double-sized coordinate pair                    ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Moveto_x_7F:    LDB     #$7F            ;Set scale factor to $7F
                STB     <VIA_t1_cnt_lo
                LDA     ,X              ;Get y high
                LDB     2,X             ;Get x high
                BRA     Moveto_d

;-----------------------------------------------------------------------;
;       F2FC    Moveto_d_7F                                             ;
;                                                                       ;
; This routine forces the scale factor to 0x7F, and then moves the      ;
; pen to the position specified in the D register.                      ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = relative Y coordinate                                   ;
;       B-reg = relative X coordinate                                   ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Moveto_d_7F:    STA     <VIA_port_a     ;Store Y in D/A register
                PSHS    D               ;Save D-register on stack
                LDA     #$7F            ;Set scale factor to $7F
                STA     <VIA_t1_cnt_lo
                CLR     <VIA_port_b     ;Enable mux
                BRA     LF318

;-----------------------------------------------------------------------;
;       F308    Moveto_ix_FF                                            ;
;       F30C    Moveto_ix_7F                                            ;
;       F30E    Moveto_ix_b                                             ;
;                                                                       ;
; These routines force the scale factor to 0xFF, 0X7F, or the           ;
; A register, and then move the pen to the (y,x) position pointed to    ;
; by the X-register.  The X-register is then incremented by 2.          ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the (y,x) coordinate pair                       ;
;       B-reg contains the scale factor (Moveto_ix_b only)              ;
;                                                                       ;
; EXIT: X-reg has been incremented by 2                                 ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Moveto_ix_FF:   LDB     #$FF
                BRA     Moveto_ix_b

Moveto_ix_7F:   LDB     #$7F
Moveto_ix_b:    STB     <VIA_t1_cnt_lo  ;Set scale factor

;-----------------------------------------------------------------------;
;       F310    Moveto_ix                                               ;
;                                                                       ;
; This routine uses the current scale factor, and moves the pen to the  ;
; (y,x) position pointed to by the X register.  The X register is then  ;
; incremented by 2.                                                     ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the (y,x) coordinate pair                       ;
;                                                                       ;
; EXIT: X-reg has been incremented by 2                                 ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Moveto_ix:      LDD     ,X++

;-----------------------------------------------------------------------;
;       F312    Moveto_d                                                ;
;                                                                       ;
; This routine uses the current scale factor, and moves the pen to the  ;
; (y,x) position specified in D register.                               ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = Y coordinate                                            ;
;       B-reg = X coordinate                                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Moveto_d:       STA     <VIA_port_a     ;Store Y in D/A register
                CLR     <VIA_port_b     ;Enable mux
                PSHS    D               ;Save D-register on stack
LF318:          LDA     #$CE            ;Blank low, zero high?
                STA     <VIA_cntl
                CLR     <VIA_shift_reg  ;Clear shift regigster
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_a     ;Store X in D/A register
                CLR     <VIA_t1_cnt_hi  ;timer 1 count high
                PULS    D               ;Get back D-reg
                JSR     Abs_a_b
                STB     -1,S
                ORA     -1,S
                LDB     #$40
                CMPA    #$40
                BLS     LF345
                CMPA    #$64
                BLS     LF33B
                LDA     #$08
                BRA     LF33D

LF33B:          LDA     #$04            ;Wait for timer 1
LF33D:          BITB    <VIA_int_flags
                BEQ     LF33D
LF341:          DECA                    ;Delay a moment
                BNE     LF341
                RTS

LF345:          BITB    <VIA_int_flags  ;Wait for timer 1
                BEQ     LF345
                RTS

;-----------------------------------------------------------------------;
;       F34A    Reset0Ref_D0                                            ;
;                                                                       ;
; This routine sets the DP register to D0, and then resets the          ;
; integrators.                                                          ;
;                                                                       ;
; EXIT: DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Reset0Ref_D0:   JSR     DP_to_D0
                BRA     Reset0Ref

;-----------------------------------------------------------------------;
;       F34F    Check0Ref                                               ;
;                                                                       ;
; This routine will check to see if the Reset0Ref enable flag ($C824)   ;
; is set, and if it is, then it will reset the integrators by calling   ;
; Reset0Ref.                                                            ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       $C824 = enable flag                                             ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Check0Ref:      LDA     Vec_0Ref_Enable
                BEQ     LF36A_RTS

;-----------------------------------------------------------------------;
;       F354    Reset0Ref                                               ;
;                                                                       ;
; This routine zeros the integrators, and resets the pen back to the    ;
; origin.  It leaves the integrators in zero mode, so nothing can be    ;
; drawn until a move is done, or $D00C is set to 0xCE to bring /ZERO    ;
; high.  This routine must be called every so often, to prevent your    ;
; vectors from getting out of whack.                                    ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Reset0Ref:      LDD     #$00CC
                STB     <VIA_cntl       ;/BLANK low and /ZERO low
                STA     <VIA_shift_reg  ;clear shift register
;-----------------------------------------------------------------------;
;       F35B    Reset_Pen                                               ;
;                                                                       ;
;       Reset the pen to the origin.                                    ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Reset_Pen:      LDD     #$0302
                CLR     <VIA_port_a     ;clear D/A register
                STA     <VIA_port_b     ;mux=1, disable mux
                STB     <VIA_port_b     ;mux=1, enable mux
                STB     <VIA_port_b     ;do it again
                LDB     #$01
                STB     <VIA_port_b     ;disable mux
LF36A_RTS:      RTS

;-----------------------------------------------------------------------;
;       F36B    Reset0Int                                               ;
;                                                                       ;
; This routine resets the integrators to zero.  It leaves the           ;
; integrators in zero mode, so nothing can be drawn until a move is     ;
; done, or D00C is set to 0xCE.                                         ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Reset0Int:      LDD     #$00CC
                STB     <VIA_cntl       ;blank low and zero low
                STA     <VIA_shift_reg  ;clear shift register
                RTS

;-----------------------------------------------------------------------;
;       F373    Print_Str_hwyx                                          ;
;                                                                       ;
; This routine prints a single string (up to an 0x80).  The parameter   ;
; block describing the string is pointed to by the U register.  The     ;
; format for the parameter block is as follows:                         ;
;                                                                       ;
;       height, width, rel y, rel x, string, 0x80                       ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to the string list                                 ;
;                                                                       ;
; EXIT: U-reg points to the byte after the terminating 0x80             ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Print_Str_hwyx: LDD     ,U++
                STD     Vec_Text_HW

;-----------------------------------------------------------------------;
;       F378    Print_Str_yx                                            ;
;                                                                       ;
; This routine prints a single string (up to an 0x80), using the        ;
; default height and width, as stored in $C82A.  The parameter block    ;
; describing the string is pointed to by the U register.  The format    ;
; for the parameter block is as follows:                                ;
;                                                                       ;
;       rel y, rel x, string, 0x80                                      ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to the string list                                 ;
;                                                                       ;
; EXIT: U-reg points to the byte after the terminating 0x80             ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Print_Str_yx:   LDD     ,U++

;-----------------------------------------------------------------------;
;       F37A    Print_Str_d                                             ;
;                                                                       ;
; This routine prints a single string (up to an 0x80), using the        ;
; default height and width, as stored in $C82A, and at the pen position ;
; specified in the D register.  The parameter block describing the      ;
; string is pointed to by the U register.  The format for the           ;
; parameter block is as follows:                                        ;
;                                                                       ;
;     string, 0x80                                                      ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to string list                                     ;
;       A-reg = relative Y position                                     ;
;       B-reg = relative X position                                     ;
;                                                                       ;
; EXIT: U-reg points to the byte after the terminating 0x80             ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;
   noopt        ; neccessary for assembling, this jsr is allways
                ; optimized to a short branch otherwise
Print_Str_d:    JSR     >Moveto_d_7F
   opt
                JSR     Delay_1
                JMP     Print_Str

;-----------------------------------------------------------------------;
;       F385    Print_List_hw                                           ;
;                                                                       ;
; This displays the group of strings described by the parameter block   ;
; which is pointed to by the U register.  The string parameter block    ;
; has the following format:                                             ;
;                                                                       ;
;     height, width, rel y, rel x, string, 0x80,                        ;
;     height, width, rel y, rel x, string, 0x80,                        ;
;     0x00                                                              ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to string list                                     ;
;                                                                       ;
; EXIT: U-reg points to null terminator byte                            ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

LF383:          BSR     Print_Str_hwyx
Print_List_hw:  LDA     ,U
                BNE     LF383
                RTS

;-----------------------------------------------------------------------;
;       F38A    Print_List                                              ;
;       F38C    Print_List_chk                                          ;
;                                                                       ;
; This displays the group of strings described by the parameter block   ;
; which is pointed to by the U register.  The string parameter block    ;
; has the following format:                                             ;
;                                                                       ;
;       rel y, rel x, string, 0x80,                                     ;
;       rel y, rel x, string, 0x80,                                     ;
;       0x00                                                            ;
;                                                                       ;
; The current string height and width to which the hardware is set will ;
; be used.                                                              ;
;                                                                       ;
; Print_List routine will first print the passed-in string, and THEN    ;
; check for the end of the string list.  Print_List_Chk will check for  ;
; the end of the string list first.                                     ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to string list                                     ;
;                                                                       ;
; EXIT: U-reg points to null terminator byte                            ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Print_List:     BSR     Print_Str_yx
Print_List_Chk: LDA     ,U
                BNE     Print_List
                RTS

;-----------------------------------------------------------------------;
;       F391    Print_Ships_x                                           ;
;       F393    Print_Ships                                             ;
;                                                                       ;
; This routine displays the number of ships passed in the B register    ;
; followed by a minus sign and the ship icon character passed in the    ;
; A register at the (y,x) coordinates passed in the X register.  If     ;
; the B-register > 9, then the infinity symbol is displayed.            ;
;                                                                       ;
; Note: This routine uses bytes at a negative offset from the stack as  ;
;       temporary storage, so hopefully an IRQ won't happen until the   ;
;       string is finished bring printed!                               ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = ship icon character                                     ;
;       B-reg = number of ships                                         ;
;       X-reg = (y,x) coordinates (Print_Ships only)                    ;
;       X-reg points to (y,x) coordinates (Print_Ships_x only)          ;
;                                                                       ;
;       D-reg, X-reg, U-reg trashed                                     ;
;-----------------------------------------------------------------------;

Print_Ships_x:  LDX     ,X
Print_Ships:    PSHS    B               ;Save B-reg
                LDB     #$80
                LEAU    -8,S            ;Point U into the stack
                PSHU    D               ;Save A-reg and a terminator
                PULS    A               ;Get back B-reg
                CMPA    #$09            ;If B-reg >9 then
                BLS     LF3A3
                LDA     #$6C-$30        ;load $6C = infinty symbol
LF3A3:          ADDA    #$30
                LDB     #'-'
                PSHU    D               ;Push digit and minus sign
                PSHU    X               ;Push (y,x) coordinates
                BRA     Print_Str_yx    ;Print it

;-----------------------------------------------------------------------;
;       F3AD    Mov_Draw_VLc_a                                          ;
;                                                                       ;
; This routine moves to the first location specified in vector list,    ;
; and then draws lines between the rest of coordinates in the list.     ;
; The number of vectors to draw is specified as the first byte in the   ;
; vector list.  The current scale factor is used.  The vector list has  ;
; the following format:                                                 ;
;                                                                       ;
;       count, rel y, rel x, rel y, rel x, ...                          ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Mov_Draw_VLc_a: LDA     ,X+
                BRA     Mov_Draw_VL_a

;-----------------------------------------------------------------------;
;       F3B1    Mov_Draw_VL_b                                           ;
;                                                                       ;
; This routine moves to the first location specified in vector list,    ;
; and then draws lines between the rest of coordinates in the list.     ;
; The vector list has the following format:                             ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       B-reg = scale factor                                            ;
;       $C823 = number of vectors to draw                               ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: $C823 is cleared                                                ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Mov_Draw_VL_b:  STB     <VIA_t1_cnt_lo  ;Set scale factor
                BRA     Mov_Draw_VL

;-----------------------------------------------------------------------;
;       F3B5    Mov_Draw_VLcs                                           ;
;                                                                       ;
; This routine moves to the first location specified in vector list,    ;
; and then draws lines between the rest of coordinates in the list.     ;
; The number of vectors to draw is specified as the first byte in the   ;
; vector list, and the scale factor is the second byte in the vector    ;
; list.  The vector list has the following format:                      ;
;                                                                       ;
;       count, scale, rel y, rel x, rel y, rel x, ...                   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Mov_Draw_VLcs:  LDD     ,X++

;-----------------------------------------------------------------------;
;       F3B7    Mov_Draw_VL_ab                                          ;
;       F3B9    Mov_Draw_VL_a                                           ;
;                                                                       ;
; This routine moves to the first location specified in vector list,    ;
; and then draws lines between the rest of coordinates in the list.     ;
; The vector list has the  following format:                            ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = number of vectors to draw                               ;
;       B-reg = scale factor to use (Draw_VL_ab only)                   ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Mov_Draw_VL_ab: STB     <VIA_t1_cnt_lo  ;Set scale factor
Mov_Draw_VL_a:  STA     $C823

;-----------------------------------------------------------------------;
;       F3BC    Mov_Draw_VL                                             ;
;       F3BE    Mov_Draw_VL_d                                           ;
;                                                                       ;
; This routine moves to the first location specified in vector list,    ;
; and then draws lines between the rest of coordinates in the list.     ;
; The vector list has the following format:                             ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; Draw_VL_d starts at the (y,x) coordinates specified in the D register ;
; and ignores the first pair of coordinates in the vector list.         ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       $C823 = number of vectors to draw                               ;
;       D-reg = start coordinate (Draw_VL_d only)                       ;
;       X-reg points to the vector list (2,X for Mov_Draw_VL_d)         ;
;                                                                       ;
; EXIT: $C823 is cleared                                                ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Mov_Draw_VL:    LDD     ,X              ;Get next coordinate pair
Mov_Draw_VL_d:  STA     <VIA_port_a     ;Send Y to A/D
                CLR     <VIA_port_b     ;Enable mux
                LEAX    2,X             ;Point to next coordinate pair
                NOP                     ;Wait a moment
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_a     ;Send X to A/D
                LDD     #$0000          ;Shift reg=0 (no draw), T1H=0
                BRA     LF3ED           ;A->D00A, B->D005

;-----------------------------------------------------------------------;
;       F3CE    Draw_VLc                                                ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed    ;
; to by the X register.  The number of vectors to draw is specified     ;
; as the first byte in the vector list.  The current scale factor is    ;
; used.  The vector list has the following format:                      ;
;                                                                       ;
;       count, rel y, rel x, rel y, rel x, ...                          ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLc:       LDA     ,X+
                BRA     Draw_VL_a

;-----------------------------------------------------------------------;
;       F3D2    Draw_VL_b                                               ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed to ;
; by the X register.  The vector list has the following format:         ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       B-reg = the scale factor                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VL_b:      STB     <VIA_t1_cnt_lo  ;Set scale factor
                BRA     Draw_VL

;-----------------------------------------------------------------------;
;       F3D6    Draw_VLcs                                               ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed    ;
; to by the X register.  The number of vectors to draw is specified     ;
; as the first byte in the vector list.  The scale factor is specified  ;
; as the second byte in the vector list. The vector list has the        ;
; following format:                                                     ;
;                                                                       ;
;       count, scale, rel y, rel x, rel y, rel x, ...                   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLcs:      LDD     ,X++

;-----------------------------------------------------------------------;
;       F3D8    Draw_VL_ab                                              ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed    ;
; to by the X register.  The vector list has the following format:      ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = the number of vectors to draw                           ;
;       B-reg = the scale factor                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VL_ab:     STB     <VIA_t1_cnt_lo

;-----------------------------------------------------------------------;
;       F3DA    Draw_VL_a                                               ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed    ;
; to by the register.  The current scale factor is used.  The vector    ;
; list has the following format:                                        ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = the number of vectors to draw                           ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VL_a:      STA     $C823

;-----------------------------------------------------------------------;
;       F3DD    Draw_VL                                                 ;
;                                                                       ;
; This routine draws vectors between the set of (y,x) points pointed    ;
; to by the X register.  The number of vectors to draw must already be  ;
; specified in $C823.  The current scale factor is used.  The vector    ;
; list has the following format:                                        ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VL:        LDD     ,X

;-----------------------------------------------------------------------;
;       F3DF    Draw_Line_d                                             ;
;                                                                       ;
; This routine will draw a line from the current pen position, to the   ;
; point specified by the (y,x) pair specified in the D register.  The   ;
; current scale factor is used.  Before calling this routine, $C823     ;
; should be = 0, so that only the one vector will be drawn.             ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg = relative y position                                     ;
;       B-reg = relative x position                                     ;
;                                                                       ;
; EXIT: X-reg is incremented by 2                                       ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_Line_d     STA     <VIA_port_a     ;Send Y to A/D
                CLR     <VIA_port_b     ;Enable mux
                LEAX    2,X             ;Point to next coordinate pair
                NOP                     ;Wait a moment
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_a     ;Send X to A/D
                LDD     #$FF00          ;Shift reg=$FF (solid line), T1H=0
LF3ED:          STA     <VIA_shift_reg  ;Put pattern in shift register
                STB     <VIA_t1_cnt_hi  ;Set T1H (scale factor?)
                LDD     #$0040          ;B-reg = T1 interrupt bit
LF3F4:          BITB    <VIA_int_flags  ;Wait for T1 to time out
                BEQ     LF3F4
                NOP                     ;Wait a moment more
                STA     <VIA_shift_reg  ;Clear shift register (blank output)
                LDA     $C823           ;Decrement line count
                DECA
                BPL     Draw_VL_a       ;Go back for more points
                JMP     Check0Ref       ;Reset zero reference if necessary

;-----------------------------------------------------------------------;
;       F404    Draw_VLp_FF                                             ;
;       F408    Draw_VLp_7F                                             ;
;                                                                       ;
; These routines force the scale factor to 0xFF or 0x7F, and then       ;
; process the vector list pointed to by the X register.  The vector     ;
; list has the following format:                                        ;
;                                                                       ;
;       pattern, rel y, rel x                                           ;
;       pattern, rel y, rel x                                           ;
;          .      .      .                                              ;
;          .      .      .                                              ;
;       pattern, rel y, rel x                                           ;
;       0x01                                                            ;
;                                                                       ;
; The list is terminated by a pattern byte with the high bit cleared.   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to the terminator byte                             ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLp_FF:    LDB     #$FF
                BRA     Draw_VLp_b

Draw_VLp_7F:    LDB     #$7F
                BRA     Draw_VLp_b

;-----------------------------------------------------------------------;
;       F40C    Draw_VLp_scale                                          ;
;                                                                       ;
; This routine processes the vector list pointed to by the X register.  ;
; The first byte in the vector list is the scale factor.  The vector    ;
; list has the following format:                                        ;
;                                                                       ;
;       scale                                                           ;
;       pattern, rel y, rel x                                           ;
;       pattern, rel y, rel x                                           ;
;          .      .      .                                              ;
;          .      .      .                                              ;
;       pattern, rel y, rel x                                           ;
;       0x01                                                            ;
;                                                                       ;
; The list is terminated by a pattern byte with the high bit cleared.   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to the terminator byte                             ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLp_scale: LDB     ,X+

;-----------------------------------------------------------------------;
;       F40E    Draw_VLp_b                                              ;
;                                                                       ;
; This routine draws patterned lines using the vector list pointed to   ;
; by the X register.  The vector list has the following format:         ;
;                                                                       ;
;       pattern, rel y, rel x                                           ;
;       pattern, rel y, rel x                                           ;
;          .      .      .                                              ;
;          .      .      .                                              ;
;       pattern, rel y, rel x                                           ;
;       0x01                                                            ;
;                                                                       ;
; The list is terminated by a pattern byte with the high bit cleared.   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       B-reg = the scale factor                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to the terminator byte                             ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLp_b:     STB     <VIA_t1_cnt_lo  ;Set scale factor

;-----------------------------------------------------------------------;
;       F410    Draw_VLp                                                ;
;                                                                       ;
; This routine draws patterned lines using the vector list pointed to   ;
; by the X-register.  The current scale factor is used.  The vector     ;
; list has the following format:                                        ;
;                                                                       ;
;       pattern, rel y, rel x                                           ;
;       pattern, rel y, rel x                                           ;
;          .      .      .                                              ;
;          .      .      .                                              ;
;       pattern, rel y, rel x                                           ;
;       0x01                                                            ;
;                                                                       ;
; The list is terminated by a pattern byte with the high bit cleared.   ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;                                                                       ;
; EXIT: X-reg points to the terminator byte                             ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VLp:       LDD     1,X             ;Get next coordinate pair
                STA     <VIA_port_a     ;Send Y to A/D
                CLR     <VIA_port_b     ;Enable mux
                LDA     ,X              ;Get pattern byte?
                LEAX    3,X             ;Advance to next point in list
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_a     ;Send X to A/D
                STA     <VIA_shift_reg  ;Store pattern in shift register
                CLR     <VIA_t1_cnt_hi  ;Clear T1H
                LDD     #$0040          ;B-reg = T1 interrupt bit
LF425:          BITB    <VIA_int_flags  ;Wait for T1 to time out
                BEQ     LF425
                NOP                     ;Wait a moment more
                STA     <VIA_shift_reg  ;Clear shift register (blank output)
                LDA     ,X              ;Get next pattern byte
                BLE     Draw_VLp        ;Go back if high bit of pattern is set
                JMP     Check0Ref

;-----------------------------------------------------------------------;
;       F434    Draw_Pat_VL_a                                           ;
;       F437    Draw_Pat_VL                                             ;
;       F439    Draw_Pat_VL_d                                           ;
;                                                                       ;
; All of these routines draw a series of patterned vectors.  The        ;
; pattern to use must already be specified in $C829.  When using        ;
; Draw_Pat_VL or Draw_Pat_VL_d, the number of vectors to draw minus 1   ;
; must be specified in $C823; when using Draw_Pat_VL_a, the number of   ;
; vectors to draw minus 1 must be passed in in the A register.          ;
; The vector list, pointed to by the X register, has the following      ;
; format:                                                               ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; Draw_Pat_VL_d starts at the (y,x) coordinates specified in the        ;
; D register and ignores the first pair of coordinates in the vector    ;
; list.                                                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;       A-reg = the number of vectors to draw (Draw_Pat_VL_a only)      ;
;       D-reg = start (Y,X) coordinate (Draw_Pat_VL_d only)             ;
;       $C829 contains the line pattern.                                ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

LF433:          DECA
Draw_Pat_VL_a:  STA     $C823
Draw_Pat_VL:    LDD     ,X              ;Get next coordinate pair
Draw_Pat_VL_d:  STA     <VIA_port_a     ;Send Y to A/D
                CLR     <VIA_port_b     ;Enable mux
                LEAX    2,X             ;Point to next coordinate pair
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_a     ;Send X to A/D
                LDA     Vec_Pattern     ;Get default pattern
                LDB     #$40            ;B-reg = T1 interrupt bit
                STA     <VIA_shift_reg  ;Put pattern in shift register
                CLR     <VIA_t1_cnt_hi  ;Clear T1H (scale factor?)
                BITB    VIA_int_flags   ;Check if T1 timed out (note wasted byte)
                BEQ     LF45C           ;Update pattern if not

;               Don't reset the zero reference if last line is really short?

                CLR     <VIA_shift_reg  ;Clear shift register (blank output)
                LDA     $C823           ;Get line counter
                BNE     LF433           ;Go back for more points
                RTS

;               This code is for lines that are not really short lines

LF459:          LDA     Vec_Pattern     ;Get default pattern
LF45C:          STA     <VIA_shift_reg  ;Update pattern register
                NOP                     ;Wait a moment
                BITB    <VIA_int_flags  ;Check if T1 timed out
                BEQ     LF459           ;Update pattern again if not
                LDA     $C823           ;Get line counter
                CLR     <VIA_shift_reg  ;Clear shift register (blank output)
                TSTA                    ;Go back if more lines to draw
                BNE     LF433
                JMP     Check0Ref       ;Reset zero reference if necessary

;-----------------------------------------------------------------------;
;       F46E    Draw_VL_mode                                            ;
;                                                                       ;
; This routine processes the vector list pointed to by the X register.  ;
; The current scale factor is used.  The vector list has the following  ;
; format:                                                               ;
;                                                                       ;
;       mode, rel y, rel x,                                             ;
;       mode, rel y, rel x,                                             ;
;        .      .      .                                                ;
;        .      .      .                                                ;
;       mode, rel y, rel x,                                             ;
;       0x01                                                            ;
;                                                                       ;
; where mode has the following meaning:                                 ;
;                                                                       ;
;       < 0  use the pattern in $C829                                   ;
;       = 0  move to specified endpoint                                 ;
;       = 1  end of list, so return                                     ;
;       > 1  draw to specified endpoint                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to the vector list                                 ;
;       $C829 contains the line pattern.                                ;
;                                                                       ;
; EXIT: X-reg points to next byte after terminator                      ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_VL_mode:   LDA     Vec_0Ref_Enable ;Save old Check0Ref flag
                PSHS    A
                CLR     Vec_0Ref_Enable ;Don't reset the zero reference yet
LF476:          LDA     ,X+             ;Get the next mode byte
                BPL     LF47E
                BSR     Draw_Pat_VL     ;If <0, draw a patterned line
                BRA     LF476

LF47E:          BNE     LF485
                JSR     Mov_Draw_VL     ;If =0, move to the next point
                BRA     LF476

LF485:          DECA
                BEQ     LF48D
                JSR     Draw_VL         ;If <>1, draw a solid line
                BRA     LF476

LF48D:          PULS    A               ;If =1, exit
                STA     Vec_0Ref_Enable ;Restore old Check0Ref flag
                JMP     Check0Ref       ;Reset zero reference if necessary

;-----------------------------------------------------------------------;
;       F495    Print_Str                                               ;
;                                                                       ;
; This is the routine which does the actual printing of a string.  The  ;
; U register points to the start of the string, while $C82A contains    ;
; the height of the character, cell, and $C82B contains the width of    ;
; the character cell.  The string is terminated with an 0x80.           ;
;                                                                       ;
; The string is displayed by drawing 7 horizontal rows of dots.  The    ;
; first row is drawn for each character, then the second, etc.  The     ;
; character generation table is located at ($F9D4 + $20).  Only         ;
; characters 0x20-0x6F (upper case) are defined; the lower case         ;
; characters a-o produce special icons.                                 ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       U-reg points to the start of the string                         ;
;                                                                       ;
; EXIT: U-reg points to next byte after terminator                      ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Print_Str:      STU     Vec_Str_Ptr     ;Save string pointer
                LDX     #Char_Table-$20 ;Point to start of chargen bitmaps
                LDD     #$1883          ;$8x = enable RAMP?
                CLR     <VIA_port_a     ;Clear D/A output
                STA     <VIA_aux_cntl   ;Shift reg mode = 110, T1 PB7 enabled
                LDX     #Char_Table-$20 ;Point to start of chargen bitmaps
LF4A5:          STB     <VIA_port_b     ;Update RAMP, set mux to channel 1
                DEC     <VIA_port_b     ;Enable mux
                LDD     #$8081
                NOP                     ;Wait a moment
                INC     <VIA_port_b     ;Disable mux
                STB     <VIA_port_b     ;Enable RAMP, set mux to channel 0
                STA     <VIA_port_b     ;Enable mux
                TST     $C800           ;I think this is a delay only
                INC     <VIA_port_b     ;Enable RAMP, disable mux
                LDA     Vec_Text_Width  ;Get text width
                STA     <VIA_port_a     ;Send it to the D/A
                LDD     #$0100
                LDU     Vec_Str_Ptr     ;Point to start of text string
                STA     <VIA_port_b     ;Disable RAMP, disable mux
                BRA     LF4CB

LF4C7:          LDA     A,X             ;Get bitmap from chargen table
                STA     <VIA_shift_reg  ;Save in shift register
LF4CB:          LDA     ,U+             ;Get next character
                BPL     LF4C7           ;Go back if not terminator
                LDA     #$81
                STA     <VIA_port_b     ;Enable RAMP, disable mux
                NEG     <VIA_port_a     ;Negate text width to D/A
                LDA     #$01
                STA     <VIA_port_b     ;Disable RAMP, disable mux
                CMPX    #Char_Table_End-$20;     Check for last row
                BEQ     LF50A           ;Branch if last row
                LEAX    $50,X           ;Point to next chargen row
                TFR     U,D             ;Get string length
                SUBD    Vec_Str_Ptr
                SUBB    #$02            ; -  2
                ASLB                    ; *  2
                BRN     LF4EB           ;Delay a moment
LF4EB:          LDA     #$81
                NOP
                DECB
                BNE     LF4EB           ;Delay some more in a loop
                STA     <VIA_port_b     ;Enable RAMP, disable mux
                LDB     Vec_Text_Height ;Get text height
                STB     <VIA_port_a     ;Store text height in D/A
                DEC     <VIA_port_b     ;Enable mux
                LDD     #$8101
                NOP                     ;Wait a moment
                STA     <VIA_port_b     ;Enable RAMP, disable mux
                CLR     <VIA_port_a     ;Clear D/A
                STB     <VIA_port_b     ;Disable RAMP, disable mux
                STA     <VIA_port_b     ;Enable RAMP, disable mux
                LDB     #$03            ;$0x = disable RAMP?
                BRA     LF4A5           ;Go back for next scan line

LF50A:          LDA     #$98
                STA     <VIA_aux_cntl   ;T1->PB7 enabled
                JMP     Reset0Ref       ;Reset the zero reference

;-----------------------------------------------------------------------;
;       F511    Random_3                                                ;
;       F517    Random                                                  ;
;                                                                       ;
; This routine generates a random 1-byte number, and places it in the   ;
; A register.  Random_3 runs through the random number generator        ;
; algorithm three times.  The random number seed is stored in the       ;
; three bytes pointed to by $C87B.                                      ;
;                                                                       ;
; EXIT: A-reg contains the generated random number                      ;
;                                                                       ;
;       All other registers are preserved.                              ;
;-----------------------------------------------------------------------;

Random_3:       PSHS    B,X
                LDB     #$02
                BRA     LF51A

Random:         PSHS    B,X
                CLRB
LF51A:          LDX     Vec_Seed_Ptr
LF51D:          LDA     1,X
                ROLA
                ROLA
                ROLA
                ROLA
                EORA    2,X
                RORA
                ROL     ,X
                ROL     1,X
                ROL     2,X
                DECB
                BPL     LF51D
                LDA     ,X
                PULS    B,X,PC

;-----------------------------------------------------------------------;
;       F533    Init_Music_Buf                                          ;
;                                                                       ;
; This routine clears out the music work buffer, located at             ;
; $C83F-$C84C.                                                          ;
;                                                                       ;
;       X-reg, D-reg trashed                                            ;
;-----------------------------------------------------------------------;

Init_Music_Buf: LDB     #$0D
                LDX     #Vec_Music_Work
                BSR     Clear_x_b
                LDA     #$3F
                STA     6,X
                RTS

;-----------------------------------------------------------------------;
;       F53F    Clear_x_b                                               ;
;                                                                       ;
; This routine clears to 0 the block of memory starting at the          ;
; address contained in the X register, and continuing for the number    ;
; of bytes specified by B+1.                                            ;
;                                                                       ;
; ENTRY X-reg points to the start of the RAM to be cleared.             ;
;       B-reg = number of bytes minus 1 to clear.                       ;
;                                                                       ;
; EXIT: D-reg = $FFFF                                                   ;
;-----------------------------------------------------------------------;

Clear_x_b:      CLRA
                BRA     Clear_x_d

;-----------------------------------------------------------------------;
;       F542    Clear_C8_RAM    (never used by GCE carts?)              ;
;                                                                       ;
; This routine clears to 0 the block of memory in the range             ;
; $C800-$C8FF.                                                          ;
;                                                                       ;
; EXIT: X-reg = $C800                                                   ;
;       D-reg = $FFFF                                                   ;
;-----------------------------------------------------------------------;

Clear_C8_RAM:   LDX     #$C800

;-----------------------------------------------------------------------;
;       F545    Clear_x_256                                             ;
;       F548    Clear_x_d                                               ;
;                                                                       ;
; This routine clears the block of memory starting at the contained     ;
; in the X register to zero.                                            ;
;                                                                       ;
; ENTRY X-reg points to the start of RAM to be cleared                  ;
;       D-reg = number of bytes to clear minus 1 (Clear_x_d only)       ;
;                                                                       ;
; EXIT: D-reg = $FFFF                                                   ;
;-----------------------------------------------------------------------;

Clear_x_256:    LDD     #$00FF
Clear_x_d:      CLR     D,X
                SUBD    #$0001
                BPL     Clear_x_d
                RTS

;-----------------------------------------------------------------------;
;       F550    Clear_x_b_80                                            ;
;       F552    Clear_x_b_a                                             ;
;                                                                       ;
; This routine sets the block of memory pointed to by the X register    ;
; to $80 or the A register.  The B register specifies the number of     ;
; bytes to be cleared.                                                  ;
;                                                                       ;
; ENTRY A-reg = byte to be stored (Clear_x_b_a only)                    ;
;       B-reg = number of bytes to clear ($00 = 256)                    ;
;       X-reg points to start of memory block to clear                  ;
;                                                                       ;
; EXIT: A-reg = $80 (Clear_x_b_80 only)                                 ;
;       B-reg = $00                                                     ;
;                                                                       ;
;       All other registers preserved.                                  ;
;-----------------------------------------------------------------------;

Clear_x_b_80:   LDA     #$80
Clear_x_b_a:    STA     B,X
                DECB
                BNE     Clear_x_b_a
                STA     ,X
                RTS

;-----------------------------------------------------------------------;
;       F55A    Dec_3_Counters                                          ;
;       F55E    Dec_6_Counters                                          ;
;                                                                       ;
; These routines check either the first three or all six of the         ;
; default counters at $C82E-$C833 and decrements those which are not    ;
; already zero.                                                         ;
;                                                                       ;
; EXIT: X-reg points to the default counters at $C82E                   ;
;       B-reg = $FF                                                     ;
;                                                                       ;
;       All other registers preserved.                                  ;
;-----------------------------------------------------------------------;

Dec_3_Counters: LDB     #$02
                BRA     LF560

Dec_6_Counters: LDB     #$05
LF560:          LDX     #Vec_Counters

;-----------------------------------------------------------------------;
;       F563    Dec_Counters                                            ;
;                                                                       ;
; This routine checks the counters pointed to by the X register and     ;
; decrements those which are not already zero.                          ;
;                                                                       ;
; ENTRY B-reg = number of counters minus 1                              ;
;       X-reg points to counter bytes                                   ;
;                                                                       ;
; EXIT: B-reg = $FF                                                     ;
;                                                                       ;
;       All other registers preserved.                                  ;
;-----------------------------------------------------------------------;

Dec_Counters:   TST     B,X
                BEQ     LF569
                DEC     B,X
LF569:          DECB
                BPL     Dec_Counters
                RTS

;-----------------------------------------------------------------------;
;       F56D    Delay_3         30 cycles                               ;
;       F571    Delay_2         25 cycles                               ;
;       F575    Delay_1         20 cycles                               ;
;       F579    Delay_0         12 cycles                               ;
;       F57A    Delay_b         5;B + 10 cycles                         ;
;       F57D    Delay_RTS       5 cycles                                ;
;                                                                       ;
; Each of these routines loads the B-register with the indicated        ;
; value, and then loops until the B register value has decremented      ;
; below zero.  Delay_RTS is just an RTS instruction, but at least       ;
; one GCE cartridge calls it.                                           ;
;                                                                       ;
; Cycle counts do not include timing of the instructions used to        ;
; call the delay routines.                                              ;
;                                                                       ;
; ENTRY B-reg = delay count (Delay_b only)                              ;
;                                                                       ;
; EXIT: B-reg = $FF (except Delay_RTS)                                  ;
;-----------------------------------------------------------------------;

Delay_3:        LDB     #$03            ;2 cycles
                BRA     Delay_b         ;3 cycles

Delay_2:        LDB     #$02            ;2 cycles
                BRA     Delay_b         ;3 cycles

Delay_1:        LDB     #$01            ;2 cycles
                BRA     Delay_b         ;3 cycles

Delay_0:        CLRB                    ;2 cycles
Delay_b:        DECB                    ;2 cycles
                BPL     Delay_b         ;3 cycles
Delay_RTS:      RTS                     ;5 cycles

;-----------------------------------------------------------------------;
;       F57E    Bitmask_a                                               ;
;                                                                       ;
; This routine takes a bit number, specified in the A register, and     ;
; returns a bit mask with only the specified bit set.                   ;
;                                                                       ;
; ENTRY A-reg contains the bit number                                   ;
;                                                                       ;
; EXIT: A-reg contains the bit mask                                     ;
;                                                                       ;
;       X-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Bitmask_a:      LDX     #Bit_Masks
                LDA     A,X
                RTS

;-----------------------------------------------------------------------;
;       F584    Abs_a_b                                                 ;
;       F58B    Abs_b                                                   ;
;                                                                       ;
; This routine returns the absolute value of the two single byte        ;
; numbers passed in in the A and B registers.  Abs_b only uses the B    ;
; register.  There is a special case: 0x80 is returned as 0x7F.         ;
;                                                                       ;
; ENTRY A-reg contains first value                                      ;
;       B-reg contains second value (Abs_a_b only)                      ;
;                                                                       ;
; EXIT: A-reg contains absolute value of first value                    ;
;       B-reg contains absolute value of second value (Abs_a_b only)    ;
;                                                                       ;
;       All other registers preserved.                                  ;
;-----------------------------------------------------------------------;

Abs_a_b:        TSTA
                BPL     Abs_b
                NEGA
                BVC     Abs_b
                DECA
Abs_b:          TSTB
                BPL     LF592
                NEGB
                BVC     LF592
                DECB
LF592:          RTS

;-----------------------------------------------------------------------;
;       F593    Rise_Run_Angle                                          ;
;                                                                       ;
; Given a (rise,run) pair, this routine calculates the angle which      ;
; corresponds to that (rise,run) pair.  The returned angle is relative  ;
; to the x-axis (+ is CCW), so to convert it to a Vectrex angle         ;
; (relative to the y-axis, + is CCW), you must subtract the number 0x10 ;
; (90 degrees) from the returned value.                                 ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       A-reg = rise value                                              ;
;       B-reg = run value                                               ;
;                                                                       ;
; EXIT: A-reg = the angle from the x-axis                               ;
;       B-reg = the angle from the x-axis                               ;
;                                                                       ;
;       All other registers preserved.                                  ;
;-----------------------------------------------------------------------;

Rise_Run_Angle: PSHS    X
                STD     <Vec_RiseRun_Tmp
                ROLB
                LDB     #$00
                ROLB
                ROLA
                ROLB
                ASLB
                STB     <Vec_Angle
                LDD     <Vec_RiseRun_Tmp
                BSR     Abs_a_b
                STA     <Vec_RiseRun_Tmp
                CMPB    <Vec_RiseRun_Tmp
                BLS     LF5B2
                INC     <Vec_Angle
                EXG     A,B
                BRA     LF5B2

LF5B0:          LSRA
                LSRB
LF5B2:          CMPA    #$09
                BHI     LF5B0
                STD     <Vec_RiseRun_Tmp
                LDB     <Vec_Angle
                LDX     #DFC24
                LDB     B,X
                LDX     #DFC2C
                LDA     A,X
                ADDA    <$C835
                ADDA    #$0A
                BITB    #$01
                BNE     LF5D0
                ADDB    A,X
                BRA     LF5D3

LF5D0:          DECB
                SUBB    A,X
LF5D3:          STB     <Vec_Angle
                LDA     <Vec_Angle
                PULS    X,PC

;-----------------------------------------------------------------------;
;       F5D9    Get_Rise_Idx                                            ;
;       F5DB    Get_Run_Idx                                             ;
;                                                                       ;
; These routines are responsible for generating the two index pairs     ;
; which are required by the rest of the rotation routines.  Each index  ;
; pair is two bytes long, and has the following format:                 ;
;                                                                       ;
;       The high byte is obtained by masking the anglewith 0x1F (this   ;
;       forces the angle to be between 0 and 180 degrees), and then     ;
;       using this value to index into the multiplier table.            ;
;                                                                       ;
;       The lower byte contains information about whether the angle     ;
;       lies along either the x or y axis, and whether the rise/run     ;
;       will be positive or negative.                                   ;
;                                                                       ;
;               0 => positive rise, not on an axis, or                  ;
;                    negative run, not on an axis.                      ;
;            0x80 => negative rise, not on an axis, or                  ;
;                    positive run, not on an axis.                      ;
;               1 => positive rise, on an axis, or                      ;
;                    negative run, on an axis.                          ;
;            0x81 => negative rise, on an axis, or                      ;
;                    positive run, on an axis.                          ;
;                                                                       ;
; ENTRY A-reg = the angle value                                         ;
;                                                                       ;
; EXIT: A-reg = slope?                                                  ;
;       B-reg = slope direction?                                        ;
;                                                                       ;
;       X-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Get_Rise_Idx:   ADDA    #$10            ;Offset angle by 90 degrees
Get_Run_Idx:    LDX     #DFC6D          ;Get address of slope table
                CLRB
                BITA    #$20            ;If angle in 180-360,
                BEQ     LF5E5
                LDB     #$80            ;flag negative rise or positive run
LF5E5:          ANDA    #$1F            ;Mask to multiple of 180 degrees
                CMPA    #$10            ;If 90 degrees
                BNE     LF5EC
                INCB                    ;then rise or run is on an axis
LF5EC:          LDA     A,X             ;Get slope from slope table
                RTS

;-----------------------------------------------------------------------;
;       F5EF    Rise_Run_Idx                                            ;
;                                                                       ;
; This routine gets the index pair for both the rise and run, using     ;
; the passed-in angle value.                                            ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       $C836 contains the angle value                                  ;
;                                                                       ;
; EXIT: $C837-$C838 contains the index pair for the run                 ;
;       $C839-$C83A contains the index pair for the rise                ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Rise_Run_Idx:   PSHS    X               ;Save X-reg
                LDA     <Vec_Angle      ;Get angle
                BSR     Get_Run_Idx     ;Get run index pair for angle
                STD     <Vec_Run_Index
                LDA     <Vec_Angle      ;Get angle
                BSR     Get_Rise_Idx    ;Get rise index pair for angle
                STD     <Vec_Rise_Index
                PULS    X,PC            ;Restore X-reg and return

;-----------------------------------------------------------------------;
;       F5FF    Rise_Run_X                                              ;
;       F601    Rise_Run_Y                                              ;
;       F603    Rise_Run_Len                                            ;
;                                                                       ;
; This routine takes an angle value which is relative to the x- or      ;
; y-axis, and calculates the rise and run for that angle, relative to a ;
; passed-in scalar velocity value.  A large scalar value will cause an  ;
; object to move quickly, while a small scalar value will cause an      ;
; object to move more slowly.                                           ;
;                                                                       ;
; Keep in mind that most games store x & y coordinates as 2 bytes each, ;
; with the upper byte being the actual coordinate, and the lower byte   ;
; being that which is usually added to the rise/run value; when the     ;
; lower byte overflows into the hi byte, then the object will 'move'.   ;
; The rise/run values returned here are meant to be added to the low    ;
; byte -- NOT the hi byte!!                                             ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       A-reg = the scalar velocity value (except Rise_Run_Len)         ;
;       B-reg = the Vectrex angle value                                 ;
;                                                                       ;
; EXIT: A-reg = the rise value                                          ;
;       B-reg = the run value                                           ;
;                                                                       ;
;       All other registers are saved.                                  ;
;-----------------------------------------------------------------------;

Rise_Run_X:     SUBB    #$10
Rise_Run_Y:     STB     <Vec_Angle
Rise_Run_Len:   STA     <Vec_RiseRun_Len
                BSR     Rise_Run_Idx    ;Get index pair of angle
                BSR     Xform_Run       ;Get run value
                NEGA
                PSHS    A               ;Save run value
                BSR     Xform_Rise      ;Get rise value
                PULS    B,PC            ;Restore run value and return

;-----------------------------------------------------------------------;
;       F610    Rot_VL_ab                                               ;
;       F616    Rot_VL                                                  ;
;                                                                       ;
; This routine rotates a vector list of length 'n+1', where 'n' is      ;
; specified by the value in the B register.  The A register contains    ;
; the rotation value, and the X contains a pointer to the vector list.  ;
; The U register contains a pointer to a buffer into which the          ;
; transformed points are to be saved.  The vector list has the          ;
; following format:                                                     ;
;                                                                       ;
;       rel y, rel x, rel y, rel x, ...                                 ;
;                                                                       ;
; ENTRY A-reg = rotation angle value (Rot_VL_ab only)                   ;
;       $C836 = rotation angle value (Rot_VL only)                      ;
;       B-reg = number of points - 1 (Rot_VL_ab only)                   ;
;       $C823 = number of points - 1 (Rot_VL only)                      ;
;       X-reg points to original vector list                            ;
;       U-reg points to rotated vector list                             ;
;                                                                       ;
; EXIT: DP = $C8                                                        ;
;       X-reg points to next byte after list                            ;
;       U-reg points to next byte after rotated list                    ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Rot_VL_ab:      STA     Vec_Angle
                STB     $C823
Rot_VL:         PSHS    DP
                JSR     DP_to_C8
                BSR     Rise_Run_Idx
                BRA     LF637

;-----------------------------------------------------------------------;
;       F61F    Rot_VL_Mode                                             ;
;       F62B    Rot_VL_M_dft                                            ;
;                                                                       ;
; This routine rotates a vector list having the following format:       ;
;                                                                       ;
;       mode, rel y, rel x,                                             ;
;       mode, rel y, rel x,                                             ;
;         .     .      .                                                ;
;         .     .      .                                                ;
;       mode, rel y, rel x,                                             ;
;       0x01                                                            ;
;                                                                       ;
; The A register contains the rotation value, and the X contains a      ;
; pointer to the vector list.  The U register contains a pointer to a   ;
; buffer into which the transformed points are to be saved.             ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       A-reg = rotation angle value (Rot_VL_Mode only)                 ;
;       X-reg points to original vector list                            ;
;       U-reg points to rotated vector list                             ;
;                                                                       ;
; EXIT: X-reg points to next byte after list                            ;
;       U-reg points to next byte after rotated list                    ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Rot_VL_Mode:    STA     Vec_Angle       ;Save angle
                PSHS    DP              ;Save DP register
                JSR     DP_to_C8        ;DP to RAM
                STA     <$C823          ;Store $C8 (negative value) into $C823
                BSR     Rise_Run_Idx    ;Get index pair of angle
Rot_VL_M_dft:   LDA     ,X+             ;Get mode byte
                STA     ,U+             ;Copy to destination
                BLE     LF637           ;Rotate if not end of list
                CLR     <$C823          ;Exit with $C823 cleared
                PULS    DP,PC           ;Restore DP register and return

LF635:          DEC     <$C823          ;Decrement count for (y,x) list
LF637:          LDA     ,X+             ;Get y coordinate
                BSR     Xform_Rise_a
                STA     ,U              ;Store partial y coordinate
                LDA     ,X              ;Get x coordinate
                BSR     Xform_Run_a
                ADDA    ,U              ;Add to partial y coordinate
                STA     ,U+             ;Store rotated y coordinate
                LDA     -1,X            ;Get y coordinate
                BSR     Xform_Run_a
                STA     ,U              ;Store partial x coordinate
                LDA     ,X+             ;Get x coordinate
                BSR     Xform_Rise_a
                SUBA    ,U              ;Add to partial x coordinate
                STA     ,U+             ;Store rotated x coordinate
                LDA     <$C823          ;Get counter
                BMI     Rot_VL_M_dft    ;If negative, go back to mode list loop
                BNE     LF635           ;If non-zero, go back to (y,x) list loop
                PULS    DP,PC

;-----------------------------------------------------------------------;
;       F65B    Xform_Run_a                                             ;
;       F65D    Xform_Run                                               ;
;                                                                       ;
; These two routines generate a run value, using the run index pair in  ;
; $C837-$C838.  For Xform_Run_a the scalar value is passed in the       ;
; A register, while for Xform_Run, the scalar value must already be in  ;
; $C83B.  The transformed value is return in the A register.            ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       A-reg = length for rise/run (Xform_Rise_a only)                 ;
;                                                                       ;
; EXIT: A-reg = run value                                               ;
;                                                                       ;
;       B-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Xform_Run_a:    STA     <Vec_RiseRun_Len
Xform_Run:      LDD     <Vec_Run_Index
                BRA     LF665

;-----------------------------------------------------------------------;
;       F661    Xform_Rise_a                                            ;
;       F663    Xform_Rise                                              ;
;                                                                       ;
; These two routines generate a rise value, using the rise index pair   ;
; in $C839-$C83A.  For Xform_Rise_a the scalar value is passed in the   ;
; A register, while for Xform_Rise, the scalar value must already be    ;
; in $C83B.  The transformed value is return in the A register.         ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       A-reg = length for rise/run (Xform_Run_a only)                  ;
;                                                                       ;
; EXIT: A-reg = rise value                                              ;
;                                                                       ;
;       B-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Xform_Rise_a:   STA     <Vec_RiseRun_Len
Xform_Rise:     LDD     <Vec_Rise_Index
LF665:          STB     <$C83C
                BITB    #$01
                BEQ     LF66F
                LDA     <Vec_RiseRun_Len
                BRA     LF679

LF66F:          LDB     <Vec_RiseRun_Len
                BPL     LF676
                COM     <$C83C
                NEGB
LF676:          MUL
                ADCA    #$00
LF679:          LDB     <$C83C
                BPL     LF67E
                NEGA
LF67E:          RTS

;-----------------------------------------------------------------------;
;       F67F    Move_Mem_a_1                                            ;
;       F683    Move_Mem_a                                              ;
;                                                                       ;
; This routine copies a block of memory, starting at the hi address,    ;
; and working down to the low address.  The base of the source address  ;
; is specified in the U register, and the base of the destination       ;
; address is  specified in the X register.  The A register contains     ;
; the number of bytes to copy; 0x80 is the maximum value which can      ;
; be specified.                                                         ;
;                                                                       ;
; ENTRY A-reg = byte count (Move_Mem_a only)                            ;
;       A-reg = byte count minus 1 (Move_Mem_a_1 only)                  ;
;       X-reg points to the destination                                 ;
;       U-reg points to the source                                      ;
;                                                                       ;
; EXIT  A-reg = $FF                                                     ;
;       B-reg = first byte of source                                    ;
;-----------------------------------------------------------------------;

Move_Mem_a_1:   LDB     A,U             ;Copy the byte
                STB     A,X
Move_Mem_a:     DECA                    ;Decrement the count
                BPL     Move_Mem_a_1    ;Go back until finished
LF686:          RTS

;-----------------------------------------------------------------------;
;       F687    Init_Music_chk                                          ;
;       F68D    Init_Music                                              ;
;       F692    Init_Music_dft                                          ;
;                                                                       ;
; These routines are responsible for filling the music work buffer      ;
; while a sound is being made.  It should be called once during each    ;
; refresh cycle.  If you want to start a new sound, then you must set   ;
; $C856 to 0x01, and point the U-register to the sound block.  If no    ;
; sound is in progress ($C856 = 0), then it returns immediately         ;
; (unless you called Init_Music or Init_Music_dft, which do not make    ;
; this check).  When a sound is in progress, $C856 will be set to 0x80. ;
;                                                                       ;
; These routines process a single note at a time, and calculate the     ;
; amplitude and course/fine tuning values for the 3 sound channels.     ;
; The values calculated are stored in the music work buffer, at         ;
; $C83F-$C84C.                                                          ;
;                                                                       ;
; Music data format:                                                    ;
;                                                                       ;
;       header word -> $C84F  32 nibble ADSR table                      ;
;       header word -> $C851  8-byte "twang" table                      ;
;       data bytes                                                      ;
;                                                                       ;
; The ADSR table is simply 32 nibbles (16 bytes) of amplitude values.   ;
;                                                                       ;
; The twang table is 8 signed bytes to modify the base frequency of     ;
; each note being played.  Each channel has a different limit to its    ;
; twang table index (6-8) to keep them out of phase to each other.      ;
;                                                                       ;
; Music data bytes:                                                     ;
;       Bits 0-5 = frequency                                            ;
;       Bit 6 clear = tone                                              ;
;       Bit 6 set = noise                                               ;
;       Bit 7 set = next music data byte is for next channel            ;
;       Bit 7 clear, play note with duration in next music data byte:   ;
;               bits 0-5 = duration                                     ;
;               bit 6 = unused                                          ;
;               bit 7 set = end of music                                ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       U-reg points to the start of the music data                     ;
;       $C84D points to frequency table (Init_Music_dft only)           ;
;       $C856 may need to be set.                                       ;
;                                                                       ;
;       D-reg, X-reg, Y-reg, U-reg trashed                              ;
;-----------------------------------------------------------------------;

Init_Music_chk: LDA     <Vec_Music_Flag ;Test sound active flag
                BMI     LF6B3           ;Continue sound if active
                BEQ     LF686           ;Return if sound not active
Init_Music:     LDX     #Freq_Table     ;Save pointer to frequency table
                STX     <Vec_Freq_Table
Init_Music_dft: LDA     #$80            ;Set sound active flag
                STA     <Vec_Music_Flag
                LDD     ,U++            ;Save address of ADSR table
                STD     <Vec_ADSR_Table
                LDD     ,U++            ;Save address of twang table
                STD     <Vec_Twang_Table
                STU     <Vec_Music_Ptr  ;Save pointer to music data
                JSR     Init_Music_Buf  ;Initialize music buffer
                LDD     #$1F1F
                STD     <Vec_ADSR_Timers+1;Init ADSR timers of chans 2 & 3
                LDD     #$0000
                STD     <Vec_Music_Freq+2;Clear frequency of channel 2
                STD     <Vec_Music_Freq+4;Clear frequency of channel 3
                STA     <Vec_Music_Chan ;A-reg = 0 (sound channel number?)
                BRA     LF6EC

; Continue currently playing sound here

LF6B3:          LDU     #Vec_ADSR_Timers;Get address of ADSR timers
                LDB     #$02            ;Count for three channels
LF6B8:          LDA     B,U             ;Get the channel's ADSR timer
                CMPA    #$1F
                BEQ     LF6C0           ;Skip if at maximum
                INC     B,U             ;Else increment the timer
LF6C0:          DECB                    ;Go back for the other channels
                BPL     LF6B8
                LDX     <Vec_Twang_Table
                LDU     #Vec_Music_Twang
                LDA     #$07            ;Twang limit is 6-8 depending on channel
LF6CA:          INC     ,U              ;Increment twang counter
                CMPA    ,U              ;Check against limit
                BGE     LF6D2
                CLR     ,U              ;Clear it if limit exceeded
LF6D2:          LDB     ,U+             ;Get twang count
                ANDB    #$07            ;Mask out low 3 bits
                LDB     B,X             ;Get twang value from table
                STB     ,U+             ;Update current twang value
                INCA                    ;Increment twang limit
                CMPA    #$09
                BLS     LF6CA           ;Go back until all three channels done
                DEC     <Vec_Duration   ;Decrement the duration timer
                BNE     LF74E           ;Update ADSR while note still playing
LF6E3:          LDA     <Vec_Music_Chan ;Go to next music channel
                DECA
                BPL     LF6EA           ;If < 0, set it to 2
                LDA     #$02
LF6EA:          STA     <Vec_Music_Chan
LF6EC:          LDB     [Vec_Music_Ptr] ;Get next byte of music data
                LDU     #Vec_ADSR_Timers;Clear ADSR timer for this channel
                CLR     A,U
                BITB    #$40            ;If $40 bit of music data set,
                BEQ     LF712           ;we're going to make some noise
                LDX     #Music_Table_1  ;Get bit mask for this channel
                LDA     A,X
                ANDA    <Vec_Music_Wk_7 ;Turn channel bit off for register 7
                STA     <Vec_Music_Wk_7
                LDA     <Vec_Music_Chan ;Set current channel bit in register 7
                ADDA    #$03
                LDA     A,X
                ORA     <Vec_Music_Wk_7
                STA     <Vec_Music_Wk_7
                ANDB    #$1F            ;Mask off low 5 bits of music data
                STB     <Vec_Music_Wk_6 ;and store in register 6
                BRA     LF735

LF712:          LDX     #Music_Table_2  ;If $40 bit of music data was cleared,
                LDA     A,X             ;Get bit mask for this channel
                ANDA    <Vec_Music_Wk_7 ;Turn channel bit off for register 7
                STA     <Vec_Music_Wk_7
                LDA     <Vec_Music_Chan ;Set current channel bit in register 7
                ADDA    #$03
                LDA     A,X
                ORA     <Vec_Music_Wk_7
                STA     <Vec_Music_Wk_7
                LDA     <Vec_Music_Chan ;Get $C855 * 2 + 3
                ASLA
                ADDA    #Vec_Music_Freq-Vec_ADSR_Timers
                LEAU    A,U             ;Point U-reg to #$C861 + $C855 * 2
                ANDB    #$3F            ;Mask off low 6 bits of music data,
                ASLB                    ;multiply by 2
                LDX     <Vec_Freq_Table ;Get pointer to note-to-frequency table
                LDD     B,X             ;Get note table data
                STD     ,U              ;Store in word at $C861-$C866
LF735:          LDX     <Vec_Music_Ptr  ;Re-get byte of music data
                LDB     ,X+
                STX     <Vec_Music_Ptr  ;Update music data pointer
                TSTB
                BMI     LF6E3           ;If byte>=$80, advance to next channel
                LDB     ,X+             ;Get second byte of music data
                BPL     LF748           ;If >=$80, (terminator)
                JSR     Init_Music_Buf  ;  clear music buffer,
                CLR     <Vec_Music_Flag ;  clear music flag,
                RTS                     ;  and exit

LF748:          STX     <Vec_Music_Ptr  ;Update music data pointer
                ANDB    #$3F            ;Duration in low 6 bits of second byte
                STB     <Vec_Duration   ;Store duration counter
LF74E:          LDY     <Vec_ADSR_Table ;Get pointer to ADSR table
                LDU     #Vec_ADSR_Timers;Point to ADSR timer table
                LDX     #Vec_Music_Wk_A
                LDA     #$02            ;Count for three channels
LF759:          LDB     ,U+             ;Get channel timer?
                BITB    #$01            ;Test low bit of ADSR index
                BEQ     LF766
                LSRB                    ;If odd, divide ADSR index by by 2
                LDB     B,Y             ;Get low nibble from ADSR table
                ANDB    #$0F
                BRA     LF76D

LF766:          LSRB                    ;If even, divide ADSR index by 2
                LDB     B,Y             ;Get high nibble from ADSR table
                LSRB
                LSRB
                LSRB
                LSRB
LF76D:          STB     A,X             ;Store ADSR value in regs 10-12
                DECA                    ;Decrement channel counter
                BPL     LF759           ;Go back for next channel
                LDU     #Vec_Music_Freq+6;Point to base frequency table
                LDX     #Vec_Music_Wk_5 ;Point to twang table
LF778:          LDD     ,--U            ;Get next base frequency
                TST     -8,U            ;Test twang value
                BPL     LF788
                NEG     -8,U            ;If <0, negate twang table entry
                SUBB    -8,U            ;Subtract negated value from frequency
                SBCA    #$00            ;Propagate borrow to high byte
                NEG     -8,U            ;Un-negate twang entry
                BRA     LF78C

LF788:          ADDB    -8,U            ;If >0 add twang to base frequency
                ADCA    #$00            ;Propagate carry to high byte
LF78C:          STD     ,X++            ;Store freq in regs 5/4, 3/2, 1/0
                CMPX    #Vec_Music_Work+14
                BNE     LF778
LF793_RTS:      RTS

;-----------------------------------------------------------------------;
;       F7A9    Select_Game                                             ;
;                                                                       ;
; This routine provides a game with the means for allowing the player   ;
; to choose the game number he would like to play, and the number of    ;
; players.  The game indicates the number of game versions available,   ;
; by placing the  value in the B register.  The number of players       ;
; allowed is specified in the A register.  If a parameter is passed in  ;
; with a value of 0, then the corresponding question will not be asked. ;
; The number of players selected is returned in $C879, while the game   ;
; number selected is returned in $C87A.                                 ;
;                                                                       ;
; This routine performs most of the work involved in allowing the       ;
; player to select a game version and the number of players.  It        ;
; displays the game # and player options, and allows the player a       ;
; certain amount of time to modify their values.  Anytime one of the    ;
; buttons is used to modify a value, the timer will be restarted.       ;
; When a button is pressed, the associated value is modified,           ;
; and then redisplayed on the screen.  This routine will return when    ;
; either the timer expires, or button 4 is pressed.                     ;
;                                                                       ;
; ENTRY A-reg = maximum number of players allowed                       ;
;       B-reg = number of game versions available                       ;
;                                                                       ;
; EXIT: DP = $C8                                                        ;
;       $C879 contains number of players selected                       ;
;       $C87A contains the game version selected                        ;
;                                                                       ;
;       D-reg, X-reg, Y-reg trashed                                     ;
;-----------------------------------------------------------------------;

Player_Str:     FDB     $20C0
                FDB     $40C0
                FCC     "PLAYER"
                FCB     $80

Game_Str:       FDB     $E0C0
                FDB     $01C0
                FCC     " GAME"
                FCB     $80

Select_Game:    STD     Vec_Max_Players ;Save max players and games
                TSTA                    ;If non-zero players specified,
                BEQ     LF7B1
                LDA     #$01            ;  set selection to 1
LF7B1:          TSTB                    ;If non-zero games specified,
                BEQ     LF7B6
                LDB     #$01            ;  set selection to 1
LF7B6:          STD     Vec_Num_Players ;Save default selection
                JSR     DP_to_C8        ;DP to RAM
                LDD     #$F850
                STD     <Vec_Text_HW
                STA     <$C83C          ;Set $C83C flag to non-zero
                BRA     LF82C

LF7C5:          JSR     Wait_Recal      ;Start with a fresh frame, DP to I/O
                CLRA                    ;Read buttons, all in direct mode
                JSR     Read_Btns_Mask
                JSR     Dec_3_Counters
                JSR     Intensity_7F    ;Brightness to normal
                LDA     Vec_Num_Players ;Display number of players
                LDY     #Player_Str
                BSR     Display_Option
                LDA     Vec_Num_Game    ;Display currently selected game
                LDY     #Game_Str
                BSR     Display_Option
                JSR     DP_to_C8        ;DP to RAM
                LDA     <$C83C          ;If $C83C=0, check buttons
                BEQ     LF7F1
                LDA     <Vec_Btn_State
                BNE     LF82C           ;If any button pressed, reset timers
                CLR     <$C83C          ;Clear $C83C flag
LF7F1:          LDA     <Vec_Counter_2  ;Return if counter 2 timed out
                BEQ     LF793_RTS
                LDA     <Vec_Counter_1  ;If repeat timer not timed out,
                BNE     LF7C5           ;  ignore the buttons
                LDA     <Vec_Button_1_4
                BNE     LF793_RTS       ;Return if button 4 pressed
                LDA     <Vec_Button_1_1
                BEQ     LF810
                LDA     <Vec_Num_Players; Ignore if no players option
                BEQ     LF810           ;If button 1 pressed,
                INCA                    ;   increment number of players
                CMPA    <Vec_Max_Players
                BLS     LF80C
                LDA     #$01            ;Reset to 1 if max players exceeded
LF80C:          STA     <Vec_Num_Players; Update number of players
                BRA     LF82C           ;Update timers and go back to the loop

LF810:          LDA     <Vec_Num_Game   ;Return to the loop if no game options
                BEQ     LF7C5
                LDB     <Vec_Button_1_2
                BEQ     LF821
                INCA                    ;If button 2 down, increment game
                CMPA    <Vec_Max_Games
                BLS     LF82A
                LDA     #$01            ;Reset to 1 if maximum exceeded
                BRA     LF82A

LF821:          LDB     <Vec_Button_1_3
                BEQ     LF7C5
                DECA                    ;If button 3 down, decrement game
                BNE     LF82A
                LDA     <Vec_Max_Games  ;Reset to max if zero reached
LF82A:          STA     <Vec_Num_Game
LF82C:          LDA     #$F3            ;Reset timers
                STA     <Vec_Counter_2
                COMA
                STA     <Vec_Counter_1
                BRA     LF7C5           ;Go back to the loop

;-----------------------------------------------------------------------;
;       F835    Display_Option  (not called by GCE cartridges)          ;
;                                                                       ;
; This routine displays the player or game option string, along with    ;
; the current value for that option.  The A-register contains the       ;
; value of the option, while the Y-register points to a block of the    ;
; following form:                                                       ;
;                                                                       ;
;       rel y, rel x,      ( for value )                                ;
;       rel y, rel x,      ( for option string)                         ;
;       option string,                                                  ;
;       0x80                                                            ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       A-reg=the option value.                                         ;
;       Y-reg points to the string block.                               ;
;                                                                       ;
;       D-reg, U-reg, X-reg trashed                                     ;
;-----------------------------------------------------------------------;

Display_Option: LDX     #$C85E          ;Point to temp storage
                PSHS    A               ;Save option
                BSR     Clear_Score     ;Clear scratch score accumulator
                LDA     ,S+             ;Get option back
                BEQ     LF84E           ;Exit printing nothing if option = zero
                BSR     Add_Score_a     ;Put option in scratch score accumulator
                TFR     X,U             ;Transfer X to be printed
                LDD     ,Y++            ;Get (y,x) of value
                JSR     Print_Str_d     ;Print value
                TFR     Y,U             ;Transfer Y to be printed
                JSR     Print_Str_yx    ;Print option string
LF84E:          RTS

;-----------------------------------------------------------------------;
;       F84F    Clear_Score                                             ;
;                                                                       ;
; This routine will initialize the passed-in score string (pointed to   ;
; by the X-register) to the following value:                            ;
;                                                                       ;
;       "     0",0x80                                                   ;
;                                                                       ;
; ENTRY X-reg points to seven byte score accumulator                    ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Clear_Score:    LDD     #' '*256+' '    ;Store the leading blanks
                STD     ,X
                STD     2,X
                STA     4,X
                LDD     #'0'*256+$80    ;Store the zero and terminator byte
                STD     5,X
                RTS

;-----------------------------------------------------------------------;
;       F85E    Add_Score_a                                             ;
;       F87C    Add_Score_d                                             ;
;                                                                       ;
; These routines take the BCD value in the D-register or the binary     ;
; value in the A-register, and add it to the 6-byte ASCII number        ;
; pointed by the X-register.                                            ;
;                                                                       ;
; ENTRY A-reg = binary value (Add_Score_a only)                         ;
;       D-reg = BCD value (Add_Score_d only)                            ;
;       U-reg = BCD conversion of A-reg (Add_Score_a only)              ;
;       X-reg points to six byte ASCII score accumulator                ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Add_Score_a:    LDU     #$0000          ;Initialize BCD result to zero
LF861:          CMPA    #99             ;Add in the hundreds
                BLS     LF86D
                SUBA    #100
                LEAU    $0100,U
                BRA     LF861

LF86D:          CMPA    #9              ;Add in the tens
                BLS     LF878
                SUBA    #10
                LEAU    $10,U
                BRA     LF86D

LF878:          LEAU    A,U             ;Add in the ones
                TFR     U,D             ;Move it to the D-register

Add_Score_d:    PSHS    A               ;Save BCD on stack in reverse order
                PSHS    B
                LDB     #$05
LF882:          CLRA                    ;Add zero to 10000 and 100000 digits
                CMPB    #$01
                BLS     LF897
                BITB    #$01            ;Add right nibble to hundreds and ones
                BEQ     LF88F
                LDA     ,S
                BRA     LF895

LF88F:          LDA     ,S+             ;Add left nibble to thousands and tens
                LSRA
                LSRA
                LSRA
                LSRA
LF895:          ANDA    #$0F            ;Isolate desired nibble
LF897:          ADDA    $C823           ;Add in carry ($C823 is normally zero)
                CLR     $C823           ;Clear carry
                ADDA    B,X             ;Add to digit
                CMPA    #'0'-1          ;If digit was a blank,
                BGT     LF8A5
                ADDA    #$10            ;  promote the result to a digit
LF8A5:          CMPA    #'9'            ;If a carry has occurred,
                BLS     LF8AE
                SUBA    #10             ;  subtract ten
                INC     $C823           ;  and set carry flag
LF8AE:          STA     B,X             ;Store resulting digit
                DECB                    ;Go back for more digits
                BPL     LF882
                CLR     $C823           ;Clear $C823 back to zero
                CLRB

;-----------------------------------------------------------------------;
;       F8B7    Strip_Zeros                                             ;
;                                                                       ;
; This routine strips the leading zeros from a score accumulator.       ;
;                                                                       ;
; ENTRY B-reg = first digit to start with (usually zero)                ;
;       X-reg points to six byte ASCII score accumulator                ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Strip_Zeros:    LDA     B,X             ;Test current digit
                CMPA    #'0'
                BNE     LF8C6           ;Exit if not zero
                LDA     #' '            ;Change it to a blank
                STA     B,X
                INCB
                CMPB    #$05
                BLT     Strip_Zeros
LF8C6:          RTS

;-----------------------------------------------------------------------;
;       F8C7    Compare_Score                                           ;
;                                                                       ;
; This routine will compare two BCD score strings, to determine which   ;
; one is higher.  The two strings are pointed to by the U and X         ;
; registers.  Depending upon how the scores compare, one of the         ;
; following values will be returned in the A-register:                  ;
;                                                                       ;
;       1) The scores are the same: a = 0                               ;
;       2) X score > U score:   a = 1                                   ;
;       3) U score > X score:   a = 2                                   ;
;                                                                       ;
; ENTRY X-reg points to first score string (terminated with $80)        ;
;       U-reg points to second score string                             ;
;                                                                       ;
; EXIT: A-reg returns result of the compare                             ;
;                                                                       ;
;       B-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Compare_Score:  PSHS    X,U             ;Save score pointers
                CLRA                    ;Default to scores are the same
LF8CA:          LDB     ,X+
                BMI     LF8D6           ;Return if end of string
                CMPB    ,U+
                BEQ     LF8CA           ;Continue if byte is the same
                BHI     LF8D5           ;Return 1 if X > U
                INCA                    ;Return 2 if U > X
LF8D5:          INCA
LF8D6:          PULS    X,U,PC          ;Restore pointers and return

;-----------------------------------------------------------------------;
;       F8D8    New_High_Score                                          ;
;                                                                       ;
; This routine compares a players score string, pointed to by the       ;
; X register, to the current hi score, pointed by the U register.  If   ;
; the player's score is higher than the currently saved hi score, then  ;
; the player's score will be copied into the hi score buffer pointed    ;
; to by the U register.                                                 ;
;                                                                       ;
; ENTRY X-reg points to a player's score string                         ;
;       U-reg points to the high score string (usually $CBEB?)          ;
;                                                                       ;
;       X-reg, U-reg, D-reg trashed                                     ;
;-----------------------------------------------------------------------;

New_High_Score: BSR     Compare_Score   ;Compare the scores
                CMPA    #$01
                BNE     LF8E4           ;Return if X is not > U
LF8DE:          LDA     ,X+             ;Copy the new high score
                STA     ,U+
                BPL     LF8DE           ;until end of string encountered
LF8E4:          RTS

;-----------------------------------------------------------------------;
;       F8E5    Obj_Will_Hit_u                                          ;
;       F8F3    Obj_Will_Hit                                            ;
;                                                                       ;
; This routine first modifies the position of the object, and then it   ;
; checks to see if the missile has hit the object.  The Y register      ;
; contains the (y,x) position of the object, the U register contains    ;
; a pointer to the (y,x) modification values, the X register contains   ;
; the missile (y,x) position, and the D register contains the           ;
; (height/2, width/2) of the object.                                    ;
;                                                                       ;
; (0,u) is temporarily added to the y position of the object, and       ;
; (1,u) is temporarily added to the x position.                         ;
;                                                                       ;
; ENTRY Y-reg = (y,x) position of the object                            ;
;       X-reg = (y,x) position of the missile                           ;
;       U-reg points to movement (y,x) (Mov_Obj_Hit_u only)             ;
;       U-reg = movement (y,x) (Mov_Obj_Hit only)                       ;
;       D-reg = (h/2,w/2) size of object                                ;
;                                                                       ;
; EXIT: Carry bit set if the object & missile have collided             ;
;                                                                       ;
;       ALL registers saved.  Even the original Y-register.             ;
;-----------------------------------------------------------------------;

Obj_Will_Hit_u: PSHS    Y               ;Save regs for the hit-test code
                PSHS    D,X,Y
                LDD     4,S             ;Get object position
                ADDA    ,U              ;Add it to the modification values
                ADDB    1,U
LF8EF:          STD     4,S             ;Put updated object position back
                BRA     LF903           ;Go do the hit-test

Obj_Will_Hit:   PSHS    Y               ;Save regs for the hit-test code
                PSHS    D,X,Y
                TFR     U,D             ;Get modification values
                ADDA    4,S             ;Add them to the object position
                ADDB    5,S
                BRA     LF8EF           ;Put update position back and hit-test

;-----------------------------------------------------------------------;
;       F8FF    Obj_Hit                                                 ;
;                                                                       ;
; Thit routine checks to see if a missile hashit an object.  If the     ;
; missile has hit the object, then the carry bit will be set;           ;
; otherwise, the carry bit will be cleared.  A hit is checked for in    ;
; the following fashion:                                                ;
;                                                                       ;
;   if (object y-height/2) <= missile y <= (object y+height/2)          ;
;                               and                                     ;
;      (object x-width/2)  <= missile x <= (object x+width/x)           ;
;                                                                       ;
;   then the missile hit, otherwise it missed.                          ;
;                                                                       ;
; ENTRY Y-reg = (y,x) position of the object                            ;
;       X-reg = (y,x) position of the missile                           ;
;       D-reg = (h/2,w/2) size of object                                ;
;                                                                       ;
; EXIT: Carry bit set if the object & missile have collided             ;
;                                                                       ;
;       All registers preserved.                                        ;
;-----------------------------------------------------------------------;

Obj_Hit:        PSHS    Y               ;Save some regs
                PSHS    D,X,Y
LF903:          TFR     S,X             ;Point X to the stack
                CLRB                    ;Offset to point to y
LF906:          ABX
                LDA     4,X             ;Get height/2
                ADDA    ,X              ;Add object y
                BVC     LF90F
                LDA     #$7F            ;Set to $7F if overflow
LF90F:          CMPA    2,X             ;Branch if missile out of range
                BLT     LF928
                LDA     4,X             ;Get height/2
                SUBA    ,X              ;Subtract object y
                BVC     LF91B
                LDA     #$80            ;Set to $80 if overflow
LF91B:          CMPA    2,X             ;Branch if missile out of range
                BGT     LF928
                INCB                    ;Offset to point to x
                CMPB    #$02
                BCS     LF906           ;Go back for x
                ORCC    #$01            ;Object in range, set carry
                BRA     LF92A

LF928:          ANDCC   #$FE            ;Object not in range, clear carry
LF92A:          PULS    D,X,Y
                PULS    Y,PC

;-----------------------------------------------------------------------;
;       F92E    Explosion_Snd                                           ;
;                                                                       ;
; This routine appears to generate some type of an explosion sound,     ;
; dependent upon the 4 bytes which are pointed to by the U register.    ;
; You will probably need to call Do_Sound for this to do anything.      ;
;                                                                       ;
; The format of the 4-byte block is:                                    ;
;       1)      Bits 0-2 = ?    Stored in $C85D                         ;
;               Bits 3-5 = ?    Stored in $C853                         ;
;               Bits 6-7 = 0                                            ;
;               Bits 0-2 and 3-5 are ORed and stored in bits 0-2 of     ;
;                                                               $C854   ;
;       2)      <0 = ?          Something to do with register 6         ;
;               =0 = ?                                                  ;
;               >0 = ?                                                  ;
;       3)      <0 = ?                                                  ;
;               =0 = ?                                                  ;
;               >0 = ?                                                  ;
;       4)      Speed?  Higher values = lower duration?                 ;
;                                                                       ;
; ENTRY DP = $C8                                                        ;
;       U-reg points to 4-byte block of data if $C867 high bit set      ;
;                                                                       ;
;       D-reg, X-reg trashed                                            ;
;-----------------------------------------------------------------------;

Explosion_Snd:  LDA     <Vec_Expl_Flag
                BPL     LF95B
                ANDA    #$7F
                STA     <Vec_Expl_Flag
                LDX     #Vec_Expl_1     ;Copy 4 bytes from U-reg to $C858
                LDA     #$04
                JSR     Move_Mem_a
                LSRB                    ;Divide first byte by 8
                LSRB
                LSRB
                ORB     <Vec_Expl_1     ;OR with first byte
                ANDB    #$07            ;AND with 7
                STB     <Vec_Expl_Chans ;store in $C854
                LDB     <Vec_Expl_1     ;Get first byte
                ANDB    #$38            ;Mask off bits 3-5
                STB     <Vec_Expl_ChanA ;store in $C853
                LDB     <Vec_Expl_1     ;Get first byte
                ANDB    #$07            ;AND with 7
                STB     <Vec_Expl_ChanB ;store in $C85D
                LDB     #$02            ;Start with channel number 2
                STB     <Vec_Expl_Chan
                LDA     #$7F            ;Initialize time count
                BRA     LF968

LF95B:          LDA     <Vec_Expl_Timer
                BEQ     LF9C9_RTS
                SUBA    <Vec_Expl_4
                BPL     LF968
                CLRB
                STB     <Vec_Expl_Timer
                BRA     LF9CA

LF968:          STA     <Vec_Expl_Timer
                LSRA
                LSRA
                LDB     <Vec_Expl_ChanA
                BEQ     LF97D
                STA     <Vec_Music_Wk_6
                LDB     <Vec_Expl_2
                BMI     LF97B
                BEQ     LF97D
                TFR     A,B
                COMB
LF97B:          STB     <Vec_Music_Wk_6
LF97D:          LSRA
                CMPA    #$07
                BLS     LF987
                CMPA    #$0F
                BEQ     LF987
                INCA
LF987:          LDB     <Vec_Expl_3
                BMI     LF991
                BEQ     LF98F
                EORA    #$0F
LF98F:          TFR     A,B
LF991:          BSR     LF9CA
                LDB     <Vec_Expl_ChanB
                BEQ     LF9C2
LF997:          LDA     <Vec_Expl_Chan  ;Get channel number
                DECA                    ;Decrement channel number
                BPL     LF99E
                LDA     #$02            ;Reset to 2 if less than zero
LF99E:          STA     <Vec_Expl_Chan  ;Save channel number
                JSR     Bitmask_a       ;Get bit mask of the channel
                BITA    <Vec_Expl_ChanB
                BEQ     LF997           ;Go back if not in for $C85D
                LDB     <Vec_Expl_Chan
                ASLB                    ;Negative of channel number ; 2
                NEGB
                LDX     #Vec_Music_Wk_1 ;  (registers 1, 3, and 5)
                LEAX    B,X
                JSR     Random
                ANDA    #$0F
                CMPA    #$05
                BHI     LF9BC
                ASLA
                ADDA    #$05
LF9BC:          STA     ,X
                LDA     <Vec_Random_Seed+1
                STA     1,X
LF9C2:          LDA     <Vec_Expl_1
                COMA
                ANDA    <Vec_Music_Wk_7
                STA     <Vec_Music_Wk_7
LF9C9_RTS:      RTS

LF9CA:          LDA     <Vec_Expl_Chans
                LDX     #Vec_Music_Wk_7
LF9CF:          TSTA                    ;Exit if all channels done
                BEQ     LF9DB_RTS
                LEAX    -1,X            ;Point to next register (8-10)
                LSRA
                BCC     LF9CF
                STB     ,X              ;Store noise value if chan in use
                BRA     LF9CF

LF9DB_RTS:      RTS

Bit_Masks:      FCB     $01,$02,$04,$08,$10,$20,$40,$80 ;For Bitmask_a

Music_Table_1:  FCB     $F7,$EF,$DF,$01,$02,$04         ;For noise

Music_Table_2:  FCB     $FE,$FD,$FB,$08,$10,$20         ;For music

Recal_Points:   FDB     $7F7F,$8080                     ;For Recalibrate

Char_Table:     FDB     $0020,$5050,$20C8,$2010,$1040,$2000,$0000,$0008
                FDB     $3020,$7070,$10F8,$30F8,$7070,$0060,$0000,$0070
                FDB     $7020,$F070,$F0F8,LF878,$8870,$0888,$8088,$88F8
                FDB     $F070,$F070,$F888,$8888,$8888,$F870,$8070,$2000
                FDB     $0020,$0820,$0000,$0038,$1020,$4444,$00FE,$FFFE

                FDB     $0070,$5050,$78C8,$5020,$2020,$A820,$0000,$0008
                FDB     $4860,$8888,$3080,$4008,$8888,$6060,$1000,$4088
                FDB     $8850,$4888,$4880,$8080,$8820,$0890,$80D8,$C888
                FDB     $8888,$8888,$A888,$8888,$8888,$0840,$8008,$5000
                FDB     $0070,$0C20,$7070,$0044,$1070,$0000,$6C82,$FFFE

                FDB     $0070,$50F8,$A010,$5040,$4010,$7020,$0000,$0010
                FDB     $4820,$0808,$50F0,$8010,$8888,$6000,$2078,$2008
                FDB     $A888,$4880,$4880,$8080,$8820,$08A0,$80A8,$A888
                FDB     $8888,$8840,$2088,$8888,$5050,$1040,$4008,$8800
                FDB     $70A8,$0A20,$88F8,$60BA,$3820,$0000,$9282,$FFFE

                FDB     $0020,$0050,$7020,$6000,$4010,$A8F8,$0070,$0020
                FDB     $4820,$7030,$9008,$F020,$7078,$0060,$4000,$1010
                FDB     $B888,$7080,$48E0,$E098,$F820,$08C0,$80A8,$9888
                FDB     $F088,$F020,$2088,$50A8,$2020,$2040,$2008,$0000
                FDB     $FE20,$0820,$88F8,$F0A2,$38F8,$8238,$9282,$FFFE

                FDB     $0000,$00F8,$7040,$A800,$4010,$A820,$4000,$0040
                FDB     $4820,$8008,$F808,$8840,$8808,$6060,$2078,$2020
                FDB     $B0F8,$4880,$4880,$8088,$8820,$08A0,$8088,$8888
                FDB     $80A8,$A010,$2088,$50A8,$5020,$4040,$1008,$0000
                FDB     $FE20,$78A8,$88F8,$F0BA,$7C20,$4444,$6C82,$FFFE

                FDB     $0000,$0050,$2898,$9000,$2020,$0020,$4000,$0080
                FDB     $4820,$8088,$1088,$8880,$8810,$6020,$1000,$4000
                FDB     $8088,$4888,$4880,$8088,$8820,$8890,$8888,$8888
                FDB     $8090,$9088,$2088,$20A8,$8820,$8040,$0808,$0000
                FDB     $4820,$F070,$7070,$6044,$6C50,$3882,$0082,$FFFE

Char_Table_End: FDB     $0020,$0050,$F898,$6800,$1040,$0000,$8000,$8080
                FDB     $3070,$F870,$1070,$7080,$7060,$0040,$0000,$0020
                FDB     $7888,$F070,$F0F8,$8078,$8870,$7088,$F888,$88F8
                FDB     $8068,$8870,$2070,$2050,$8820,$F870,$0870,$00F8
                FDB     $0020,$6020,$0000,$0038,$8288,$0000,$00FE,$FFFE

;       These tables are used by the rise/run calculations

DFC24:          FDB     $0011,$4130,$2110,$2031

DFC2C:          FDB     $0001,$0306,$0A0F,$151C,$242D,$0810,$0810,$0B08
                FDB     $100D,$0A08,$100E,$0B09,$0810,$0E0C,$0A09,$0810
                FDB     $0E0D,$0B0A,$0908,$100F,$0D0C,$0B0A,$0908,$100F
                FDB     $0E0C,$0B0A,$0909,$0810,$0F0E,$0D0C,$0B0A,$0909
                FCB     $08

DFC6D:          FDB     $0019,$324A,$6279,$8EA2,$B5C6,$D5E2,$EDF5,$FBFF
                FDB     $FFFF,$FBF5,$EDE2,$D5C6,$B5A2,$8E79,$624A,$3219

;       Music note to frequency table

Freq_Table:     FDB     $03BD,$0387,$0354,$0324,$02F7,$02CD,$02A4,$027E
                FDB     $025B,$0239,$0219,$01FB,$01DE,$01C3,$01AA,$0192
                FDB     $017C,$0166,$0152,$013F,$012D,$011C,$010C,$00FD
                FDB     $00EF,$00E2,$00D5,$00C9,$00BE,$00B3,$00A9,$00A0
                FDB     $0097,$008E,$0086,$007F,$0078,$0071,$006B,$0065
                FDB     $005F,$005A,$0055,$0050,$004B,$0047,$0043,$003F
                FDB     $003C,$0038,$0035,$0032,$002F,$002D,$002A,$0028
                FDB     $0026,$0024,$0022,$0020,$001E,$001C,$001B,$0000

;       FD0D = power-on music and music for Crazy Coaster and Narrow Escape

Intro_Music:    FDB     DFEE8,DFEB6,$931F,$0C93,$1F06,$989F,$243C,$1180

;       FD1D = music for Berzerk?

DFD1D:          FDB     DFD69,DFD79,$2107,$2107,$2107,$2107,$2107,$2107
                FDB     $210E,$999F,$240E,$959B,$200E,$2107,$2107,$2107
                FDB     $2107,$2107,$2107,$9DA3,$280E,$A0A6,$2B0E,$2202
                FDB     $2802,$2D02,$2802,$2202,$2802,$2D02,$2802,$2202
                FDB     $2802,$2D02,$2802,$2E02,$2D28,$2180

;       FD69 = ADSR table for Berzerk and FF7A

DFD69:          FDB     $EFFF,$FEDC,$BA00,$0000,$0000,$0000,$0000,$0000

;       FD79 = twang table for Berzerk and Scramble

DFD79:          FDB     $0001,$0201,$00FF,$FEFF

;       FD81 = music

DFD81:          FDB     DFDC3,DFEB6,$5124,$5006,$5006,$500C,$5006,$5006
                FDB     $5004,$5004,$5004,$5018,$5004,$5004,$5004,$500C
                FDB     $500C,$5024,$5006,$5006,$500C,$5006,$5006,$5004
                FDB     $5004,$5004,$5018,$5004,$5004,$5004,$500C,$5018
                FDB     $2680

;       FDC3 = ADSR table for FD81 and FF8F

DFDC3:          FDB     $FDBA,$9876,$5544,$3322,$1100,$0000,$0000,$0000

;       FDD3 = music for Scramble

DFDD3:          FDB     DFE28,DFD79,$981C,$103F,$0898,$1C04,$981C,$0498
                FDB     $1C10,$3F08,$981C,$0498,$1C04,$981C,$0893,$1808
                FDB     $981C,$089C,$1F08,$981C,$0893,$1808,$981C,$0893
                FDB     $1808,$981C,$089C,$1F08,$981C,$0893,$1808,$981C
                FDB     $0893,$1808,$981C,$089C,$1F08,$981C,$0893,$1808
                FCB     $9C,$1F,$30,$1A,$80

;       FE28 = ADSR table for Scramble, FF26, FF44, FF62

DFE28:          FDB     $FFFE,$DCBA,$9876,$5432,$1000,$0000,$0000,$0000

;       FE38 = music for Solar Quest

DFE38:          FDB     DFE66,DFEB6,$0C18,$1118,$0C18,$1118,$0C18,$1118
                FDB     $0C12,$0C06,$1118,$9D21,$189F,$2318,$A124,$18A3
                FDB     $2618,$9FA4,$2818,$0712,$0706,$003C,$1880

;       FE66 = ADSR table for Solar Quest

DFE66:          FDB     $DEEF,$FEDC,$BA00,$0000,$0000,$0000,$0000,$0000

;       FE76 = music

DFE76:          FDB     DFEB2,DFEB6,$1806,$1A06,$1C0C,$180C,$1A24,$2318
                FDB     $1706,$1806,$1A0C,$170C,$1824,$2418,$A428,$0CA3
                FDB     $260C,$A124,$0C9F,$230C,$9D21,$189A,$1F18,$1706
                FDB     $1806,$1A0C,$170C,$1824,$2424,$1880

;       FEB2 = ADSR table for FE76

DFEB2:          FDB     $FFEE,$DDCC

;       FEB6 = "flat" twang table

DFEB6:          FDB     $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000

;       FEC6 = music

DFEC6:          FDB     DFEE8,DFEB6,$969A,$1D1E,$9195,$181E,$9498,$1B1E
                FDB     $8F94,$1814,$160A,$8C91,$1514,$160A,$9195,$1832
                FDB     $1880

;       FEE8 = ADSR table for FEC6

DFEE8:          FDB     $EEFF,$FFEE,$EEDD,$CCBB,$AA99,$8888,$8888,$8888

;       FEF8 = music for Melody Master

DFEF8:          FDB     DFF16,DFEB6,$1C06,$1F06,$1C06,$1806,$1A06,$1806
                FDB     $1506,$1306,$1806,$1306,$1706,$181E,$1880

;       FF16 = ADSR table for FEF8

DFF16:          FDB     $FFFF,$EEEE,$DDDD,$CCCC,$0000,$0000,$0000,$0000

;       FF26 = music

DFF26:          FDB     DFE28,DFEB6,$160F,$1605,$1605,$1605,$1A0F,$160F
                FDB     $1D0F,$1D05,$1D05,$1D05,$210F,$1D32,$1D80

;       FF44 = music

DFF44:          FDB     DFE28,DFEB6,$1606,$1602,$1602,$1602,$1A06,$1606
                FDB     $1D06,$1D02,$1D02,$1D02,$2106,$1D32,$1180

;       FF62 = music

DFF62:          FDB     DFE28,DFEB6,$1B0F,$1605,$1605,$1605,$1730,$1605
                FDB     $1605,$1605,$1730,$1680

;       FF7A = music

DFF7A:          FDB     DFD69,DFEB6,$A023,$12A0,$230C,$9C20,$069E,$2112
                FCB     $9C,$20,$32,$13,$80

;       FF8F = music

DFF8F:          FDB     DFDC3,DFEB6,$1604,$1604,$1604,$1604,$1A08,$1C80

;-----------------------------------------------------------------------;
;       FF9F    Draw_Grid_VL                                            ;
;                                                                       ;
; This routine apparently will draw a vector list using a 16x16 grid,   ;
; and occasionally using regular vector lists too.  This could possibly ;
; be useful for drawing gridded things like a chess board and all of    ;
; its pieces at the same time.                                          ;
;                                                                       ;
; The master vector list contains multiple sublists that start with     ;
; a flag byte:                                                          ;
;       Bit 7 = draw the next regular vector list (from X-reg) first    ;
;       Bit 6 = this is the last sublist in the master vector list      ;
;       Bits 5,4 = unused                                               ;
;       Bits 3-0 = number of points in this sublist (1-16)              ;
;                                                                       ;
; The points are stored as a pair of nibbles:                           ;
;       Bits 7-4 = Y coordinate (?)                                     ;
;       Bits 3-0 = X coordinate (?)                                     ;
;                                                                       ;
; ENTRY DP = $D0                                                        ;
;       X-reg points to regular vector lists                            ;
;       Y-reg points to master vector list                              ;
;                                                                       ;
; EXIT: X-reg points to next byte after last regular vector list used   ;
;       Y-reg points to next byte after end of master vector list       ;
;                                                                       ;
;       D-reg trashed                                                   ;
;-----------------------------------------------------------------------;

Draw_Grid_VL:   LDA     ,Y+             ;Get flag byte
                BRA     LFFAB           ;Jump into loop

LFFA3:          JSR     Mov_Draw_VL_d   ;Draw a regular vector list
                LDA     $C880           ;Clear vector list flag
                ANDA    #$7F
LFFAB:          STA     $C880           ;Save flag byte for vector count
LFFAE:          DEC     $C880           ;Decrement vector count
                LDA     ,Y              ;Get Y of next point
                ASRA
                ANDA    #$F8
                LDB     ,Y+             ;Get X of next point
                ASLB
                ASLB
                ASLB
                ASLB
                ASRB
                ANDB    #$F8
                TST     $C880           ;Draw a regular vector list?
                BMI     LFFA3           ;Go back if so
                JSR     Draw_Line_d     ;Draw a line to the new point
                LDA     $C880           ;Check vector counter
                BITA    #$0F
                BNE     LFFAE           ;Go back if more vectors to draw
                BITA    #$20            ;Check for end of list
                BEQ     Draw_Grid_VL    ;Go back if more lists to draw
                RTS

                FCC     "KARRSOFT82LDMCBCJT82LDMCBCJ"

                FDB     0,0             ;Unused

                FDB     $CBF2           ;SWI3 vector
                FDB     $CBF2           ;SWI2 vector
                FDB     $CBF5           ;FIRQ vector
                FDB     $CBF8           ;IRQ vector
                FDB     $CBFB           ;SWI vector
                FDB     $CBFB           ;NMI vector
                FDB     Start           ;Reset vector

                END     Start
