X-NEWS: hylka comp.sys.cbm: 9773 Path: klaava!news.funet.fi!news.tele.fi!uunet!pipex!uknet!warwick!not-for-mail From: stuce@csv.warwick.ac.uk (Peter Weighill) Newsgroups: comp.sys.cbm Subject: 1541 disk drive commands. Date: 25 Sep 1993 19:20:47 +0100 Organization: Commodore 64 Services, University of Warwick, UK Lines: 122 Message-ID: <28225v$1s3@tansy.csv.warwick.ac.uk> TWO RARELY USED 1541 DISK DRIVE FUNCTIONS 1. The Utility Loader '&' command. INTRODUCTION A little known and little used command on the 1541 disk drive is the "&" command. This is probably due to the fact that there is no mention of it in the "1541 DISK DRIVE users guide". Many other books about the disk drive also fail to mention it. As to a use for the command, I have not found one yet. Perhaps someone could think of one. I would expect that the 1570/1571 and 1581 drive will also contain the "&" command as well, since they are based on the 1541. UTILITY LOADER ("&" command) The utility loader is the command which will load a USR file from disk into disk drive memory where it will then execute. The format for the command is as follows: OPEN15,8,15:PRINT#15,"&filename":CLOSE15 USR FILES A user file has to follow certain guidlines. It is limited to just one sector and this sector is constructed as below; Byte 0 Start address low order 1 Start address high order 2 Number of bytes in program 3+ Program code bytes last Checksum This means that the maximum size of program code is 251 bytes. The checksum byte is calculated by adding all the values of the bytes, starting at the low order start address (byte 0), while adding you subtract 255 from the total every time it exceeds 255. Thus the checksum byte can range from 1-255. One final constraint is that the filename must begin with an "&". Below is a program which will make it easier for you to create a USR file in the required format, so that it can be executed by the utility loader command. The program automatically calculates the length of the code and also the checksum at the end. All you need to do is add your own code to the data statements between 210 and 300 and specify a filename in line 10. 10 OPEN2,8,2,"0:&filename,U,W" 20 READLO,HI:C=LO+HI:IFC>255THENC=C-255 30 PRINT#2,CHR$(LO)CHR$(HI); 40 T$="" 50 READD:IFD=-1THEN100 60 C=C+D:IFC>255THENC=C-255 70 T$=T$+CHR$(D) 80 GOTO50 100 L=LEN(T$) 110 C=C+L:IFC>255THENC=C-255 120 PRINT#2,CHR$(L)T$CHR$(C); 130 CLOSE2 140 END 170 : 200 DATA 0,5 :REM lo/hi start address 210 : REM program code 220 DATA 173,0,28,41,16,201,16,208,11 230 DATA 169,247,45,0,28,141,0,28,76 240 DATA 0,5,32,24,193,76,0,5 300 DATA -1 :REM program data finished The example code in the program is not that useful, it is just there to show how the utility loader works. It just switches the drives light on and off depending on if the write protect sensor is covered or not. If you can think of something which could be done with the utility loader then I would love to hear of it. ERRORS THAT CAN OCCUR 39, 'file not found' This occurs if the file you specified using the utility loader command does not exist or is not a USR file. 50, 'record not present' The checksum calculated by the disk drive and the checksum at the end of the file differ. 51, 'overflow in record' Either: 1. The end of the file was reached before the checksum byte was read. or 2. The file contains extra bytes of data after the checksum byte. Check the length byte in the usr file (position 3, after lo/hi.) 2. Checking that a file is on the disk. INTRODUCTION If you wrote a program which needed to check that a particular file existed on a disk then you would probably open the file for a read, then check the error channel for 62, FILE NOT FOUND. Thus: 10 OPEN15,8,15 20 OPEN2,8,2,"filename,P,R" 30 INPUT#15,E,E$ 40 IFE>0THENPRINTE$:GOTO60 50 PRINT"FILE EXISTS" 60 CLOSE2:CLOSE15 Another way to check if a file exists is to try to rename it as itself. Thus: 10 OPEN15,8,15,"R:filename=filename" 20 INPUT#15,E,E$ 30 CLOSE15 40 PRINTE$ If the file exists then the error created is 63, FILE EXISTS, otherwise it is 62, FILE NOT FOUND. Judge for yourself which works better. Written, September 93, by Peter Weighill. email: stuce@warwick.csv.ac.uk From: Nicholas.Cull@comp.vuw.ac.nz (Nicholas Cull) Newsgroups: comp.sys.cbm Subject: Re: 1541 disk drive commands. Date: 30 Sep 1993 00:00:20 GMT Organization: Dept. of Comp. Sci., Victoria Uni. of Wellington, New Zealand. Originator: ncull@comp.vuw.ac.nz In article <28225v$1s3@tansy.csv.warwick.ac.uk>, stuce@csv.warwick.ac.uk (Peter Weighill) writes: |> |> 1. The Utility Loader '&' command. ... |> A user file has to follow certain guidlines. It is limited to just ^^^^^^^^^^^^^^^^^^^^^ |> one sector and this sector is constructed as below; ^^^^^^^^^^ This is incorrect. The user file may be more than one sector long, although the maximum size of the program code is limited to 256 bytes. To obtain this, byte 2 (the number of bytes in program) should be set to 0. A formula for this would be (NB AND 255) where NB is the number of bytes. Remember that the checksum has to be updated in a similar way too, eg C = C+(NB AND 255): IF C>255 THEN C=C-255 The number of bytes in a Block-Execute command is limited to a single sector, which is 256 bytes, although these can be all data bytes. Maybe you were confusing the two commands? |> |> Byte |> 0 Start address low order |> 1 Start address high order |> 2 Number of bytes in program |> 3+ Program code bytes |> last Checksum |> In fact there can be more than one block of this construction per file. To do this, simply repeat the construction. For example, if you wanted to have a program which sat in drive locations $0300 to $0400, and $0480 to $0500, the construction would be as follows: Byte 0 Low byte start address of first block (0) 1 High byte start address of first block (3) 2 Number of bytes in this block (0) [= 256 AND 255] 3 - 259 Program code for first block (data goes in here...) 260 Checksum for first block (whatever this may be) 261 Low byte start address of second block (128) 262 High byte start address of second block (4) 263 Number of bytes in this block (128) 264 - 392 Program code for second block (second lot of data here) 393 Checksum for second block (whatever) Okay, so this may not be the best description in the world, but hopefully you get the general idea. There may be as many blocks of this type as you need, and theycan all be any size from 1 to 256 bytes long. Once the file has been completely loaded into the drive, execution starts from the start address of the FIRST block be be transferred. |> the total every time it exceeds 255. Thus the checksum byte can range from ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |> 1-255. ^^^^^^ The checksum could be 0 if all the data bytes were 0 :-) Seriously though, the point of having the checksum calculated in this way is to make use of the carry bit in machine code addition if a carry is generated. The point can be made more clearly in the following code fragment: [accumulator holds current data byte] clc ;Clear carry bit for first add adc $87 ;Add byte to current checksum adc #$00 ;Add carry bit to checksum sta $87 ;Save checksum to memory If the sum of the accumulator and the contents of location $87 is greater than #$FF then the carry flag will be set, in order to do multi-byte addition correctly. Instead of adding this to a second byte however, it is added to the same byte which generated the carry. This causes the value in the accumulator to be incremented by 1 - the same as if #$FF had been subtracted from it. If the sum is of the accumulator and the contents of location $87 is less than or equal to #$FF, then no carry is generated and no further addition or subtractionis needed. |> Below is a program which will make it easier for you to create a USR |> file in the required format, so that it can be executed by the utility |> loader command... Here is a new version the the program, modified to handle multiple data blocks, and a maximum program size of 256 bytes per block: 10 OPEN2,8,2,"0:&filename,U,W" 20 READNB 30 READLO,HI,LN:C=LO+HI:C=C+(C>255)*255 40 C=C+(LNAND255):C=C+(C>255)*255 50 PRINT#2,CHR$(LO);CHR$(HI);CHR$(LNAND255); 60 READD:PRINT#2,CHR$(D); 70 C=C+D:C=C+(C>255)*255 80 LN=LN-1:IFLN>0THEN60 90 PRINT#2,CHR$(C); 100 NB=NB-1:IFNB>0THEN30 110 CLOSE2 120 END 190 : 200 DATA2 :REM number of data blocks 210 DATA128,3 :REM lo/hi start address of first block 220 DATA6 :REM length of first block 230 : REM program code 240 DATA32,71,198,76,0,3 300 DATA0,3 :REM lo/hi start address of second block 310 DATA26 :REM length of second block 320 : REM rest of program code 330 DATA173,0,28,41,16,201,16,208,11 340 DATA169,247,45,0,28,141,0,28,76 350 DATA0,3,32,24,193,76,0,3 The example code here is just a minor extension to the original code. It re-initializes the drive before jumping to the original code. This is just to demonstrate that both parts of the code are being loaded and executed correctly. |> ERRORS THAT CAN OCCUR |> |> 51, 'overflow in record' |> Either: 1. The end of the file was reached before the checksum |> byte was read. |> or 2. The file contains extra bytes of data after the checksum ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |> byte. ^^^^^ |> Check the length byte in the usr file (position 3, after lo/hi.) The second condition is not quite accurate. If end-of-file is reached before the drive expects to read the checksum, then this error will occur. If extra bytes appear after the checksum, the drive assumes these to be the start of a new block of data and will try to interpret these as address bytes, length byte, data bytes etc as above. When end-of-file appears, the drive will report this error, since it is expecting another block of data to appear and cannot complete the transfer of this into memory. Hence the definition of this error should be: The end of the file was encountered unexpectedly. May indicate an incorrect length byte, or additional data written after the end of the last data block. Note the semicolon at the end of line 90 of the program. If this were omitted, a carriage return byte would be sent by the computer after the checksum byte and may be the cause of this message. One caution should be added at this point. Although data may be transferred to any address in the RAM of the drive, it should be remembered that part of the memory will be allocated to buffering the file as it comes off the disk. Thus it may be possible to overwrite incoming data being buffered in memory before it can be transferred correctly to its new location. Experimentation may be the best way of determining which areas are "safe" and which ones have problems. I found that the file seemed to be buffered in locations $0600 to $0700, but this would depend on how may files you had open, etc. Nick. ---- email: ncull@comp.vuw.ac.nz Victoria University of Wellington, New Zealand.