;============================================================
;THESE ARE THE DECLARATIONS FOR CONSTANTS AND VARIABLES THAT
;WILL BE USED WITHIN THE COMMODORE 64 DURING PROGRAM RUNS
;============================================================
;
PB64   =$DD00     ;PORT CONTAINING SERIAL I/O BITS
DIN64  =$80       ;DATA IN LINE
DOUT64 =$20       ;DATA OUT LINE
CIN64  =$40       ;CLOCK IN LINE
COUT64 =$10       ;CLOCK OUT LINE
ATNOUT =$08       ;ATN OUTPUT (NOT USED)
;
;KERNAL ROUTINES USED IN THIS PROGRAM
;
CHKIN  =$FFC6     ;MAKE FILE INPUT
CKOUT  =$FFC9     ;MAKE FILE OUTPUT
CLRCHN =$FFCC     ;CLEAR CHANNELS
GETIN  =$FFE4     ;GET A CHARACTER FROM CHANNEL
CHROUT =$FFD2     ;PRINT A CHARACTER TO CHANNEL
SETLFS =$FFBA     ;SET LOGICAL FILE NUMBER AND DEVICE
SETNAM =$FFBD     ;SET FILE NAME FOR OPEN
OPEN   =$FFC0     ;OPEN A FILE
CLOSE  =$FFC3     ;CLOSE A FILE
;
;ZERO PAGE USED BY THIS PROGRAM
;
BYTE64 =$FB       ;INCOMING OR OUTGOING BYTE DURING FAST I/O
BCNT64 =$FC       ;COUNTER FOR BYTES TO SEND OR RECEIVE
LPB64  =$FD       ;COPY OF LAST STATE OF THE PORT FOR BURST LOAD
PTR    =$FE       ;POINTER FOR DATA FETCHES OR STORES
PTR2   =$6A       ;WORK POINTER (IN FAC #2)
VPTR   =$6C       ;POINTER TO THE SCREEN
CPTR   =$62       ;POINTER TO THE COLOR (IN FAC #1)
COLOR  =$64       ;CURRENT COLOR TO USE
TEMP   =$65       ;TEMPORARY VARIABLE
VARTAB =$2D       ;END OF PROGRAM POINTER
;
;NON ZERO PAGE VARIABLES USED BY THIS PROGRAM
;
PRGCNT =$02A7     ;NUMBER OF PROGRAMS ON THE DISK
CURPRG =$02A8     ;CURRENT PROGRAM THAT CURSOR IS ON
FPRG   =$02A9     ;FIRST PROGRAM ON THE SCREEN
CURLIN =$02AA     ; CURRENT LINE IN MENU THAT CURSOR IS ON
WRKLIN =$02AB     ;USED DURING FILENAME DISPLAY
WRKPRG =$02AC     ;USED DURING FILENAME DISPLAY
DCNTR  =$02AD     ;COUNTER FOR BYTES DOWNLOADED TO DISK
;
;============================================================
;THESE ARE THE DECLARATIONS FOR CONSTANTS AND VARIABLES THAT
;WILL BE USED WITHIN THE 1541 DRIVE DURING PROGRAM RUNS
;============================================================
;
;
PB15   =$1800     ;PORT CONTAINING SERIAL I/O BITS
DIN15  =$01       ;DATA IN LINE
DOUT15 =$02       ;DATA OUT LINE
CIN15  =$04       ;CLOCK IN LINE
COUT15 =$08       ;CLOCK OUT LINE
ATNIN  =$80       ;ATN INPUT (NOT USED)
;
JOBS   =$00       ;JOB QUEUE FOR THE CONTROLLER
HDRS   =$06       ;ARGUMENTS FOR EACH JOB (ONLY FIRST 4 ARE USED)
;
READ   =$80       ;THESE ARE THE CODES FOR EACH JOB TO BE PERFORMED
WRITE  =$90
WVERFY =$A0
SEEK   =$B0
SECSEK =SEEK+$08
BUMP   =$C0
JUMPC  =$D0
EXEC   =$E0
;
BUF1   =$0300     ;ADDRESSES OF EACH BUFFER IN DISK RAM
BUF2   =$0400     ;FIRST 2 BUFFERS ARE USED FOR DATA
BUF3   =$0500     ;THIS IS WHERE THE STATIC CODE LIVES
BUF4   =$0600     ;TRANSIENT BLOCKS OF CODE ARE DOWNLOADED TO HERE
BUF5   =$0700     ;THIS BUFFER IS USED FOR VARIABLE STORAGE
;
;ZERO PAGE STORAGE USED BY THE DISK ROUTINES, USES HDRS ASSOCIATED
;WITH BUFFERS 3 THROUGH 5 BECAUSE THESE ARE NEVER USED BY THE CONTROLLER
;
BUFPTR =HDRS+$04  ;POINTER TO CURRENT ACTIVE BUFFER
JOBOFF =HDRS+$06  ;INDEX TO CURRENT ACTIVE JOB
WRKOFF =HDRS+$07  ;PREVIOUS ACTIVE JOB
BYTE15 =HDRS+$08  ;CURRENT INPUT/OUTPUT BYTE
BCNT15 =HDRS+$09  ;COUNTER FOR MULTIPLE BYTE I/O
;
;NON ZERO PAGE STORAGE USED BY THE DISK ROUTINES
;
*=BUF5+$80        ;JUST USE THE UPPER HALF OF BUFFER 5
;
LPB15 *=*+1       ;COPY OF LAST PORT VALUE DURING BURST LOAD
;
;===================================================================
;THIS SECTION OF CODE STARTS THE PROGRAM BY DOWNLOADING THE STATIC
;FAST INPUT OUTPUT CODE TO BUFFER 5 IN THE DRIVE.  �HIS FAST I/O
;ROUTINE IS THEN USED FOR ALL SUBSEQUENT CODE TRANSFERS BETWEEN THE
;DRIVE AND THE 64.  �OTE, THESE I/O ROUTINES WORK WITH THE SCREEN
;AND INTERRUPTS TURNED ON BUT AREN'T AS FAST AS THE BURST TRANSFERS
;===================================================================
;
*=$0801  (C64 ����� START ADDRESS)
;
;THIS DATA FORMS A BASIC LINE 10 THAT SAYS SYS2061
;
       .BYTE $0B,$08,$0A,0,$9E,'2061',0,0,0
;
AD2061 LDA #15       ;OPEN A COMMAND CHANNEL TO THE DRIVE
       TAY           ;BUT DON'T INITIALISE, THERE'S NO NEED
       LDX #8        ;MAYBE THIS SHOULD BE VARIABLE ******
       JSR SETLFS
       LDA #$00      ;NO NAME TO SEND
       JSR SETNAM
       JSR OPEN
;
       LDA #<DCODE   ;BUILD A POINTER TO THE DISK CODE
       STA PTR
       LDA #>DCODE
       STA PTR+1
;
       LDA #<BUF3    ;BUILD ADDRESS OF DESTINATION INTO THE MEMORY...
       STA DDEST     ;WRITE COMMAND
       LDA #>BUF3    ;THIS ISN'T REALLY NEEDED BUT IT IS SAFER IN...
       STA DDEST+1   ;CASE THIS CODE IS CALLED AGAIN
;
       LDA #<DCLEN   ;SET UP COUNTER FOR LENGTH OF DISK CODE
       STA DCNTR
       LDA #>DCLEN
       STA DCNTR+1
;
;THIS IS THE MAIN LOOP TO DOWNLOAD CODE IN 32 BYTE SECTIONS
;
DOWN00 LDX #15       ;MAKE CHANNEL 15 OUTPUT
       JSR CKOUT
       LDX #$00      ;AND NOW OUTPUT THE COMMAND STRING TO THE DISK
;
DOWN10 LDA MEMCMD,X
       JSR CHROUT
       INX
       CPX #6        ;HAVE WE SENT ALL THE BYTES YET?
       BNE DOWN10    ;NOPE, NOT YET
;
       LDY #$00      ;NOW OUTPUT 32 BYTES OF THE DISK CODE
DOWN15 LDA (PTR),Y
       JSR CHROUT
       INY
       CPY #32
       BNE DOWN15
;
       JSR CLRCHN    ;LET THE DISK EXECUTE THIS COMMAND
       CLC
       LDA DDEST     ;MOVE THE DESTINATION POINTER ALONG BY 32 BYTES
       ADC #32
       STA DDEST
       BCC DOWN16
       INC DDEST+1
;
DOWN16 CLC           ;MOVE POINTER TO THE SOURCE DATA ON BY 32 BYTES
       LDA PTR
       ADC #32
       STA PTR
       BCC DOWN20    ;THIS CAN WRAP OVER A PAGE BOUNDARY
       INC PTR+1
;
DOWN20 LDA DCNTR     ;CHECK IF WE HAVE DOWNLOADED ALL DATA
       SEC
       SBC #32
       STA DCNTR
       BCS DOWN00    ;STILL MORE DATA TO SEND
       LDA DCNTR+1   ;CHECK THE HI BYTE
       BEQ DOWN25    ;ALL DATA HAS BEEN SENT
       DEC DCNTR+1
       JMP DOWN00
;
;
;==================================================================
;GETS TO HERE WHEN ALL OF THE CODE HAS BEEN DOWNLOADED, THE ROUTINE
;MUST NOW START THE DISK CODE RUNNING WITH A U3 COMMAND AND GIVE IT
;A LITTLE TIME TO INSTALL ITSELF BEFORE SENDING IT COMMANDS.
;==================================================================
;
DOWN25 LDX #15       ;MAKE CHANNEL 15 OUTPUT
       JSR CKOUT
       LDA #'U'      ;SEND A U3 COMMAND TO EXECUTE CODE AT $0500
       JSR CHROUT
       LDA #'3'
       JSR CHROUT
       JSR CLRCHN    ;THIS WILL LEAVE DOUT64 AND COUT64 =�0
       JMP MENU      ;ALL INITIALISED AND READY TO GO SO PRINT THE MENU
;
;
MEMCMD .BYTE 'M-W'   ;COMMAND TO DO A MEMORY WRITE
DDEST  .WORD BUF3    ;VARIABLE, WHERE TO WRITE TO
       .BYTE 32      ;CONSTANT, NUMBER OF BYTES TO BE WRITTEN
;
;
;================================================================
;THIS IS THE SECTION OF CODE THAT GETS DOWNLOADED TO THE DRIVE ON
;POWER UP OF THE PROGRAM.  IT CONTAINS FAST TRANSFER ROUTINES FOR
;BOTH 64 TO 1541 AND 1541 TO 64.  THESE ROUTINES WORK WITH THE
;SCREEN TURNED ON AND INTERRUPTS RUNNING AND ARE USED FOR SENDING
;COMMANDS TO THE DRIVE AND RETURNING ERRORS TO THE 64.  �HERE IS
;ALSO A HANDSHAKE THAT WORKS WITH THE 64'S SCREEN TURNED OFF FOR
;DOING SUPER FAST BURST LOAD OF PROGRAMS.
;
;THE JSR COMMANDS USE A COMPUTED DESTINATION ADDRESS SO THAT THIS
;CODE CAN BE ASSEMBLED IN LINE WITH THE MAIN 64 CODE BUT WILL HAVE
;THE CORRECT ADDRESS WHEN THE CODE IS IN THE DISK BUFFERS.
;================================================================
;
DCODE  LDA PB15                 ;CLEAR THE CLOCK AND DATA LINES TO START
       AND #$FF-DOUT15-COUT15
       STA PB15
;
;
;=================================================================
;THIS IS THE MAIN LOOP THAT THE DRIVE CODE SITS IN.  IT WAITS FOR
;THE 64 TO SEND A COMMAND BYTE AND CALLS THE CORRECT ROUTINE.
;
;COMMAND BYTES ARE AS FOLLOWS:-
;
;0     TURN OFF AND RETURN CONTROL TO THE DOS
;1     DO A SEEK AND RETURN THE STATUS TO THE 64
;2     EXECUTE THE DIRECTORY SEARCH AND SEND ROUTINE
;3     EXECUTE THE BURST LOAD FROM A GIVEN START TRACK AND SECTOR
;=================================================================
;
CMDLP  JSR IBYT15-DCODE+BUF3    ;GET A COMMAND FROM THE 64
       JSR DOJMP-DCODE+BUF3     ;CALL THE CORRECT ROUTINE
       JMP CMDLP-DCODE+BUF3     ;AND GET ANOTHER COMMAND.
;
DOJMP  CMP #1            ;DOES THE 64 WANT TO DO A SEEK ON THE DISK ?
       BEQ DOSEEK        ;YES
       CMP #2            ;IS THIS A DIRECTORY COMMAND ?
       BEQ DODIR         ;YES
       CMP #3            ;IS IT A BURST LOAD COMMAND ?
       BEQ BRSTLD        ;YES
       PLA               ;NO, ANY OTHER VALUE RETURNS TO DOS
       PLA               ;BY SCRAPPING RETURN ADDRESS TO CMDLP
       RTS               ;AND RETURNING TO CALLER OF THIS CODE
;
;
;================================================================
;THIS CODE JUST DOES A SEEK ON TRACK 18 SECTOR 0 AND RETURNS THE
;ERROR CODE TO THE 64.  USED TO VERIFY THAT A DISK IS IN THE DRIVE
;================================================================
;
DOSEEK LDA #18      ;SET UP THE TRACK AND SECTOR FOR THE SEEK
       STA HDRS
       LDA #0
       STA HDRS+1
       LDA #SEEK
       STA JOBS
;
LL5    LDA JOBS                ;WAIT FOR THE SEEK TO FINISH
       BMI LL5                 ;NOT DONE YET
       JMP OBYT15-DCODE+BUF3   ;FINISH BY SENDING STATUS TO THE 64
;
;
;==================================================================
;CALL THE DIRECTORY READ ROUTINE WITH A JUMP, (BRANCH IS TOO FAR)
;==================================================================
;
DODIR  JMP BDIR-DCODE+BUF3
;
;==================================================================
;CALL THE BURST LOADING ROUTINE WITH A JUMP, (BRANCH IS TOO FAR)
;==================================================================
;
BRSTLD JMP FLOAD-DCODE+BUF3
;
;====================================================================
;THIS IS THE FRAME HANDSHAKE THAT STARTS TRANSMISSION OF 8 BITS
;IN ANY DIRECTION.  �T IS CALLED BY THE INPUT AND OUTPUT ROUTINES TO
;PUT THE 64 AND 1541 CODE IN SYNCH FOR A FASTER HANDSHAKE ON BITS
;====================================================================
;
FRAM15 LDA PB15         ;WAIT FOR CLKIN = 1 (64 IS READY FOR THE BYTE)
       TAY              ;SAVE THE PORT VALUE FOR LATER
       AND #CIN15
       BEQ FRAM15       ;64 ISN'T READY YET
       TYA              ;ACKNOWLEDGE 64'S READY SIGNAL WITH DATOUT=1
       ORA #DOUT15      ;64 WILL SEE THIS AS DATIN = 0
       STA PB15
       SEI              ;DISK CAN'T HAVE ANY IRQ'S NOW
;
FR0015 LDA PB15         ;NOW WAIT FOR THE 64 TO ACKNOWLEDGE AGAIN
       TAY              ;BY RESETTING CLKIN TO 0
       AND #CIN15
       BNE FR0015       ;HASN'T ANSWERED US YET
       TYA              ;FINALISE FRAME HANDSHAKE BY SETTING DATOUT=0
       AND #$FF-DOUT15  ;64 WILL SEE THIS AS DATIN=1
       STA PB15
       RTS              ;NOW GO AND DO THE BIT HANDSHAKE
;
;
;===================================================================
;THIS ROUTINE SENDS A BYTE OF DATA TO THE 64 USING A FAST HANDSHAKE
;ENTER WITH .A=BYTE TO SEND.
;===================================================================
;
OBYT15 STA BYTE15       ;STORE THE BYTE BEING SENT
       TXA              ;SAVE THE .X REGISTER
       PHA
       TYA
       PHA                    ;SAVE THE .Y REGISTER
       LDX #$08               ;KEEP A BIT COUNTER
       JSR FRAM15-DCODE+BUF3  ;GO DO A FRAME HANDSHAKE
;
;THE FOLLOWING HANDSHAKE IS PERFORMED FOR EACH BIT THAT IS SENT TO THE 64
;
OB1015 LDA PB15         ;WAIT FOR CLKIN=1 (64 IS READY FOR THE BIT)
       TAY              ;SAVE PORT VALUE FOR LATER
       AND #CIN15
       BEQ OB1015       ;64 ISN'T READY YET
;
       TYA              ;64 EXPECTS THE BIT TO BE VALID VERY SOON!
       LSR BYTE15       ;DATOUT IS 0 AT THE MOMENT SO SEE WHAT TO SEND
       BCS OB2015       ;IF A 1 IS NEEDED, SEND 0 TO COMPLEMENT DATA
       ORA #DOUT15      ;A 0 IS NEEDED SO SEND A 1 TO COMPLEMENT THE DATA
OB2015 STA PB15         ;PRESENT THE 64 WITH IT'S DATA
;
OB3015 LDA PB15         ;WAIT FOR THE 64 TO SAY IT HAS THE DATA
       TAY              ;IT WILL SET CLKIN = 0 WHEN IT HAS
       AND #CIN15
       BNE OB3015       ;64 DIDN'T PICK IT UP YET
       TYA              ;SET DATOUT TO A KNOWN STATE AGAIN (0)
       AND #$FF-DOUT15
       STA PB15
       DEX              ;ARE THERE ANY MORE BITS TO SEND ?
       BNE OB1015       ;YES, SO START THE BIT HANDSHAKE AGAIN
       CLI              ;OK, ALL BITS SENT SO ALLOW IRQ'S AGAIN
       PLA              ;RESTORE .Y REGISTER
       TAY
       PLA              ;RESTORE .X REGISTER
       TAX
       RTS              ;BYE BYE
;
;
;===================================================================
;THIS ROUTINE GETS A BYTE OF DATA FROM THE 64 USING A FAST HANDSHAKE
;ENTER WITH .A=BYTE TO SEND.
;===================================================================
;
IBYT15 LDA #$01               ;PUT A FLAG BIT INTO THE DATA BYTE
       STA BYTE15             ;SO WE KNOW WHEN 8 BITS HAVE BEEN SENT
       TXA                    ;SAVE THE .X REGISTER
       PHA
       TYA                    ;SAVE THE .Y REGISTER
       PHA
       JSR FRAM15-DCODE+BUF3  ;GO DO A FRAME HANDSHAKE
;
;THE FOLLOWING HANDSHAKE IS PERFORMED FOR EACH BIT THAT IS SENT BY THE 64
;
IB1015 LDA PB15    ;WAIT FOR CLKIN=1 (64 HAS SENT THE DATA BIT)
       TAY         ;SAVE PORT VALUE FOR LATER
       AND #CIN15
       BEQ IB1015  ;64 HASN'T SET IT YET
       TYA         ;OK, GET THE BIT BACK
       LSR A       ;MOVE IT TO THE CARRY
       ROL BYTE15  ;AND THEN INTO THE DATA BYTE
;
IB2015 LDA PB15    ;WAIT FOR THE 64 TO SET CLKIN TO 0 AGAIN
       AND #CIN15  ;NOTE, ANY FLAG BIT IN THE CARRY IS PRESERVED
       BNE IB2015  ;NOT DONE IT YET
       BCC IB1015  ;FLAG BIT DIDN'T DROP OFF YET SO GET ANOTHER BIT
       CLI         ;OK, ALL BITS FETCHED SO ALLOW IRQ'S AGAIN
       PLA         ;RESTORE .Y
       TAY
       PLA         ;RESTORE .X
       TAX
       LDA BYTE15  ;AND RETURN RECEIVED BYTE IN .A
       RTS
;
;
;===================================================================
;THESE ARE SUBROUTINES FOR STARTING READS ON CHAINED BLOCKS.
;CALL RFBLOK TO READ THE FIRST BLOCK INTO BUF1 AND CALL RNBLOK TO
;READ THE NEXT BLOCK INTO THE BUFFER THAT IS NOT BEING USED.  RNBLOK
;TAKES ITS ARGUMENTS FROM THE CURRENT ACTIVE BUFFER, IF THE FIRST
;BYTE IS 0 THEN THERE IS NO BLOCK TO CHAIN TO AND NOTHING IS DONE
;===================================================================
;
;CALL RFBLOK WITH .X=TRACK AND .Y=SECTOR TO BE READ
;
RFBLOK STX BUF2      ;STORE THE FIRST TRACK WE WANT TO READ
       STY BUF2+1    ;AND THE FIRST SECTOR
       LDA #1        ;FOOL RNBLOK INTO THINKING BUF2 IS ACTIVE
       STA JOBOFF    ;DROP THROUGH TO THE READ NEXT BLOCK ROUTINE
;
;THIS ROUTINE STARTS A BLOCK READ INTO BUF1 OR BUF2 DEPENDING ON JOBOFF
;
RNBLOK LDA JOBOFF    ;JOBOFF TELLS US WHERE THE TRACK AND SECTOR ARE
       STA WRKOFF    ;SAVE CURRENT VALUE AS A WORK POINTER
       EOR #1        ;MAKE THE OTHER BUFFER THE ACTIVE ONE
       STA JOBOFF    ;JOBOFF NOW POINTS TO BUFFER WHERE BLOCK WILL GO
       CLC           ;USE OLD VALUE OF JOBOFF AS PLACE TO GET T/S
       LDA WRKOFF
       ADC #>BUF1    ;USE THE RESULT TO MODIFY SOME CODE
       STA GT-DCODE+BUF3+2
       STA GS-DCODE+BUF3+2
       LDA JOBOFF    ;COMPUTE INDEX TO THE CORRECT HEADER
       ASL A
       TAX           ;TO SET UP TRACK AND SECTOR FOR READING
GS     LDA BUF1+1    ;THIS GETS MODIFIED - FETCH THE SECTOR
       STA HDRS+1,X
GT     LDA BUF1      ;THIS GETS MODIFIED TOO - FETCH THE TRACK
       STA HDRS,X
       BEQ RNBL00    ;TRACK WAS 0, SO NOTHING ELSE TO READ
       LDX JOBOFF    ;NOW START A READ INTO THE CORRECT BUFFER
       LDA #READ
       STA JOBS,X
RNBL00 RTS           ;ALL DONE
;
;
;=============================================================
;THIS ROUTINE READS THE NAME OF THE DISK AND SENDS ALL
;PROGRAM NAMES TO THE 64.  �HE SEND FORMAT IS AS FOLLOWS:
;
;1     THE ERROR CODE WHEN READING 18,0 - EXIT IF <> 1
;2     16 BYTES THAT MAKE UP THE NAME OF THE DISK
;
;3     TRACK AND SECTOR WHERE FILE STARTS ON THE DISK
;      0 BYTE FOR TRACK MEANS DIRECTORY READ IS COMPLETE, END.
;4     SEND THE NAME OF THE PROGRAM (16 BYTES)
;5     GO BACK TO STEP 3
;=============================================================
;
BDIR   LDX #18               ;READ 18,0 TO FIND THE DISK NAME
       LDY #0
       JSR RFBLOK-DCODE+BUF3
;
BDIR00 JSR SNEXT-DCODE+BUF3  ;BUILD POINTER AND START NEXT READ
       PHA                   ;SAVE THE CONTROLLER RETURN CODE
       JSR OBYT15-DCODE+BUF3 ;SEND THE CODE TO THE 64
       PLA                   ;GET THE CODE BACK
       CMP #1                ;WAS OUR ACTIVE BLOCK READ OK ?
       BEQ BDIR05            ;YES SO PROCEED TO READ THE DISK NAME
       RTS                   ;ERROR, JUST RETURN TO MAIN COMMAND LOOP
;
BDIR05 LDY #144              ;INDEX TO THE DISK NAME
BDIR10 LDA (BUFPTR),Y        ;GET NEXT CHARACTER OF THE DISK NAME
       JSR OBYT15-DCODE+BUF3 ;SEND IT TO THE 64
       INY
       CPY #160              ;HAVE WE SENT THE WHOLE NAME ?
       BNE BDIR10            ;NOPE, NOT YET
;
;OK, THE DISK NAME HAS BEEN SENT SO FIND ALL PROGRAM TYPES AND SEND
;THE NAMES AND START T/S TO THE 64 FOR USER SELECTION
;
BDIR20 JSR SNEXT-DCODE+BUF3  ;START THE NEXT BLOCK READING
       CMP #1                ;DID THE CURRENT BLOCK READ OK ?
       BEQ BDIR25            ;YES
       LDA #$00              ;ERROR!, SEND 64 A ZERO BYTE AND RETURN
       BEQ BDIR80            ;BRA
;
BDIR25 LDA #$02         ;POINT TO THE FIRST DIRECTORY ENTRY
       STA LPB15        ;KEEP THE INDEX
BDIR30 LDY LPB15        ;GET CURRENT INDEX TO THE DIRECTORY ENTRIES
       INY              ;POINT TO ITS TRACK/SECTOR FIELD
       LDA (BUFPTR),Y   ;IF TRACK = 0 THEN DIRECTORY DONE
       BEQ BDIR80       ;YEP, SEND A ZERO BYTE AND EXIT
       DEY              ;OK, A FILE IS THERE SO CHECK IF IT'S A PROG
       LDA (BUFPTR),Y   ;GET THE TYPE BYTE
       CMP #$82         ;IS IT A CLOSED PROGRAM FILE ?
       BNE BDIR40       ;NOPE, GO TO THE NEXT ENTRY
       LDA #18          ;KEEP A BYTE COUNTER
       STA BCNT15
;
BDIR35 INY              ;OK, SEND THE NEXT 18 BYTES (T/S,NAME)
       LDA (BUFPTR),Y
       JSR OBYT15-DCODE+BUF3
       DEC BCNT15       ;HAVE WE SENT IT ALL ?
       BNE BDIR35       ;NOPE
;
BDIR40 LDA LPB15        ;POINT TO THE NEXT DIRECTORY ENTRY
       CLC
       ADC #32
       STA LPB15
       BCC BDIR30       ;HAVEN'T FINISHED YET
;
       LDY #$00         ;OK, FINISHED THIS BLOCK, SEE IF THERE'S ANOTHER
       LDA (BUFPTR),Y   ;IF TRACK LINK <> 0 THEN THERE IS
       BNE BDIR20       ;START ANOTHER READ AND SEND NEXT BUFFER
;
BDIR80 JMP OBYT15-DCODE+BUF3 ;SEND A ZERO BYTE TO FINISH
;
;
;=====================================================================
;THIS ROUTINE WAITS FOR THE JOB TO FINISH ON THE BUFFER WE ARE GOING
;TO READ, AND THEN STARTS ANOTHER READ ON THE OTHER BUFFER (BUF1 OR 2)
;=====================================================================
;
SNEXT  LDA #$00               ;BUILD POINTER TO THE CURRENT BUFFER
       STA BUFPTR
       LDA JOBOFF
       CLC
       ADC #>BUF1
       STA BUFPTR+1
       LDX JOBOFF             ;WAIT FOR THE CURRENT JOB TO BE FINISHED
SNEX00 LDA JOBS,X
       BMI SNEX00
       PHA                    ;SAVE THE RETURNED ERROR CODE
       JSR RNBLOK-DCODE+BUF3  ;START A READ ON THE NEXT BLOCK
       PLA                    ;GET BACK THE ERROR CODE
       RTS                    ;ALL DONE
;
;=============================================================
;THIS ROUTINE DOES THE BURST LOAD OF A PROGRAM FILE, THE 64
;SENDS THE START TRACK AND SECTOR USING THE NORMAL FAST I/O
;ROUTINES AND ALSO RECEIVES THE START ADDRESS OF THE PROGRAM
;IN THE SAME MANNER
;=============================================================
;
FLOAD  JSR IBYT15-DCODE+BUF3  ;GET THE START TRACK
       TAX
       JSR IBYT15-DCODE+BUF3  ;GET THE START SECTOR
       TAY
       JSR RFBLOK-DCODE+BUF3   ;READ THE FIRST BLOCK INTO BUF1
       JSR SNEXT-DCODE+BUF3    ;AND START THE SECOND BLOCK READING
       LDA BUF1+2              ;SEND THE START ADDRESS OF THE CODE
       JSR OBYT15-DCODE+BUF3
       LDA BUF1+3
       JSR OBYT15-DCODE+BUF3
;
       LDY #4                  ;WHERE TO START THE SEND FROM
       LDX #252                ;NUMBER OF BYTES BEING SENT
       BNE FLO20               ;SEND THE BLOCK STARTING AT .Y INDEX
;
;THIS IS THE MAIN LOOP THAT SENDS A BLOCK OF CODE TO THE 64
;
FLO10  LDY #$00              ;ASSUME ITS A FULL BLOCK
       LDX #254
       LDA (BUFPTR),Y        ;IF TRACK = 0 THEN IT ISNT
       BNE FLO15             ;EVERYTHING IS OK
       INY                   ;POINT TO SECTOR FIELD FOR NMBER OF BYTES TO SEND
       LDA (BUFPTR),Y
       TAX
FLO15  LDY #$02
FLO20  TXA                   ;TELL 64 HOW MANY BYTES
       JSR FSTB15-DCODE+BUF3
;
FLO30  LDA (BUFPTR),Y        ;NOW SEND ALL THE BYTES OF DATA
       JSR FSTB15-DCODE+BUF3
       INY
       DEX
       BNE FLO30            ;MORE TO SEND
;
       LDY #$00             ;SEE IF THERE IS ANOTHER BLOCK TO DO
       LDA (BUFPTR),Y
       BEQ FLO50            ;NOPE, ALL DONE SO FINISH BY SENDING 0
       JSR SNEXT-DCODE+BUF3 ;START THE NEXT BLOCK READING
       CMP #1               ;DID THE NEW BLOCK READ OK ?
       BEQ FLO10            ;YES SO GET ANOTHER BLOCK
;
;GETS TO HERE WHEN THE WHOLE FILE HAS BEEN SENT TO THE 64 OR AN ERROR
;WAS ENCOUNTERED WHILE READING PROGRAM BLOCKS
;
FLO50  PLA              ;SCRAP RETURN ADDRESS TO MAIN COMMAND LOOP
       PLA
       LDA #$00         ;SEND 64 A ZERO BYTE TO TERMINATE
;
;
;=================================================================
;THIS IS THE CODE TO DO A FAST HANDSHAKE TO THE 64 WITH SCREEN OFF
;=================================================================
;
FSTB15 STA BYTE15       ;SAVE THE BYTE TO BE SENT
       TXA              ;SAVE .X
       PHA
       LDX #$08         ;KEEP A COUNT OF BITS TO BE SENT
       SEI              ;AND DON'T ALLOW INTERRUPTS NOW
;
FS1500 LDA PB15         ;GET CURRENT VALUE OF THE PORT
       ASL BYTE15       ;MOVE THE NEXT DATA BIT INTO THE CARRY
       BCS FS1510       ;NOTHING TO DO IF BIT IS SET (BUS COMPLEMENTS)
       ORA #DOUT15      ;SEND A 1 BIT IF 0 WAS REQUIRED
       STA PB15
FS1510 ORA #COUT15      ;SET DATOUT = 1 TO SAY DATA AVAILABLE
       STA PB15
       NOP              ;GIVE THE 64 TIME TO FIND THE DATA
       NOP              ;***** THIS RUNS VERY CLOSE TO THE EDGE....
       NOP              ;***** ONE MORE NOP DOESN'T SLOW IT DOWN MUCH
;
       AND #$FF-DOUT15-COUT15   ;RETURN PORT TO KNOWN STATE
       STA PB15
       DEX                      ;ANY MORE BITS ?
       BNE FS1500               ;YES
       CLI                      ;IRQS ARE OK NOW
       PLA                      ;RESTORE .X
       TAX
       RTS                      ;ALL DONE
;
;
DCEND .BYTE 0 ;END OF DISK DRIVE CODE
DCLEN = DCEND-DCODE
;
;
;
;PUT"0:C64CODE.SRC"
;==========================================================
;THESE ARE THE FAST I/O ROUTINES FOR THE 64 THAT WORK WITH
;THE SCREEN AND INTERRUPTS TURNED ON.
;NO COMPUTED OFFSETS FOR THE JSR ADDRESSES ARE REQUIRED
;BECAUSE THIS CODE IS ASSEMBLED WHERE IT WILL BE EXECUTED
;===========================================================
;
;
;=================================================================
;THIS ROUTINE FETCHES A BYTE FROM THE DRIVE USING A FAST HANDSHAKE
;=================================================================
;
IBYT64 LDA #$80         ;PUT A FLAG BIT INTO THE DATA BYTE WE WILL FETCH
       STA BYTE64
       TXA              ;SAVE .X
       PHA
       TYA              ;SAVE .Y
       PHA
      JSR FRAM64        ;GO DO THE BYTE HANDSHAKE
;
;THIS SECTION LOOPS AROUND A QUICK HANDSHAKE TO FETCH 8 BITS OF DATA
;
IB1064 LDA PB64         ;SET CLKOUT =�1 TO SAY WE WANT A BIT NOW
       ORA #COUT64
       STA PB64
;
       LDX #$07         ;GIVE THE DISK TIME TO PRESENT THE DATA
IB2064 DEX              ;WITH THIS SMALL DELAY LOOP
       BNE IB2064     
;
       LDA PB64         ;OK DISK! DATA SHOULD BE VALID BY NOW
       AND #$FF-COUT64  ;TELL THE DISK WE FETCHED IT BY SETTING CLKOUT=0
       STA PB64
       ASL A            ;MOVE THE DATA BIT INTO THE DATA BYTE
       ROR BYTE64
       BCC IB1064       ;FLAG BIT DIDN'T DROP OUT YET SO GET ANOTHER BIT
;
       PLA          ;RESTORE .Y
       TAY
       PLA          ;RESTORE .X
       TAX
       LDA BYTE64   ;FETCH THE ASSEMBLED BYTE OF DATA
       RTS ;BYE BYE
;
;
;==================================================================
;THIS ROUTINE SENDS A BYTE OF DATA TO THE DISK USING THE FAST SHAKE
;THE HANDSHAKE IS DIFFERENT TO THE GET BYTE ROUTINE BECAUSE THE 64
;CAN CALL THE SHOTS AND DEPEND ON THE 1541 TO BE WAITING FOR DATA
;AT ANY GIVEN TIME.
;==================================================================
;
OBYT64 STA BYTE64   ;SAVE THE DATA BYTE TO BE SENT
       TXA ;SAVE .X
       PHA
       TYA ;SAVE .Y
       PHA
       LDX #$08     ;KEEP A COUNT OF THE BITS TO SEND
       JSR FRAM64   ;DO THE FRAME HANDSHAKE FOR THIS BYTE
;
;THIS IS THE LOOP TO HANDSHAKE EACH BIT OVER TO THE 1541
;
OB1064 LDA PB64     ;GET THE CURRENT VALUE OF THE PORT
       ASL BYTE64   ;MOVE THE NEXT DATA BIT INTO THE CARRY
       BCC OB2064   ;NOTHING TO DO, THE BIT IS CLEAR
       ORA #DOUT64  ;IT'S A 1 BIT THAT NEEDS TO BE SENT
       STA PB64     ;THIS IS A FIX (1526 DROPS BITS IF 2 ARE CHANGED)
OB2064 ORA #COUT64  ;SET CLKOUT TO 1 TO SAY DATA IS THERE
       STA PB64
;
       NOP          ;GIVE THE DRIVE TIME TO FIND THE BIT
       NOP
       NOP
       NOP
;
       AND #$FF-DOUT64-COUT64
       STA PB64     ;SET THE PORT BACK TO A KNOWN STATE
       DEX          ;ARE THERE ANY MORE BITS TO SEND
       BNE OB1064   ;YES
       PLA          ;RESTORE .Y
       TAY
       PLA          ;RESTORE .X
       TAX
       RTS          ;BYE BYE
;==============================================================
;THIS IS THE REAL FAST ZAP LOAD ROUTINE THAT FETCHES A PROGRAM
;FROM THE DRIVE WITH A VERY FAST HANDSHAKE.  �HE 64 HAS TO BE
;WATCHING THE BUS AT ALL TIMES, THEREFORE IT MUST HAVE THE
;VIDEO CHIP TURNED OFF AND INTERRUPTS DISABLED.
;
;THIS CODE IS LOADED INTO THE SCREEN AT $0402 SO THAT IT CANNOT
;BE KILLED BY PROGRAMS LOADING OVER IT (MOST CASES)
;==============================================================
;
SCTOP  LDA $0400   ;BUILD A POINTER TO THE CODE
       STA VARTAB  ;USE VARTAB SO BASIC PROGS KNOW WHERE THEY FINISH
       LDA $0401
       STA VARTAB+1
;
SCT00  JSR FSTB64-SCTOP+$0402    ;GO GET A SUPER FAST BYTE
       TAX         ;THIS IS THE NUMBER OF BYTES BEING SENT
       BEQ GOTPRG  ;0 MEANS WE ARE ALL DONE
       PHA         ;SAVE FOR LATER
       LDY #$00
;
SCT10  JSR FSTB64-SCTOP+$0402  ;GET A BYTE OF THE CODE
       STA (VARTAB),Y          ;STORE IT IN MEMORY
       INY
       DEX                     ;ANY MORE BYTES IN THIS BLOCK ?
       BNE SCT10               ;YES
;
       CLC                     ;UPDATE THE POINTER
       PLA
       ADC VARTAB
       STA VARTAB
       BCC SCT00
       INC VARTAB+1
       BNE SCT00
;
;=============================================================
;GETS TO HERE WHEN THE CODE HAS BEEN LOADED TO SEE WHAT TO DO
;=============================================================
;
GOTPRG LDA 53265
       ORA #16               ;TURN THE SCREEN BACK ON
       STA 53265
       CLI                   ;LET INTERRUPTS FLY NOW
       LDA $0401             ;WAS THIS BASIC
       CMP #8                ;IF SA = $0801 THEN YES
       BNE SYSPRG            ;HI BYTE NOT RIGHT
       LDA $0400
       CMP #1
       BNE SYSPRG
;
       JSR $A659       ;RUNC, IT WAS BASIC SO RUN IT
       JMP $A7AE       ;NEWSTT
;
SYSPRG JMP ($0400)
;
;==============================================================
;THIS ROUTINE DOES A FAST BYTE HANDSHAKE WITH THE SCREEN OFF
;==============================================================
;
FSTB64 TYA            ;SAVE .Y
       PHA
       LDA #$01       ;PUT A FLAG BIT IN THE DATA BYTE
       STA BYTE64
;
FS6400 LDA PB64       ;WAIT FOR CLKIN = 0 (DISK SENT DATA)
       TAY
       AND #CIN64
       BNE FS6400     ;OK, BIT ISN'T CLEAR YET
;
       TYA
       ASL A          ;OK, WE HAVE THE DATA BIT
       ROL BYTE64     ;MOVE IT INTO THE DATA BYTE
       BCC FS6400     ;MORE BITS TO FETCH
;
       PLA            ;RESTORE .Y
       TAY
       LDA BYTE64     ;GET BACK THE DATA BYTE
       RTS            ;ALL DONE
;
;
;==============================================================
;THIS IS THE FRAME HANDSHAKE THAT STARTS TRANSMISSION OF 8 BITS
;IN ANY DIRECTION.  IT IS CALLED BY THE 64'S FAST INPUT/OUTPUT
;ROUTINES TO MAKE SURE THE CODE IN BOTH THE DRIVE AND THE 64 IS
;IN SYNCH. IT HAS BEEN POSITIONED HERE SO THAT IT IS MOVED TO
;THE SCREEN RAM ALONG WITH THE SUPER FAST I/O ROUTINE.
;==============================================================
;
FRAM64 LDA PB64      ;SET CLKOUT = 1 TO START THE HANDSHAKE
       ORA #COUT64
       STA PB64
;
FR0064 LDA PB64      ;WAIT FOR THE DRIVE TO SET DATIN = 0
       TAY           ;SAVE THE CURRENT PORT VALUE FOR LATER
       AND #DIN64
       BNE FR0064       ;DRIVE DIDN'T RESPOND YET
;
       TYA              ;SET CLKOUT =�0 TO SET LINES TO 0 STATE
       AND #$FF-COUT64  ;AND LET THE DRIVE KNOW WE ARE READY
       STA PB64
FR1064 LDA PB64         ;FINALLY WAIT FOR THE DRIVE TO SET DATIN=1
       AND #DIN64
       BEQ FR1064       ;DRIVE DIDN'T RESPOND YET
       RTS              ;OK, FRAME HANDSHAKE IS DONE
;
;
SCEND .BYTE 0
;
;============================================================
;THIS SECTION DISPLAYS THE MENU AND GETS THE USERS SELECTION
;FROM THAT MENU.  �PRITES ARE DOWNLOADED TO $3000
;============================================================
;
POSTBL .BYTE 24,52,48,52,72,52
;
MENU   LDA #0      ;SCREEN BACKGROUND BLACK
       STA 53281
       LDA #13     ;BORDER LIGHT GREEN
       STA 53280
       LDA #147
       JSR CHROUT  ;CLEAR THE SCREEN
;
       LDX #0      ;START AT LINE 0
       LDY #3      ;AND DO 3 REVERSED LINES
       LDA #13     ;IN LIGHT GREEN ON THE SCREEN
       JSR DOLINE
;
       LDX #4      ;NOW START AT LINE 4
       LDY #3      ;AND DO 3 REVERSED LINES
       LDA #1      ;IN WHITE
       JSR DOLINE
;
;******* THIS CODE MAY BE SCRAPPED IF PROGRAM GETS TOO BIG ******
;
       LDX #$00     ;INDEX INTO SPRITE DATA
MENU10 LDA TITLEZ,X ;DOWNLOAD SPRITE DATA TO $3000
       STA $3000,X
       INX
       CPX #192     ;HAVE WE DOWNLOADED ALL OF THE DATA ?
       BNE MENU10   ;NOPE, NOT YET
;
MENU20 LDX #$03     ;COLOR ALL THREE SPRITES
MENU25 TXA          ;IN WHITE,RED AND CYAN
       STA $D026,X
       DEX
       BNE MENU25
;
       STX $D025    ;MOB MULTICOLOR 0 = BLACK
       STX $D017    ;NO Y EXPANSION
       STX $D01D    ;NO X EXPANSION
;
       LDX #192     ;BUILD POINTERS TO EACH SPRITE IN MEMORY
       STX 2040
       INX
       STX 2041
       INX
       STX 2042
;
       LDX #$05     ;NOW GIVE EACH SPRITE ITS X,Y POSITION
MENU35 LDA POSTBL,X
       STA $D000,X
       DEX
       BPL MENU35
;
       LDX #$07     ;TURN ON THE 3 USED SPRITES
       STX $D01C    ;MULTICOLOR
       STX $D015    ;ENABLE
;
;******* THIS CODE MAY BE SCRAPPED IF PROGRAM GETS TOO BIG ******
;
       LDA #0       ;PUT MESSAGE 0 ON THE SCREEN
       JSR MESAGE   ;'1541 FAST LOAD BY STEVE BEATS'
;
;===================================================================
;MENU SCREEN IS ALL SET UP NOW, SO CHECK THAT THERE IS A DISK IN THE
;DRIVE AND ASK THE USER FOR ONE IF THERE ISN'T.
;===================================================================
;
MENU40 LDA #$01     ;TELL THE DRIVE TO DO A SEEK
       JSR OBYT64
       JSR IBYT64   ;GET THE ERROR RETURN
       CMP #1       ;IS THERE A DISK IN THERE
       BEQ MENU45   ;YES
;
       LDA #1       ;NOPE, SO ASK THE GUY FOR A DISK
       JSR MESAGE
       JMP MENU40   ;AND KEEP SEEKING UNTIL A DISK IS THERE
;
;
MENU45 LDA #$01     ;DO ONE MORE SEEK BECAUSE REMOVING A DISK...
       JSR OBYT64   ;CAN MAKE SEEK RETURN A 1 WHEN NO DISK IS THERE
       JSR IBYT64
       CMP #1
       BNE MENU40   ;SORRY, WE SHOULDN'T HAVE GOT HERE YET
       LDA #2       ;PUT UP THE DISK NAME MESSAGE
       JSR MESAGE
;
       LDA #2       ;TELL DRIVE TO DO A DIRECTORY SEND
       JSR OBYT64
       JSR IBYT64   ;GET THE STATUS CODE FOR THE 18,0 READ
       CMP #1       ;IF 1 THEN OK TO CARRY ON AND GET THE NAME
       BEQ MENU50   ;NO PROBLEMS
;
       LDA #$00     ;****** ERROR FOR NOW *******
       STA $D015
       JMP OBYT64   ;TURN OFF THE DRIVE CODE
;
MENU50 LDX #5       ;BUILD A POINTER TO THE DISK NAME FIELD
       JSR SETPTR
       LDY #22      ;WHERE TO STORE THE STUFF
       LDX #16      ;WE ARE GOING TO GET 16 BYTES NOW
;
MENU55 JSR IBYT64   ;GET A BYTE FROM THE DRIVE
       AND #63      ;CONVERT CHARACTER TO REVERSE SCREEN CODE
       ORA #128
       STA (VPTR),Y ;STORE THE BYTE ON THE SCREEN
       INY
       DEX          ;HAVE WE FETCHED ALL BYTES YET ?
       BNE MENU55   ;NOPE
;
;======================================================================
;OK, WE NOW HAVE THE DISK NAME SO FETCH TRACK,SECTOR,NAME FOR EACH FILE
;THAT THE DRIVE SENDS US.  � TRACK NUMBER OF ZERO MEANS ALL FILES DONE
;======================================================================
;
       JSR SETFP    ;BUILD A POINTER TO DIRECTORY STORAGE AREA
       LDA #0       ;KEEP A COUNT OF PROGRAMS
       STA PRGCNT
;
MENU60 LDY #$00     ;SET INDEX INTO STORAGE
       JSR IBYT64   ;GET THE TRACK NUMBER
       BEQ GOTDIR   ;0, SO ALL IS DONE
       STA (PTR),Y  ;REMEMBER THE TRACK NUMBER
       INY
       JSR IBYT64   ;FETCH THE SECTOR NUMBER AND STORE IT
       STA (PTR),Y
       INY          ;NOW POINT TO THE NAME STORAGE
MENU65 JSR IBYT64   ;FETCH A BYTE OF THE FILENAME
       AND #63      ;CONVERT TO DISPLAY CODE
       STA (PTR),Y  ;AND STORE IN MEMORY
       INY
       CPY #18
       BNE MENU65
       INC PRGCNT   ;UPDATE NUMBER OF PROGRAMS THERE
       JSR NXTFIL   ;MOVE POINTER ON BY 18 BYTES
       JMP MENU60   ;BRA
;
;==================================================================
;ALL THE DIRECTORY ENTRIES ARE IN MEMORY NOW, SO SET UP THE DISPLAY
;AND ALLOW THE USER TO CURSOR AROUND TO SELECT A FILE FOR LOADING
;==================================================================
;
GOTDIR LDA PRGCNT  ;WERE THERE ANY FILES AT ALL ?
       BNE GOTD00  ;YES SO LET USER CHOOSE
;
       LDX #8      ;ERROR, NO PROGRAMS ON THE DISK
       LDY #5      ;DISPLAY THIS IN A 5 LINE REVERSE BOX
       LDA #1
       JSR DOLINE
;
       LDA #4      ;USE MESSAGES 4 AND 5
       JSR MESAGE
       LDA #5
       JSR MESAGE
;
NOPROG JSR GETIN   ;WAIT FOR STOP OR RETURN
       CMP #13     ;WAS IT RETURN TO CHANGE DISKS ?
       BNE NOPR00  ;NOPE
       JMP MENU    ;REDRAW THE MENU AND START AGAIN
;
NOPR00 CMP #3      ;WAS IT STOP
       BNE NOPROG  ;NOPE
       JMP ($FFFC) ;RESET TO CLEAN UP
;
GOTD00 LDA #$00    ;SET UP TO DISPLAY FILES FOR THE FIRST TIME
       STA FPRG    ;FIRST PROGRAM ON THE SCREEN
       STA CURPRG  ;PROGRAM NUMBER THE CURSOR IS OVER
       STA CURLIN  ;CURRENT LINE WHERE THE CURSOR IS
;
       LDX #21     ;PUT A 3 LINE DEEP REVERSE BAR AT SCREEN BOTTOM
       LDY #3
       LDA #1      ;MAKE IT WHITE
       JSR DOLINE
       LDA #3      ;DISPLAY THE INSTRUCTIONS ON IT
       JSR MESAGE
;
DSPM00 JSR DSPFIL  ;DISPLAY AS MANY FILES AS POSSIBLE
DSPM10 JSR GETIN   ;GO GET A KEY FROM THE USER
       BEQ DSPM10
       CMP #3      ;WAS IT STOP
       BNE DSPM15  ;NOPE
       JMP MENU    ;START OVER IF STOP WAS PRESSED
;
DSPM15 CMP #17     ;WAS IT CURSOR DOWN ?
       BNE DSPM20  ;NOPE
       LDX CURPRG  ;FIRST CHECK IF WE WOULD GO PAST THE END BY MOVING
       INX
       INX
       CPX PRGCNT
       BCS DSPM10  ;IT WAS SO DON'T DO ANYTHING
       STX CURPRG  ;STILL OK
DSPM16 LDX CURLIN  ;MOVE DOWN A LINE
       INX
       CPX #12     ;UNLESS WE WERE ON THE LAST ONE
       BNE DSPM17  ;WE AREN'T SO JUST INCREMENT AND CARRY ON
       INC FPRG    ;TIME TO SCROLL SO FIRST PROG =�FIRST+2
       INC FPRG
       DEX         ;CORRECT .X BECAUSE IT WENT TOO FAR
DSPM17 STX CURLIN
       JMP DSPM00  ;REDISPLAY THE SCREEN FULL OF FILES
;
DSPM20 CMP #145    ; WAS IT CURSOR UP ?
       BNE DSPM30  ;NOPE
       LDX CURPRG  ;ONLY MOVE UP IF PROG # IS 2 OR MORE
       CPX #2
       BCC DSPM10  ;NOTHING TO DO WE ARE ON THE TOP LINE
       DEX         ;MOVE BACK BY 2
       DEX
       STX CURPRG
       LDA CURLIN  ;MOVE CURRENT LINE BACK UNLESS WE ARE ON THE TOP
       BNE DSPM25  ;ITS OK, WE ARE NOT ON THE TOP LINE
       DEC FPRG    ;FIRST = FIRST -2
       DEC FPRG
       JMP DSPM00  ;DISPLAY THE NEW FILES THAT MOVED IN
DSPM25 DEC CURLIN  ;OK TO JUST MOVE THE CURSOR UP THE SCREEN
       JMP DSPM00
;
DSPM30 CMP #29     ;WAS IT CURSOR FORWARD
       BNE DSPM40  ;NOPE
       LDA CURPRG  ;MOVE TO THE NEXT IF CURPRG<PRGCNT AND EVEN
       TAX
       INX
       CPX PRGCNT
       BEQ DSPM10  ;ALREADY AT THE MAXIMUM
       AND #$01
       BNE DSPM10  ;ALREADY IN THE SECOND COLUMN
       STX CURPRG  ;STORE THE NEW POSITION AND REDISPLAY
       JMP DSPM00
;
DSPM40 CMP #157    ;WAS IT CURSOR BACK ?
       BNE DSPM50  ;NOPE
       LDA CURPRG  ;MAKE NUMBER EVEN
       AND #$FE
       STA CURPRG
       JMP DSPM00  ;REDISPLAY THE FILES
;
DSPM50 CMP #13     ;WAS IT RETURN TO LOAD ?
       BEQ DSPM55  ;YES, SO GO LOAD THE PROGRAM FAST
       JMP DSPM10  ;NOPE, SO JUST GET ANOTHER KEY
;
;==============================================================
;GETS TO HERE WHEN THE USER HAS CHOSEN A PROGRAM FROM THE MENU
;THE MAIN LOADING CODE GETS PUT INTO SCREEN RAM AND EXECUTED
;TO LOAD IN THE PROGRAM.  DEPENDING ON START ADDRESS, THE PROGRAM
;IS EITHER RUN OR CALLED DIRECTLY.
;==============================================================
;
DSPM55 LDA #147         ;CLEAR THE SCREEN
       JSR CHROUT
       LDX #SCEND-SCTOP ;MOVE CODE INTO THE SCREEN
DSPM56 LDA SCTOP,X
       STA $0402,X      ;LEAVE ROOM TO STORE START ADDRESS
       DEX
       CPX #$FF
       BNE DSPM56
;
       SEI              ;NO INTERRUPTS NOW PLEASE
       LDA 53265        ;TURN THE SCREEN OFF
       AND #255-16
       STA 53265
       LDA #$00         ;TURN THE SPRITES OFF
       STA $D015
       STA $0801        ;MAKE THIS PROGRAM DISAPPEAR
       STA $0802
       LDA #3           ;TELL THE DRIVE TO GO TO THE BURST LOAD
       JSR OBYT64
       LDA CURPRG       ;FIND OUT WHICH PROGRAM TO LOAD
       JSR FNDPRG
       LDY #$00         ;TELL BURST LOAD WHERE TO START FROM
       LDA (PTR),Y      ;TRACK
       JSR OBYT64
       INY
       LDA (PTR),Y      ;SECTOR
       JSR OBYT64
       JSR IBYT64       ;GET THE START ADDRESS OF THIS PROGRAM
       STA $0400        ;SAVE IT FOR THE FAST LOADER ROUTINE
       JSR IBYT64
       STA $0401
       JMP $0402        ;CALL THE ZAP PART OF ZAPLOADER
;
;==============================================================
;ROUTINE TO DISPLAY FILES THAT ARE IN MEMORY ON THE SCREEN
;
;PRGCNT    ACTUAL NUMBER OF PROGRAMS IN MEMORY
;CURPRG    PROGRAM NUMBER THAT THE CURSOR IS CURRENTLY ON
;CURLIN    LINE NUMBER THAT THE CURSOR IS ON (0-11)
;FPRG      FIRST PROGRAM BEING DISPLAYED ON THE SCREEN
;==============================================================
;
DSPFIL LDX #8           ;POINT TO THE FIRST LINE
       JSR SETPTR       ;WHERE THE MENU WILL BE DISPLAYED
       LDA #$00         ;WE ARE ON LINE 0 NOW
       STA WRKLIN
       LDA FPRG         ;WHICH PROGRAM DO WE START AT
       STA WRKPRG
       JSR FNDPRG       ;BUILD A POINTER (IN PTR) TO THE FIRST PROGRAM
;
DSPF00 LDX #$00         ;ASSUME CURRENT PROG IS NOT THE SAME AS THE...
       LDA WRKPRG       ;ONE THE CURSOR IS OVER
       CMP CURPRG
       BNE DSPF10
       LDX #$80         ;IT IS THE SAME SO DISPLAY IT REVERSED
DSPF10 STX TEMP         ;TEMP CONTAINS THE REVERSE FLAG
       LDY #$02         ;POINT TO THE NAME AND IT'S SCREEN DESTINATION
DSPF15 LDA (PTR),Y
       ORA TEMP
       STA (VPTR),Y
       LDA #15          ;DISPLAY NAMES IN LIGHT GREY
       STA (CPTR),Y
       INY
       CPY #18
       BNE DSPF15
;
       CLC              ;MOVE SCREEN POINTERS TO NEXT COLUMN
       LDA VPTR
       ADC #20
       STA VPTR
       STA CPTR
       BCC DSPF20
       INC VPTR+1
       INC CPTR+1
;
DSPF20 JSR NXTFIL       ;MOVE FILENAME POINTER TO THE NEXT ENTRY
;
DSPF25 LDX WRKPRG       ;HAVE WE FINISHED ?
       INX
       CPX PRGCNT
       BEQ DSPF50       ;YES SO SEE IF WE HAVE TO ERASE 2ND COLUMN
       STX WRKPRG
       TXA              ;IF PROGRAM NUMBER IS EVEN THEN MOVE DOWN A LINE
       AND #$01
       BNE DSPF00       ;NOPE, WE ARE ON THE SAME LINE
       INC WRKLIN       ;DO WE HAVE ROOM TO DISPLAY ANY MORE
       LDA WRKLIN
       CMP #12
       BNE DSPF00       ;YES KEEP DISPLAYING THE PROGRAMS
DSPF30 RTS              ;OUT OF ROOM, SO FINISH
;
DSPF50 TXA              ;IF WE FINISHED IN COLUMN 2 THEN WHATS THERE
       AND #$01         ;NOW WILL HAVE TO BE ERASED (NO FILE HERE NOW)
       BEQ DSPF30       ;NOPE, WE FINISHED IN COLUMN 1
       LDY #18          ;OK, WE HAVE TO BLANK OUT THE LAST LINE
       LDA #32
DSPF55 STA (VPTR),Y
       DEY
       BNE DSPF55
       RTS
;
;=================================================================
;THIS ROUTINE BUILDS A POINTER TO THE PROGRAM ENTRY NUMBER IN .A
;THE POINTER IS LEFT IN (PTR) FOR THE CALLER TO USE AS AN INDIRECT
;=================================================================
;
FNDPRG TAX           ;KEEP A COUNTER
       JSR SETFP     ;BUILD POINTER TO FIRST ENTRY
       CPX #0        ;IS THE POINTER CORRECT NOW ?
       BNE FNDP00    ;NOPE
       RTS           ;POINTER DONE
;
FNDP00 JSR NXTFIL    ;ADD 18 TO PTR FOR EACH FILENAME ENTRY
       DEX           ;STILL MORE TO DO ?
       BNE FNDP00    ;YES
       RTS
;
;
;BUILD A POINTER TO THE FILENAME AREA IN MEMORY
;
SETFP  LDA #<DIRSTR
       STA PTR
       LDA #>DIRSTR
       STA PTR+1
       RTS
;
;
;MOVE PTR TO THE NEXT FILE ENTRY (BY ADDING 18)
;
NXTFIL CLC
       LDA PTR
       ADC #18
       STA PTR
       BCC NXTF00
       INC PTR+1
NXTF00 RTS
;
;=====================================================
;THESE ARE GENERAL PURPOSE SCREEN AND MESSAGE ROUTINES
;=====================================================
;
;THIS ROUTINE SETS A POINTER IN VPTR AND CPTR TO THE SCREEN
;LINE SENT IN .X
;
SETPTR PHA
       TXA
       PHA
       ASL A
       TAX
       LDA SCRLIN,X
       STA VPTR
       STA CPTR        ;COLOR AND SCREEN LO BYTES ARE THE SAME
       LDA SCRLIN+1,X
       STA VPTR+1
       CLC
       ADC #>54272     ;OFFSET TO THE COLOR RAM
       STA CPTR+1
       PLA
       TAX
       PLA
       RTS
;
SCRLIN .WORD 1024,1064,1104,1144,1184
       .WORD 1224,1264,1304,1344,1384
       .WORD 1424,1464,1504,1544,1584
       .WORD 1624,1664,1704,1744,1784
       .WORD 1824,1864,1904,1944,1984
;
;
;==============================================================
;THIS ROUTINE PUTS REVERSE SPACES ON .Y LINES OF THE SCREEN
;STARTING AT LINE .X IN COLOR .A
;==============================================================
;
DOLINE STA COLOR     ;SAVE THE COLOR TO DO
       STY TEMP      ;SAVE THE LINE COUNT
DOLI00 JSR SETPTR    ;BUILD A POINTER TO THE LINE IN .X
       LDY #39
DOLI10 LDA COLOR     ;STORE THE COLOR
       STA (CPTR),Y
       LDA #$A0      ;STORE A REVERSE SPACE
       STA (VPTR),Y
       DEY
       BPL DOLI10
       INX           ;POINT .X TO THE NEXT LINE
       DEC TEMP      ;ANY MORE TO DO ?
       BNE DOLI00    ;YES
       RTS           ;ALL DONE
;
;================================================================
;CALL THIS ROUTINE TO DISPLAY MESSAGE .A ON THE SCREEN AT THE
;CO-ORDINATES THAT ARE STORED WITH THE MESSAGE.  �HE TEXT IS
;DISPLAYED IN REVERSE VIDEO.
;================================================================
;
MESAGE ASL A          ;ACCESS TABLE OF MESSAGE ADDRESSES
       TAX
       LDA MSGTBL,X
       STA PTR        ;BUILD A POINTER TO THE DESIRED MESSAGE
       LDA MSGTBL+1,X
       STA PTR+1
       LDY #$00       ;FIND OUT WHICH LINE TO STORE THE MESSAGE ON
       LDA (PTR),Y
       TAX
       JSR SETPTR
       INY            ;MAKE POINTER ABSOLUTE (ONLY SCREEN PTR
       LDA (PTR),Y    ;IS USED BECAUSE COLOR HAS BEEN DONE ALREADY)
       CLC
       ADC VPTR
       STA VPTR
       BCC MESA00
       INC VPTR+1
;
MESA00 LDA PTR      ;MOVE POINTER TO TEXT SO THAT IT POINTS
       CLC          ;TO THE TEXT STRING WITH INDEX Y = 0
       ADC #2
       STA PTR
       BCC MESA10
       INC PTR+1
MESA10 LDY #$00     ;OK, POINTERS ARE SET UP
;
MESA15 LDA (PTR),Y  ;GET A BYTE OF THE TEXT
       BEQ MESA20   ;0 BYTE TERMINATES IT
       AND #63      ;CONVERT TO REVERSE SCREEN CODE
       ORA #128
       STA (VPTR),Y
       INY
       BNE MESA15
MESA20 RTS          ;ALL DONE
;
MSGTBL .WORD MSG1,MSG2,MSG3,MSG4,MSG5,MSG6
;
MSG1   .BYT 1,10,'1541 FAST LOAD BY STEVE BEATS',0
MSG2   .BYT 5,0,'PLEASE PUT YOUR PROGRAM DISK IN THE 1541',0
MSG3   .BYT 5,0,'PROGRAMS ON THE DISK "                " ',0
MSG4   .BYT 22,0,'CURSOR KEYS TO SELECT AND RETURN TO LOAD',0
MSG5   .BYT 9,1,'THERE ARE NO PROGRAMS ON THIS DISK !!!',0
MSG6   .BYT 11,1,'RETURN TO CHANGE DISKS OR STOP TO QUIT',0
;
;========================================================
;THIS IS THE DATA FOR THE SPRITES THAT MAKE UP THE TITLE
;========================================================
;
TITLEZ .BYT $55,$55,$54,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$6A,$AA,$A4,$55,$5A,$A4,$00
       .BYT $1A,$90,$00,$1A,$90,$00,$6A,$40
       .BYT $00,$6A,$40,$01,$A9,$00,$01,$A9
       .BYT $00,$06,$A4,$00,$06,$A4,$00,$1A
       .BYT $90,$00,$1A,$90,$00,$6A,$95,$54
       .BYT $6A,$AA,$A4,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$55,$55,$54,$00,$00,$00,$24
;
TITLEA .BYT $55,$55,$54,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$6A,$AA,$A4,$69,$55,$A4,$69
       .BYT $01,$A4,$69,$01,$A4,$69,$01,$A4
       .BYT $69,$55,$A4,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$6A,$AA,$A4,$69,$55,$A4,$69
       .BYT $01,$A4,$69,$01,$A4,$69,$01,$A4
       .BYT $69,$01,$A4,$69,$01,$A4,$69,$01
       .BYT $A4,$55,$01,$54,$00,$00,$00,$54
;
TITLEP .BYT $55,$55,$54,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$6A,$AA,$A4,$69,$55,$A4,$69
       .BYT $01,$A4,$69,$01,$A4,$69,$01,$A4
       .BYT $69,$55,$A4,$6A,$AA,$A4,$6A,$AA
       .BYT $A4,$6A,$AA,$A4,$69,$55,$54,$69
       .BYT $00,$00,$69,$00,$00,$69,$00,$00
       .BYT $69,$00,$00,$69,$00,$00,$69,$00
       .BYT $00,$55,$00,$00,$00,$00,$00,$C4
;
DIRSTR .BYTE 0 ;WHERE DIRECTORY ENTRIES AE STORED
       .END
