;============================================================ ;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 sta ptr+1 ; lda #buf3 ;this isn't really needed but it is safer in... sta ddest+1 ;case this code is called again ; 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 curprgdirstr 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