;============================================================
;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.  This fast i/o
;routine is then used for all subsequent code transfers between the
;drive and the 64.  Note, these i/o routines work with the screen
;and interrupts turned on but aren't as fast as the burst transfers
;===================================================================
;
*=$0801  (c64 BASIC 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.  There 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.  It 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.  The 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.  The 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.  Sprites 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.  A 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.  The 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
