[description taken from the prlink 0.9.6 README file] 2.5.3 fastload.a65 This routine has actually nothing to do with prlink, except that it uses a similar protocol as prlink. This is a synchronous fastloader routine to be used with a 1541 or 1571 disk drive, also known as "IRQ loader". Because the transfer routines are synchronous, the loader works on both PAL-G and NTSC-M systems, also in fast processor modes. The loader uses the synchronous IEC bus protocol that is described in Section 6.5. Everything is fully synchronous, so the transfer won't be disturbed by any amount of interrupts on the computer. The loader was modified from a disassembly listing that I got a long time ago. I assume that it was the loader of the G.I.Joe game, because it only compared the first two characters of the filenames. I practically rewrote everything, only some label names remained. I also left the two-character filename comparison there. Using the loader is very simple. Select the target system and compile the loader with DASM (e.g. "make TARGET=c64 fastload.prg"). You will need to initialize the disk drive with a single call to "init". Note that the FA system variable, which holds the current (or last used) device number, must be properly set before calling the routine. After the initializations, the drive will sit in a loop, waiting for the fastload command. If the ATN signal gets asserted, the fastloader will quit to normal operation. So, the drive does not prevent any normal bus operations; you just have to reinstall the routine if you want to use it again. If there aren't any other activities on the bus, you can load several files with the fastloader without reinstalling it. The constant LEDFLASH controls the drive LED flashing. There are four options. If LEDFLASH=0, the drive LED acts normally (e.g. it is lit constantly while a file is being loaded). If LEDFLASH=1, the drive LED will glow on and off while the drive is waiting for a request. From this glow you will recognize if the fast loader is active. If LEDFLASH=2, the drive LED will be on while reading a sector, and off otherwise. Setting LEDFLASH=3 combines these two advanced options. When the fastloader is installed, you can load program files by loading the first two filename characters to the X and Y registers and by calling the "irqload" routine. The Carry flag will be set in return, if the file could not be loaded. There is only one possible flaw in the loader. If the computer gets interrupted right after it has sent the second character of the filename but before it has completed the handshake, and if the interruption lasts so long that the drive starts sending the first program byte (or an error code), the computer will remain in the loop, waiting for the handshake that occurred a long time ago. This could be solved with a watchdog timer or something. But actually this is not much of a problem, since the drive will read the disk directory before sending the status byte, which should last longer than any interruption on the computer side. Interrupts are disabled on the drive while sending data. This is mainly for improving the performance. However, interrupts must be disabled when sending the last byte, right before returning to the main loop. This prevents the deadlock situation on the drive side. Note that the interrupts must be enabled while waiting for the file name, because the disk motor is controlled by the interrupt routine. If interrupts are disabled, the disk will not stop spinning. These deadlocks could have been avoided by using the protocol described in Section 6.5.2, but it would have made the loader bigger and slightly slower. There is a further flaw in the routine. If the drive is turned off, the routine may read phantom data from the serial bus, i.e. the signals read from the bus will vary, although they shouldn't. I experienced this on my VIC-20 and Oceanic OC-118N drive (1541 clone). There were no other serial devices on the bus. So, the protocol is not completely fault-tolerant, and you might want to include some sort of a checksum in it. [the code] ;---------------------------------------------------------------------- ; Synchronous 1540/1541/1570/1571 fastloader ; Copyright © 1996 Marko Mäkelä ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ;---------------------------------------------------------------------- ; Init: jsr init ; Load: ldx #"A" ;first char of name ; ldy #"B" ;second char of name ; jsr irqload ; ; C=status: 0=ok, 1=error ;---------------------------------------------------------------------- target eqm c128 ; choose the target system vic20 = 1 ; Commodore VIC-20 c64 = 2 ; Commodore 64 c128 = 4 ; Commodore 128 c16 = 8 ; The Commodore 264 Series (C16, C116, plus/4) START = $2000 ; and the start address RETRIES = 5 ; amount of retries when reading a sector LEDFLASH = 3 ; LED flashing level: ; 0 = normal (LED constantly on while loading a file) ; 1 = LED glows on and off while waiting for a command ; 2 = LED on only while reading sectors ; 3 = 1 + 2 ;--------------------------------------- ; source code begins ; no user-modifiable routines inside :-) #processor 6502 ; include the ROM definitions #if target & c16 #include "include/c16rom.lib" #else #include "include/cbmrom.lib" #endif AMOUNT = $20 ; amount of data bytes to transfer with one M-W command ESCBYTE = $ac ; the escape char used in the transfers ; set the I/O constants and the variables #if target & vic20 iecport1 = $912c dato = 32 clko = 2 iecport2 = $911f atno = 128 clki = 1 dati = 2 #endif #if target & (c64 | c128) iecport1 = $dd00 iecport2 = iecport1 atno = 8 clko = 16 dato = 32 clki = 64 dati = 128 #endif #if target & c16 iecport1 = 1 iecport2 = iecport1 dato = 1 clko = 2 atno = 4 clki = 64 dati = 128 #endif ; declare the zeropage variables store = sal ; temporary byte storage #org START init: ; initialize the self-modifying parts of the code lda #drvcode sta mwbyte$ + 2 lda #drive sta mwcmd$ + 1 ; send the m-w command to write the data mwloop$: jsr inidev$ ldx #lmwcmd$ - 1 smwcmd$: lda mwcmd$,x jsr ciout dex bpl smwcmd$ ; send the actual data bytes ldx #0 mwbyte$: lda drvcode,x jsr ciout inx cpx #AMOUNT bne mwbyte$ ; complete the command jsr unlsn ; update the addresses clc lda #AMOUNT adc mwbyte$ + 1 sta mwbyte$ + 1 bcc noupdhi1$ clc inc mwbyte$ + 2 noupdhi1$: lda #AMOUNT adc mwcmd$ + 2 sta mwcmd$ + 2 tax lda #0 adc mwcmd$ + 1 sta mwcmd$ + 1 cpx #edrvcode bcc mwloop$ ; send m-e to start the routine jsr inidev$ ldx #lmecmd$ - 1 sendcmd$: lda mecmd$,x jsr ciout dex bpl sendcmd$ ; perform the command jmp unlsn ; subroutine: make the current drive listen inidev$: lda fa jsr listn lda #$6f jmp secnd ; the m-w command backwards mwcmd$: dc.b AMOUNT,>drive,drive,