1571-2.TXT rev 1a 96-11-01 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * THIS DOCUMENT IS COPYRIGHT (C) 1988, 1996 BY HERNE DATA SYSTEMS LTD. THE MATERIAL CONTAINED HEREIN MAY BE FREELY USED FOR PERSONAL INFORMATION ONLY. IF YOU REPRODUCE IT, THIS COPYRIGHT NOTICE MUST NOT BE REMOVED. THIS MATERIAL MAY NOT BE EXPLOITED FOR COMMERCIAL PURPOSES. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Herne Data Systems Ltd., PO Box 250, Tiverton, ON N0G 2T0 CANADA. Voice/fax 519-366-2732, e-mail herne@herne.com internet: http://www.herne.com * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * BASIC Disk Commands The 1571 disk drive is primarily intended to be used with the C-128 128-D computers. (It does, however, work very well with other Commodore computers which support the serial port, such as the C-64, SX-64, Plus/4, C-16, VIC-20 or the C-128 in C-64 mode, although these other computers do not support the 1571's fast serial port mode.) The C-128's resident version of BASIC, termed BASIC 7.0, contains a rich vocabulary of disk commands. These commands greatly simplify the process of communication between the computer and the disk drive. Where noted, some of the commands are also applicable to other versions of Commodore BASIC, such as 2.0 used on the C-64 and VIC-20, and 3.5 used on the Plus/4 and C-16. In general, the commands beginning with "D" (such as DLOAD) and "B" (such as BACKUP) are not available in BASIC 2.0. However, some of these commands are available in BASIC 3.5. This document contains a description of each of the BASIC disk access commands (grouped according to major function) along with examples and tips for their usage. The command keywords are spelled out in full. Abbreviated two or three character versions are also available for most of the commands. Capital letters included in a command string (such as U, D, B, P, etc) are part of the command string that must be entered. As a reminder, lower case text enclosed in curly braces "{}" is used to describe the string or numeric parameters which should be entered for each command. Spaces have been added between the various parameters to improve the readability. These spaces are not required by BASIC. In immediate mode, all commands should be completed by pressing the or key. It should be noted that most of the commands will accept either constants (such as the text string "FILE2" or the numeral "8") or variables (such as the text string name F$ or numerical variable N) for specifying the command parameters. In general, variable names for the BASIC 7.0 commands should be enclosed in parentheses, such as (F$) or (N), when used in such a manner. Except where noted, all filenames can contain the wildcard and pattern matching characters "?" and "*". Command parameters enclosed in square brackets "[ ]" are optional and can be left out if the default value is suitable for the application. It normally does not matter in which order optional parameters are specified. For example, "D0,U8" is the same as "U8,D0". In all cases for the BASIC 3.5/7.0 disk commands, the default value for the disk drive unit, or device, number (as given by the U parameter) is 8 and the drive number (as given by the D parameter) is 0. The drive number is intended to be used with dual disk units (i.e two disk drives in a single case where one drive would be addressed as drive "0:" and the other as drive "1:"). Since the 1571 is only a single drive, the drive number always has a value of 0. The ",U{device#}" format can be replaced by "ON{device#}", if you so desire. The two forms are inter-changeable. For BASIC 2.0 compatible commands, the default device number is always 1 (the cassette port). Retrieving Programs =================== Perhaps the most common use of your disk drive will be to store and retrieve "programs". BASIC has several commands intended for the retrieval of previously stored programs on a disk. They might be programs which you have bought or ones that you have written yourself. To the disk drive, they are the same. In simple terms, the LOAD commands read a disk file and POKE the bytes into memory. The first two bytes of the file contain the address in the computer's memory from where the file was initially saved. These two bytes are either ignored or used to tell the computer where to put the program when it is loaded, depending on the options specified with the LOAD command. Each of the LOAD commands has a different effect on where the the program will be placed in memory. Note that all of the LOAD type commands will only work with PRG (program) type disk files. If an attempt is made to LOAD another type of file (such as SEQ), a "FILE NOT FOUND" or "TYPE MISMATCH" error will be generated. However, on the C-128, a SEQ or other type of non-program file can be read into memory as a BASIC program using a technique outlined in 1571-4.TXT (DOS & the KERNAL). For all of the LOAD type commands, the "{filename}" may contain wildcard and/or pattern matching characters. In such a case, the first filename in the disk directory which matches the pattern will be LOADed. With DLOAD, BLOAD and BOOT, a "{drive#}:" character string is automatically added to the beginning of the filename as it is sent to the disk drive and displayed on thescreen during the "SEARCHING FOR {filename}" message. For the 1571, this should always appear as "0:". LOAD LOAD is perhaps the most familiar command for retreiving programs. It is available in all forms of Commodore BASIC. For disk users, the syntax for the command is: LOAD "[{drive#}:]{filename}",{device#}[,{relocate flag}] Since the default device number is 1 (i.e. the cassette port) for most Commodore computers (except the SX-64) a device number of, for example, 8 must be included for disk use. A {relocate flag} value of 0 means that the program file will be LOADed into the normal start of BASIC address as specified by the pointers set up in the computer's RAM. This is the default condition. In the C-128, the start of BASIC pointer is in BANK 0 at address 45-46 ($2d-$2e) in standard low byte-high byte format. This pointer can be manipulated with POKE's before a LOAD, but care should be taken to restore it to the default value after the LOAD. A {relocate flag} value of 1 indicates that the program will be LOADed into its own normal start address, as specified by the first two bytes contained in the program file. This is normally used for LOADing machine language subroutines and programs that must be in a specific RAM location for operation. It can also be used to LOAD non-program data, such as high resolution graphics screens, into specific areas of RAM. Some examples are: LOAD "0:BASIC PROGRAM",8 will search for and, if found, LOAD the file "BASIC PROGRAM" from disk drive device #8, drive 0. LOAD "0:ML.PROGRAM",8,1 will search for and, if found, LOAD the file "ML.PROGRAM" into a specific address of RAM as determined by the first two bytes of the file. LOAD "0:TEST*",8 will LOAD the first program in the directory whose first four characters are "TEST". Two special forms of LOAD should be noted: LOAD "*",8 [,1] will LOAD the first program listed in the disk directory (optionally with the {relocate flag} set), while: LOAD "$",8 will LOAD the disk directory as a program file. To display the directory, you must then type LIST. This method is one of the easiest ways to display a disk directory in BASIC 2.0 (which lacks a true directory command) without using a DOS wedge. This method is also necessary for obtaining a printed copy of the directory in any form of BASIC. The following procedure can be used: LOAD "$",8 OPEN 4,4 CMD4:LIST PRINT#4:CLOSE4 Unfortunately, BASIC 3.5 and 7.0's DIRECTORY and CATALOG commands (discussed later) will not allow the re-direction of output from the screen to a printer. Hence, the procedure above is applicable to all current versions of Commodore BASIC. DLOAD DLOAD is a modified form of the LOAD command which is available with BASIC 3.5 and 7.0. It LOADs from disk only. The syntax is: DLOAD "{filename}"[,U{device#}][,D{drive#}] DLOAD is the equivalent of the LOAD command but the default device is 8 (i.e. a disk drive) rather than 1. Like LOAD, DLOAD will put the file into the RAM address specified by the start of BASIC pointer. An example would be: DLOAD "GAME",U9 to DLOAD the program "GAME" from a device 9 disk drive. The statement: DLOAD (A$) will DLOAD the file specified by A$ from the default disk drive (device 8, drive 0). It should be noted that due to a bug in older versions of the C-128's ROM, DLOAD cannot be used to load a "locked" program file. (A locked file is one which cannot be scratched. It is identified by the symbol "<" which appears after the file type in the disk directory listing.) In this case, a locked file must be loaded with the LOAD command. The newer ROM versions which support locked file DLOAD's can be identified by BASIC's signon message which is dated 1986 instead of 1985. BLOAD The BASIC 7.0 command BLOAD can be thought of as a contraction of the words "Binary LOAD". It is used to LOAD a PRG type file into a specific area of memory. BLOAD can be used for LOADing a machine language subroutine that will be used by another program, or for retreiving non-program data from disk, such as a high-resolution graphics screen, data values (BANK 1), function key and sprite definitions, a custom character set, etc. BLOAD can be used either in immediate mode or from within a program. The syntax of the command is: BLOAD "{filename}"[,U{device#}][,D{drive#}][,B{bank#}] [,P{start address}] where {bank#} represents the RAM bank into which the file is to be LOADed (default BANK 15), and {start address} represents the starting memory location in RAM where the file is to be placed (default is the normal LOAD address for the file). In immediate mode, BLOAD without the {start address} option is equivalent to the LOAD command using a {relocate flag} value of 1. In program mode, BLOAD will continue with program execution with the statement immediately following the BLOAD, while LOAD will start executing the program from the beginning again, possibly creating an endless loop. The following example will BLOAD a disk file into the area of RAM normally occupied by the C-128 high resolution graphics screen (starting at the color map): BLOAD "HI-RES PICTURE",B0,P7192 Of course, you must first set up the appropriate graphics mode with the BASIC 7.0 GRAPHIC command before BLOADing the screen. Similar to DLOAD, BLOAD will not work with locked files on older C-128 ROM versions. In this case, you should use either a KERNAL LOAD (discussed in 1571-4.TXT) or a LOAD with a {relocate flag} value of 1. MONITOR-L The BASIC 3.5 and 7.0 MONITOR commands both contain the equivalent of BLOAD which can be used when in MONITOR mode. The syntax is: L "{filename}",{device#} [,{start address}] The optional {start address} parameter is applicable to BASIC 7.0 only. It has the same meaning as the parameter in the BLOAD command. However, it should be noted that in MONITOR mode, {device#} and {start address} are always specified in hexadecimal notation. BASIC 7.0 MONITOR addresses can be 5 hex digits long. If the address is greater than 4 digits long, the left most digit is taken to be the BANK number into which to load the file. For example, L "ML.PROGRAM",08,11000 will load the specified program from device 8 into the area of RAM beginning at $1000 (decimal 4096) of BANK 1 of the C-128. Many machine language monitors, such as VICMON for the VIC-20 and C-64, have LOAD options similar to the BASIC 3.5 version. BOOT BOOT is used to automatically LOAD and execute a machine language program file on the C-128. It can also be used for the automatic execution of a BASIC program. Two forms of the command are possible: BOOT [U{device#}][,D{drive#}] by itself will check for a valid BOOT sector (track 1, sector 0) on the specified or default drive, then LOAD its contents into the cassette buffer at $0b00 (dec 2816) and execute its contents, if found. This is similar to what happens during a C-128 hard reset (i.e. by pressing the reset button or turning the power off the on). It can be used to start up an autobooting disk, such as the CP/M Plus system disk or many commercial programs. The {device#} and {drive#} parameters are not normally specified because most multi part commercial autoboot software will only work from device 8, drive 0 (the default settings). They can be included for your own programs, however, if you include the specific device number when loading secondary files from the BOOT routine. On the C-128, the BOOT routine should check location $ba (decimal 186) or $11c (decimal 284) to determine which device is being BOOTed and use this device number for multi part loads. The second form of the command: BOOT "{filename}"[,U{device#}][,D{drive#}][,P{load address}] [,B{bank#}] will LOAD and execute the machine language program specified by "{file name}" from the disk drive specified by {device#} and {drive#} into the area of RAM specified by {load address} in BANK {bank#}. The default LOAD address is the normal LOAD address for the file while the default BANK is 15. This latter form of the BOOT command is equivalent to using a BLOAD followed by a SYS to the starting address of the program. An example is: BOOT "ML.PROGRAM",U8,P10000 to BLOAD the specified machine language program into RAM at decimal 10000 and begin its execution at this address. BOOT is available in BASIC 7.0 only. RUN In BASIC 7.0, the RUN command can be used to LOAD and RUN a BASIC program from disk, similar to BOOT for machine language files. The syntax is: RUN "{filename}"[,U{device#}][,D{drive#}] This is equivalent to DLOADing the specified BASIC program, then typing RUN. For example: RUN "STARBLASTER" will DLOAD then execute the BASIC program "STARBLASTER" from device 8, drive 0. Storing Programs ================ Analogous to the program retrieving commands, BASIC also has a set of program storing commands. These commands allow you to store your programs in a disk file for future retrieval. Special forms of the commands can be used for storing areas of the computer's RAM to a disk file for saving high resolution graphics screens, function key and sprite definitions, etc. In simple terms, the SAVE commands take a "snapshot" or memory image of an area of the computer's memory and write it to a disk file, byte by byte. The first two bytes of the file represent the starting address of the memory from where the snapshot was taken. This may be used later by the LOAD commands to indicate where to return the snapshot. It is important to remember that you are actually storing an area of the computer's addressable memory space rather than a "program". The area of memory can contain anything: graphics and text screens, BASIC programs, machine language, RAM or ROM, chip register values, etc. Note that in all of the program storing commands described below, "{filename}" cannot contain any pattern matching or wildcard characters. All SAVEd files are created in PRG (program) file format only. SAVE The most common command for storing programs is SAVE. This is the exact opposite of the LOAD command. For disk use, the syntax is: SAVE "[{drive#}:]{filename}",{device#} A SAVE without a specified {device#} will default to the cassette port. For example: SAVE "0:RACECAR",8 will SAVE the current program in memory in the file called "RACECAR" on a device 8 disk drive. Although {drive#}: is optional, it is always prudent to specify it. This might seem odd, but the 1571 drive, just like the 1541 before it, is based on a dual drive DOS. Most of the dual drive functions have been patched out but unless the drive number of 0 is explicitly specified each time, the DOS can become confused and tries to access a non-existant drive 1, sometimes leading to drastic consequences. This is the basic reason behind the infamous "save with replace bug" described below. A special form of the SAVE command allows you to over-write an existing file and replace it with a new one of the same name. The command works within the disk drive and acts by first SAVEing the new file then scratching the old one. The syntax is: SAVE "@0:{filename",{device} An example would be: SAVE "@0:NEW VERSION",8 This example will replace the existing file "NEW VERSION" with the new program. The "@0:" at the beginning of the file name specification indicates a "save with replace" on drive 0. This command has long been a concern of many Commodore disk drive users who have complained that it leads to hopelessly corrupted files. (I have experienced it a few times working with a VIC-20 and a 1541 drive). Because of this, many users prefer to use a two step sequence for save with replace: SAVE the new file under a different name, then scratch the old file. However, if used correctly SAVE "@0:" does work properly. The key is to always include the {drive#} parameter in ALL disk operations (not just LOADs and SAVEs, but OPENs as well). DSAVE DSAVE is the opposite of DLOAD. The syntax is: DSAVE "{filename}"[,U{device#}][,D{drive#}] DSAVE will default to device 8, drive 0 if none of the optional parameters are specified. For example: DSAVE "RACECAR" is identical to the example used above for the SAVE command. DSAVE is available in BASIC 3.5 and 7.0. A special form of DSAVE can be used for the "save with replace" option. The syntax is: DSAVE "@:{filename"[,U{device#}][,D{drive#}] Note that in the case of DSAVE, "{device#}:" is never specified at the start of the file name string. This is because DSAVE automatically adds the drive specifier when it sends the filename to the drive. If you do specify it explicitly, then a double "0:0:" will be added to the filename and the file name as it appears in the disk directory will have the "0:" added to the beginning of it, such as "0:FILE" instead of just "FILE". Both SAVE and DSAVE actually SAVE the area of memory between the start of BASIC pointer and the end of BASIC text pointer. Both of these pointers can be manipulated before a SAVE or DSAVE. However, the pointers should be set back to their original values after the operation. Typically, the end of BASIC text pointer can be increased to include a machine language subroutine at the end of a program in the SAVE. On the C-128, the end of BASIC text pointer is in BANK 0 at hex $1210-1211 (decimal 4624-4625). BSAVE BSAVE is the opposite of BLOAD, it is used to SAVE a specified area of RAM to a disk file. It can be used for SAVEing machine language programs created by BASIC POKE statements or the MONITOR command, or other areas of memory such as a high resolution graphics screen, function key definitions, or sprite data. The syntax for the command is: BSAVE "{filename}"[,U{device#}][,D{drive#}][,B{bank#}],P{start address} TO P{end address} where {bank#} is the optional bank from which to BSAVE (default BANK 15), and {start address} and {end address} are the mandatory start and end points for the memory being BSAVEd. BSAVE is only available in BASIC 7.0. The following example will BSAVE the high resolution screen (320 by 200 pixel) color map and bit map to a disk file: BSAVE "HI-RES",B0,P7168 TO P16383 MONITOR-S The BASIC 3.5 and 7.0 MONITOR commands contain an equivalent of BSAVE for use in MONITOR mode. The general syntax is: S "{filename}", {device#}, {start address}, {end address+1} {device#}, {start address} and {end address} are all expressed in hexadecimal form. In BASIC 7.0, {start address} and {end address} can be 5 digit hex numbers, although both must be in the same BANK. In addition, {end address} must be greater than {start address}. Unlike BSAVE, the second parameter is specified as {end address+1} to ensure that the last byte is SAVEd. (BSAVE automatically increases the {end address} pointer to include the last byte.) For example, S "PROGRAM",08,1000,2000 will SAVE the area of memory from $1000 (decimal 4096) to $1fff (decimal 8191) to the specified filename on device 8. In BASIC 7.0, the above area of memory will be in BANK 0. RAM, ROM or chip registers can be SAVEd to disk using this technique. Similar commands for SAVEing memory are included with most machine language monitors for the C-64 and VIC-20 also. Comparing Program Files ======================= It is often desirable to check whether a program currently in memory is the same as one stored in a disk file. This can be helpful if, for example, you have several copies of a program on a disk and wish to see if they are identical or are slightly different versions. It can also be useful if you are not sure if a program that you have been working on has been correctly SAVEd to disk. These commands, which can be used in either program or immediate mode, perform a byte by byte comparison of the disk file specified by "{filename}" with a program in memory. If a single byte is found to different, a VERIFY ERROR message will be generated. Pattern matching and wild cards can be used in the "{filename}" string. VERIFY The VERIFY command is available in all forms of Commodore BASIC for comparing program files on disk to one currently stored in memory. The syntax for the command is: VERIFY "[{drive#}:]{filename}",{device#}[,{relocate flag}] With VERIFY, the {relocate flag} should have a value of 1 for comparing machine language programs with start addresses of other than the normal start of BASIC area. For disk files, {device#} must be specified. An example is: VERIFY "DATABASE",8,1 This will compare the machine language disk program file "DATABASE" with the program currently in memory. DVERIFY Along with VERIFY, BASIC 7.0 also has a second command available with the following syntax: DVERIFY "{filename}"[,U{device#}][,D{drive#}] A special form: DVERIFY "*" can be used to test if the last program SAVEd is the same as the one currently in memory. To compare two disk program files, the following simple procedure (or equivalent in BASIC 2.0) can be used: DLOAD "{filename 1}" DVERIFY "{filename 2}" where {filename 1} and {filename 2} are the names of the two program files that you wish to compare. MONITOR-V The BASIC 7.0 MONITOR command contains the equivalent of the VERIFY command for use while in MONITOR mode. The syntax is: V "{filename}",{device#}[,{start address}] The optional {start address} parameter allows the comparison of a disk file with any area of memory starting at a location other than the normal load address of the disk file. This is especially useful for verifying relocatable machine language programs which may not normally reside in BANK 0. For example, V "APPLES",08,12000 will compare the disk file "APPLES" to the area of memory in BANK 1 beginning at $2000 (decimal 8192). Establishing the Link ===================== The second major use of a disk drive is for the storage and retrieval of data. This is a three step process, the first of which is establishing the communication link between the computer and the disk drive. In BASIC this is done with the OPEN, DOPEN or APPEND commands. One of these three commands must be used before any data can be sent to or read from a disk file. The maximum number of files which can be OPEN on the C-128 at any given time is ten. This is based on limitations of the computer. Of these, the maximum number of disk files that can be OPEN on a given disk drive is a total of 3 (SEQ or PRG or USR) files, or 1 REL file and 1 (SEQ or PRG or USR). In addition, the disk command channel can be OPEN simultaneously with any of the above combinations. This is based on limitations of the buffer space in the disk drive. OPEN OPEN is the most common command used to set up a file for subsequent input and/or output. For disk files, the syntax and usage is as follows: OPEN {file#},{device#},{channel#},"[{drive#}:]{filename}[,{type}] [,{mode}]" The {file#} is any number from 1 to 255 which must be unique for each file. (That is, no two OPEN files can have the same {file#}). This number is used to refer to the file during subsequent input and output operations. {file#} values of 128 or greater will add a linefeed (ASCII CHR$(10)) after each carriage return. Since this is generally not desirable for disk files, {file#} values of 127 or less are normally used. The {channel#} is equivalent to the secondary address used for opening files on other peripheral devices such as printers. It can generally be any number in the range of 0 to 15 with a few reserved codes which are used internally by the 1571 DOS for special functions. These are: 0 (to LOAD a PRG file or read the disk directory as a file), 1 (to SAVE a PRG file), and 15 (to OPEN the disk command channel). Since the {channel#} is used internally by DOS to allocate disk buffers, no two open disk files on the same device should have the same {channel#}. A common practice is to use the same value for {file#} and {channel#}. The {channel#} is used mainly for specifying BLOCK commands to the disk drive, as outlined in 1571-3.TXT (The 1571 Disk Operating System). The {type} specifies the kind of file that will be accessed and can be: P for a PRG file, S for SEQ, U for USR, or R for REL. If no {type} is specified for a read operation, OPEN will act on any type of file which matches the name (or the first match if wild cards are used). For a write file, a SEQ type is assumed if {type} is not specified. With the 1571 disk drive, the {mode} can be any one of: R for READ, W for WRITE, A for APPEND or M for MODIFY. The default is R. The A option allows you to add data to the end of an existing file, while M allows the recovery of data from a "splat" ("*") file. A special form of the OPEN command can be used for opening REL files for relative mode operations: OPEN {file#},{device#},{channel#},"{filename},L,"+CHR$({record length}) where {record length} is the length of the relative file record in bytes. This form of the command need only be used when first setting up the relative file. More details on the various types of files and how to use them can be found in 1571-5.TXT (Effective Use of Files). OPEN is available in all versions of Commodore BASIC. An example is: OPEN 1,8,9,"0:DATAFILE,S,W" will OPEN the new SEQ file "DATAFILE" for writing on device 8, drive 0, as logical file 1, with a disk channel number of 9. OPEN will accept variables and/or constants for any of the parameters. For example, OPEN X,Y,Z,"0:"+F$+",P,R" will OPEN the PRG file specified by the variable F$ for reading on the device specified by the value of variable Y, as logical file specified by the value of variable X on the disk channel specified by the value of varible Z. Several special forms of the OPEN command can also be used: OPEN 7,8,15,"{command string}" will OPEN the disk command channel on device 8 as logical file 7 and then send the command specified by "{command string}" to the disk drive. OPEN 1,8,0,"$0[:{pattern}]" will OPEN the disk directory as a file which can be read in subsequent GET#1's and INPUT#1's, just like any other file on the disk, optionally searching for a given filename or wildcard pattern. OPEN 2,8,4,"#[{n}]" will OPEN disk buffer {n} in the 1571's internal RAM for use by the BLOCK commands as logical file 2, disk channel 4. If {n} is not specified, DOS will assign the next available buffer. If a specific buffer is requested, but is not available, a DOS error code 70 "NO CHANNEL" will be issued. An example for a relative file would be: OPEN 3,8,3,"RELFILE,L,"+CHR$(25) This example indicates a record length of 25 characters. DOPEN The BASIC 3.5 and 7.0 version of the OPEN command is: DOPEN#{file#},"{filename},[{type}]"[,U{device#}][,D{drive#}][,W] The [,W] flag is used to indicate a write. If no file type is specified for a read operation DOPEN will open any type of file, while for a write operation, a SEQ file is assumed if none is specified. It should be noted that DOPEN cannot be used to a open a link to the disk command channel or a direct access disk buffer channel because it does not allow the explicit specification of a channel number. A channel number is chosen automatically by the C-128 operating system. An example would be: DOPEN#1,"DATAFILE,S",W This will DOPEN the SEQ file named "DATAFILE" as logical file 1, on the default disk drive, for writing. The second form of the DOPEN command is used specifically to create relative files: DOPEN#{file#},"{filename}",L{record size}[,U{device#}][,D{drive#] where {record size} specifies the length of the relative file record in bytes ranging from a minimum of 2 to a maximum of 254. For example: DOPEN#2,"RELFILE",L74 will DOPEN the relative file "RELFILE" with a record length of 74 bytes as logical file 2. For a more complete description of the use of relative files, see 1571-5.TXT (Effective Use of Files). APPEND APPEND is a modified form of the DOPEN command which allows you to add data to the end of an existing SEQ data file. This is very useful for expanding existing files without having to read in the entire existing file, write it back to a new file, then write the new data. An OPEN or DOPEN is not required to be used before an APPEND. The syntax is: APPEND#{file#},"{filename}"[,U{device#}][,D{drive#}] With the APPEND command, {filename} may contain wildcards and pattern matching characters. In such a case, the first file matching the pattern will be opened for appending data. For example: APPEND#3,"MORE DATA" will OPEN the file "MORE DATA" as logical file 3, to allow more data to be written to the end of the file. APPEND will only allow you to OPEN a file in write mode. Communicating ============= Once a disk file has been OPENed, the computer can communicate directly with the file by reading with a GET# or INPUT#, or writing data with a PRINT# as appropriate. GET# In BASIC, data can be read from a disk file only in program mode. One of two commands can be used. The first one acts on a single character at a time and has the following syntax: GET#{file#},{variable list} where {file#} is the file number used in the OPEN or DOPEN command for that particular file and {variable list} is a list of string variables to which the data bytes will be assigned. Note that there must not be a space between GET and #. Similar to the GET command for keyboard entry, one byte will assigned to each variable in the list. If no more bytes are in the file, a null byte ("") is returned. For example: GET#2, A$,B$,C$ will read the next three bytes from file 2 and assign them to A$, B$, and C$ respectively. When the end of the file has been reached, the system status variable (ST) will change from a value of 0 to 64. This can be used as a simple method for detecting the end of a file. GET# will not hang up or wait if it reaches the end of a file and cannot read a byte. INPUT# The second file reading command acts on a sequence of bytes, either in numeric form or as a character string. The syntax is: INPUT#{file#},{variable list} The parameters have the same meaning as those in the GET# command and, again, there is no space between the keyword and #. Similar to the INPUT command for keyboard entry, the {variable list} can contain any combination of numeric and string variables. However, the variable list must match the type of data in the disk file or a BASIC error code 22, FILE DATA, error will be generated. If a given string is longer than 160 characters (the length of BASIC's input buffer), a BASIC error code 23, STRING TOO LONG, error will result. Normally, the maximum length for a string is 255 characters. The length of a string in a disk file is determined by the presence and location of delimiters in the file such as carriage returns and commas. If the file data are not properly delimited, INPUT# may attempt to read more than 160 characters (80 characters on the C-64, 88 on the VIC-20) creating the above error. An example would be: INPUT#2, A,B$,C,D This will read the values of A, B$, C, and D from disk file 2. A, C, and D are numeric, while B$ is a character string. It should be noted that unlike the GET# command, if there is not enough data left in the file to satisfy all of the variables in the list or the data are not properly delimited, INPUT# may hang up and wait forever for data which will not come. Because of this, INPUT# should only be used on a file containing known data. GET# should be used on unknown files. Proper delimitation of disk files is discussed in detail in 1571-5.TXT (Effective USe of Files). PRINT# Data can be written to a disk file in both immediate and program mode using the PRINT# command. This is the opposite of INPUT# and will work with any combination of single characters, numerics or strings. The syntax is: PRINT#{file#},{variable list} The parameters are the same as for GET# and INPUT#. Similar to INPUT#, the variable list may contain any combination of string and numeric variables. The list may also contain string or numeric constants. For example: PRINT#1,A;B$;255;"MORE TEXT" will print the numeric data specified by A, the character string specified by B$, followed by the number 255 and the text string "MORE TEXT". If A=-2 and B$="SOME TEXT" then the data will look like this on the disk: -2 SOME TEXT 255 MORE TEXT where is the carriage return character (ASCII CHR$(13)). Print formatting functions, such as TAB(x), , etc., do not work properly with disk files. However, formatted output can be achieved using a form of BASIC 7.0's PRINT USING command. The syntax is: PRINT#{file#},USING"{definition string}";{variable list} A "{definition string}" is generally a series of "#" characters, each of which represents one numeric or character position. A decimal point can be used in the # string for numeric output to specify the placement of the decimal point in the output. An equal ("=") sign will centre a string in the field specified by the "#"'s, while ">" will right justify it. Both symbols count as an extra character space, just like an extra "#". For example: PRINT#1,USING "=#########";"TEXT" will centre the word "TEXT" in a 10 character field and send the 10 character string to file 1. Any other character in the definition string will be printed as a literal. The "PRINT#, USING;" statement can be used to delimit data by using a comma "," or carriage return in the definition string. The definition string can either be a constant as shown above, or a variable enclosed in parentheses such as: PRINT#1,USING(A$);"TEXT","NAME",255,27 By defining A$ as "######"+CHR$(13), a carriage return will be automatically inserted between data items. Note that multiple items in a data list for PRINT#,USING; are separated by commas. PRINT#,USING; is not available with BASIC 2.0. CMD Data can also be written to a disk file by redirecting the normal screen output to an open file. The BASIC command for output redirection to a peripheral device is: CMD{file#} where {file#} is any open output file. All output which normally goes to the screen, such as from a PRINT statement or a LIST command, will be sent to the specified file. An exception to this is DIRECTORY and CATALOG. These do not allow redirection of the output from the screen. (Because Commodore computers do not buffer the serial port, you cannot read and write to two different files or devices on the serial port simultaneously.) The following example will create a sequential file listing from any program currently in memory in text form which can be incorporated into a document with a word processor. (This technique was used extensively in the preparation of this document for adding the numerous program listings to the text.) OPEN 1,8,8,"LISTING,S,W" CMD 1 LIST PRINT#1:CLOSE1 RECORD The final communications type command applies to relative files only. The RECORD statement is used to position the relative file pointers to the correct record and, optionally, byte number within the record. The syntax is: RECORD#{file#},{record#}[,{byte#}] The {record#} can range from 1 to 65535, while {byte#} can range from 1 to 254. However, {byte#} cannot be greater than the record length specified when the file was opened. If {record#} is greater than the last record in the REL file, a DOS error code 50, RECORD NOT PRESENT, error will be generated. If writing the record, this is not really an error, just an indication that a new record is being created and the REL file is growing. An example would be: RECORD#2,45,12 This will position the relative file pointers for previously OPENed logical file 2, at record #45, byte 12. The data can then be read with INPUT# or GET# or written with a PRINT#. Commodore recommends that the RECORD command be given once before and again after attempting to read or write a relative file. This is probably essential before writing data to maintain file integrity. RECORD is not available with BASIC 2.0. For a more complete description of the creation, use and maintenance of all types of disk files, see 1571-5.TXT (Effective Use of Files). Breaking the Connection ======================= After all input and output has been performed on a file, it must be properly closed before the job is complete. This is especially important after writing to a file because the directory entry for the file will not contain the correct information about the file until after it has been closed and you could lose all of your data into a "splat" file. CLOSE CLOSE is the most common command for closing disk files. The command can be used either in immediate mode or from within a program. The syntax and usage is as follows: CLOSE {file#} closes the logical file specified by {file#}. This number will correspond to the logical file number under which the file was originally OPENed. The file can be an input or output file to a disk drive or any of the other devices such as cassette, printer, keyboard, etc. CLOSE acts on a single file only. For example: CLOSE 4 will CLOSE logical file 4. DCLOSE The BASIC 3.5 and 7.0 command: DCLOSE [U{device#}] will close all open files on the specified device, while the command: DCLOSE#{file#} closes the specified logical disk file. For disk files, it performs the same function as the CLOSE {file#} command. For example: DCLOSE will CLOSE all OPEN files (including the command channel) on device 8, drive 0. DCLOSE#4 performs the same function as CLOSE 4. DCLEAR The final closure command in BASIC 7.0 will close all disk files on the specified device and drive, then initialize the drive to its power up condition. The form of this command is: DCLEAR [U{device#}][,D{drive#}] This is similar to the DOS "I0" command discussed in 1571-3.TXT (The 1571 Disk Operating System), except that OPEN files are properly CLOSEd. Utility Commands ================ BASIC 3.5 and 7.0 contain a number of utility commands which simplify the processes of copying, renaming and deleting files; reading disk directories; formatting new disks; etc. They are presented here in alphabetical order. These commands are not available in BASIC 2.0. However, the 1571 disk operating system supports commands to perform equivalent functions. These are described in greater detail in 1571-3.TXT (The 1571 Disk Operating System). BACKUP As its name might suggest, the BACKUP command is provided to make an exact duplicate of an entire source disk on a target disk. However, it only works with a dual disk drive and, as such, is not relevant for the 1571. (At one point, Commodore had planned to release a dual drive version of the 1571, dubbed the 1572. This command would have been used with that drive.) It is, however, included here for completeness. The syntax is: BACKUP D{source drive#} TO D{target drive#}[,U{device#}] The C-128 will prompt with the message "ARE YOU SURE?". Type in Y to proceed or any other entry to abort. BACKUP cannot be used with two single drives. It produces a DOS error code 31, SYNTAX ERROR, on the 1571. CATALOG and DIRECTORY BASIC 3.5 and 7.0 provide two commands for displaying the disk directory. The syntax for both CATALOG and DIRECTORY is identical, and the commands can be used interchangeably. Take your pick. They can be used either in immediate mode or from within a program. Unlike the BASIC 2.0 directory read method (LOAD"$",8), CATALOG and DIRECTORY do not overwrite the program space in RAM. Similar to the BASIC 2.0 method, both commands will also display the disk name and the number of blocks free. The syntax for the commands is: CATALOG ["{pattern}"][,U{device#}][,D{drive#}] (or DIRECTORY) The "{pattern}" parameter allows the searching for certain filenames and/or file types. For example, CATALOG "MINE" will list only the file named "MINE", if it exists, while CATALOG "M*" will list all files beginning with the letter M. Multiple patterns can also be searched, such as: CATALOG "A*,B*,C*" will display all files beginning with either A, B, or C. The pattern can also include the file type to be searched. CATALOG "*=S" will display all of the SEQ (sequential) files on the disk. In the case of multiple pattern searches, only one file type can be searched. For example, CATALOG "A*,B*,C*=P" is valid, while CATALOG "A*=S, B*=P" is not. The valid file types for pattern searching are: S for SEQ, P for PRG, U for USR, and R for REL. Either the full (e.g. SEQ) or abbreviated (S) types can be used. Currently, the only way to produce a hard copy of a directory listing on a printer is with the BASIC 2.0 method LOAD"$",8 described previously. COLLECT The COLLECT command is provided to "cleanup" the disk block allocation map (BAM) which keeps track of used disk space. It is equivalent in function to the DOS VALIDATE command discussed in 1571-3.TXT (The 1571 Disk Operating System). On a heavily used disk, especially one which contains improperly closed files, this may free up some extra disk space for use. The syntax is: COLLECT [U{device#}][,D{drive#}] When the command has been issued, the computer will suspend operation until the cleanup has been completed. This may take several minutes or more, depending on how much of the disk has been used. COLLECT can be used either in program or immediate mode. Unlike the DOS VALIDATE command, COLLECT will cause the computer to suspend operation until it has completed its task. COLLECT should not be used on GEOS disks, disks with a BOOT sector in use, or double sided disks in a 1541 (or a 1571 in 1541 mode) because each of these contain special flag values which will be destroyed by the action of the COLLECT command. More on this can be found in section 5.2.7. CONCAT CONCAT will concatenate (join) two disk files by appending one to the end of the other. The syntax is: CONCAT "{second filename}"[,D{second drive#}] TO "{first filename}"[,D{second drive#}][,U{device#}] The file specified under "{second filename}" remains unchanged on the disk by the procedure, while "{first filename}" contains its original data followed by a copy of the data from "{second filename}". For example: CONCAT "DATAFILE2" TO "DATAFILE1" will join the data in "DATAFILE2" to the end of "DATAFILE1". The original "DATAFILE2" will remain on the disk intact. CONCAT works in both immediate mode and program mode with either SEQ or USR files. COPY The COPY command can be used for creating an exact copy of a file on the same disk (or on a second disk with a dual drive unit). The syntax is: COPY [D{source drive#}]"{source filename}" TO [D{target drive#}]"{target filename}"[,U{device#}] where the "source" refers to the disk file being copied from and the "target" is the new copy being made. The COPY command is an excellent way to create multiple backup copies of a file on a disk. Since it works both in immediate mode and program mode, COPY can be automated in a short program such as the following: 10 INPUT"FILE TO COPY FROM";F$ 20 INPUT"NUMBER OF COPIES TO MAKE";N 30 FOR I=1 TO N 40 F2$=STR$(I)+"."+F$ 50 COPY (F$) TO (F2$) 60 NEXT This program will automatically make N copies of any file which you specify, each stored under a slightly different filename such as: "1.DATAFILE"; "2.DATAFILE"; "3.DATAFILE", etc. HEADER When a disk is first unpacked from a brand new box, it cannot be used immediately. The magnetic surface of the disk must be organized into packets called tracks and sectors that the disk drive can use for storing data. (Although you cannot see them with the eye, or even with a microscope, the formatted disk has a series of magnetic "marks" on its surface which divides it into easily recognizable areas for the disk controller.) This is generally called "formatting" a disk. With BASIC 3.5 or 7.0, it is done with the HEADER command: HEADER "{disk name}"[,I{disk ID}][,U{device#}][,D{drive#}] "{disk name}" is a general name for the disk, a sort of "volume label". It is the heading which appears in reverse characters at the beginning of a displayed disk directory. The {disk ID} is a secondary identifier for the disk. It can be any two character string and is used by the internal operating system of the 1571 to help keep track of whether or not a disk has been changed. It can also be used as a unique disk identifier for many disk cataloging programs. Because the {disk ID} is used by the operating system to distinguish between different disks, each of your disks should be given a different ID code (in theory anyway) to avoid the possibility of mixups, especially when writing to a disk. Once a disk has been formatted with a given ID code, the code cannot be changed. The ID code is written into the header bytes of every sector on the disk. These bytes cannot be changed by the user without totally erasing the data on the disk. If the {disk ID} parameter is omitted, only the directory and BAM sectors of the disk are reformatted (i.e erased). This is usually called a "short format" and is a quick way to erase old disks that have been previously formatted but you wish to re-use. When operating in immediate mode, the C-128 will prompt with an "ARE YOU SURE?" message before it executes the HEADER command. No prompt appears in program mode. For both modes, the C-128 will suspend operation and wait for approximately 45 seconds, for a full format, until the disk drive has finished its task. For example: HEADER "MY DISK",ID 2K,U9 will format the disk in device 9 and give it the name "MY DISK" with an ID code of "2K". HEADER "MY SECOND DISK" will erase the disk directory and BAM of a previously formatted disk and rename it "MY SECOND DISK". The ID code remains unchanged. In addition, although the actual data are still on the disk they cannot be accessed without a sector editor because the directory and BAM have been destroyed. RENAME RENAME allows you to change the name under which a file appears in the disk directory. The syntax is: RENAME "{old filename}" TO "{new filename}" [,U{device#}][,D{drive#}] RENAME works with all file types in BASIC 3.5 or 7.0 in either immediate or program modes. Only the entry in the disk directory is changed, the file itself remains the same. For example: RENAME "APPLES" TO "ORANGES" will change the name of the file "APPLES" to "ORANGES". SCRATCH The final utility command is SCRATCH. The function of this often used command is to erase a file from the disk directory. The syntax is: SCRATCH "{pattern}"[,U{device#}][,D{drive#}] "{pattern}" can be a single file name, or a series of names represented by wildcard entries or multiple names separated by commas. Similar to the HEADER command, BASIC will prompt with the "ARE YOU SURE?" message before actually SCRATCHing the files. Some examples are: SCRATCH "BAD FILE" will erase the specified file from the directory. SCRATCH "A*" will erase all filenames that begin with the letter "A" from the directory. SCRATCH "ABC,FILE1,TES*" will erase the filenames "ABC" and "FILE1", along with all filenames beginning with the letters "TES". The computer will suspend operation until the SCRATCH has been completed. After the files have been deleted, a message will be displayed similar to: x FILES SCRATCHED where x is the number of files it has deleted. Files created with certain names (often under error conditions) can be difficult to get rid of. A typical example involves an error in an OPEN statement that creates a file with the single character name such as a single quote mark ("), ":" (a colon) or "," (a comma). The simplest way to SCRATCH a file of this type is to use pattern matching characters, such as: SCRATCH "?" Other non-standard characters, such as shifted letters or graphics symbols may also cause similar problems when SCRATCHing. Before doing a SCRATCH this way, however, you should make sure that there are no other files on the disk which match the pattern. If there are, you must RENAME these files or else they will be SCRATCHed as well. It should be noted that the files themselves have not actually been deleted, only a flag set in the directory entry to indicate a scratched file. Although the disk space for the deleted files is also de-allocated, the disk file can still be recovered in most cases with fairly simple techniques, such as the C-128 DOS shell "UNSCRATCH" function. A file should be unscratched immediately if it has been accidentally SCRATCHed, and certainly before new data is written to the same disk. Failure to do so immediately may result in the irretrievable loss of some data as its disk space is re-used by other files. Error Handling ============== With BASIC 3.5 or 7.0's error detecting and correcting routines, you can recover from most errors without crashing. There are two error detection methods available in BASIC 3.5 and 7.0, one for disk errors and the other for BASIC errors. DS and DS$ Disk errors can be conveniently detected using the reserved variables DS, DS$ and ST. DS contains the error code of the most recent disk access and DS$ contains the text description of the error. DS and DS$ depend only on the status of the last disk access, not the drive number, device number or file number where the error was caught. A list of DOS error codes can be found in 1571-A.TXT. DS and DS$ remain at their error values until the next disk access is attempted. A simple statement such as: 10 IF DS THEN PRINT "DISK ERROR" DS$ will detect a disk error. DS and DS$ can be used either in program mode or direct mode, you do not need to open the disk command channel (#15) first. (With the C-64 and VIC-20, it was not possible to read the disk error channel in direct mode without a DOS wedge). In immediate mode, a simple PRINT DS$ will print the error message on the screen. In BASIC 2.0, the disk error status can normally only be read in program mode or through the use of a DOS utility wedge. As a matter of good programming practice, you should read the disk error channel when ever you perform normal disk operations, such as OPEN, INPUT#, GET#, PRINT#, BLOAD, etc. The only exception is after issuing a burst mode command to the 1571 drive with a PRINT# statement. This may cause your program to crash because reading the error channel cancels the burst mode commands by temporarily commandeering the command channel and issuing a different direct access command to the drive. Reading DS or DS$ will also turn off the flashing error light on the disk drive. In program mode, the BASIC 2.0 method of reading the disk error channel works equally as well on the C-128 with both BASIC and machine language routines. ST BASIC has another reserved varible, ST (or system status) which can be used in conjunction with disk files. The value of this variable reflects the results of the last attempted input or output operation. A value of 0 indicates success, while any other value could indicate an error condition. ST can have a range of values depending on which error bits are set. For serial port input and output (including disk operations), the ST bit pattern is outlined in Table 4. The most common use of ST is to check for the end of a file being read with a series of GET#'s. For example, the following short program will read a file then exit when it gets to the end: 10 OPEN 1,8,8,"DATAFILE" 20 GET#1,A$:PRINT A$; 30 IF ST=64 THEN CLOSE#1:END 40 GOTO 20 ST can also be used with machine language routines. The KERNAL READSS function at $FFB7 (decimal 65453) will return the most recent value of the status byte in the .A register. The ST value is also stored at RAM location $90 (decimal 144) for all Commodore machines. TRAP BASIC 3.5 and 7.0 support a command to divert program flow to a specific sub-routine if an error is encountered during execution. To enable BASIC error detection, your program needs a statement such as: 10 TRAP xx where xx is the first line of your error handling routine. The TRAP statement should be near the beginning of the program or major subroutine that you want to protect from error crashing. More than one TRAP statement can be included in a program, but only the most recently encountered one will be active. Thus you can have different error handling routines for different sections of your program. Error trapping is disabled with the statement: 100 TRAP with no line number specified. When an error is detected, the program flow is diverted to the error handling routine mentioned in the TRAP statement, just as if a GOTO had been encountered. Once in the error routine, you can determine the nature and location of the error using the reserved variables ER and EL. ER contains a numerical code corresponding to the type of error that was encountered. The disk and file related error codes are listed in 1571-A.TXT. Some of the errors, such as a SYNTAX ERROR, cannot be corrected unless you edit the program. Others, such as FILE NOT FOUND can usually be corrected by specifying a new value for a given variable. A text description of the error can be read with the function ERR$(ER). For example, to detect a FILE NOT FOUND error, you would use an expression such as: 10 IF ER=4 THEN PRINT ERR$(4).... etc. where .... etc represents your additional code. ER and ERR$() can be used in direct mode with a PRINT ER or PRINT ERR$(ER) statement. The HELP command can be used in direct mode to list the line where the error occured and highlight the error causing portion in a multi-statement line. If HELP is used in program mode, execution will stop and the error line will be listed with the error highlighted. The key can be detected with TRAP and ER. It has been assigned an error code of 30. The reserved variable EL contains the line number where the error occured. If the error occured in direct mode, EL will have a value of 65535. To detect any error in a given line, say line 100, of your program, the error routine would contain a line such as: 20 IF EL=100 THEN PRINT "ERROR IN LINE 100".... etc. Two caveats should be mentioned about using EL and ER in programs. The line number referenced in an EL statement will not be renumbered when you use the RENUMBER command, so check all the EL's after renumbering a program. The second drawback is that you cannot TRAP an error within the error routine itself. TRAP is disabled until control is returned to the main program. This brings up the next item of discussion: error recovery and returning control to the main program. An error detection routine would not be much use if you could not correct the error or at least return to the normal execution of the program. The error correction depends on the specific application and may involve setting default values for parameters or printing an error message and asking for a new input etc. Returning to the main BASIC program is done with one of the following statements: 100 RESUME 110 RESUME NEXT 120 RESUME xx where xx is the line number to continue with. With the first form, BASIC will try to re-execute the statement where the error occured. In the second form, BASIC will execute the statement immediately following the one where the error was encountered. In the third form, the program will resume execution at the specified line number. Until one of the RESUME statements is encountered, BASIC disables further error trapping. Thus if a second error occurs during the error handling routine, the program may crash. RESUME will not purge the stack of the most recently unused GOSUB, FOR-NEXT, DO-LOOP, etc. parameters before returning control to the specified line, so be careful of nested subroutines and loops. An error trapping routine may have more than one RESUME statement: 100 IF EL=100 THEN RESUME 10 120 IF ER=4 THEN RESUME NEXT etc. This helps in directing the flow of the program back to the specific area required after detecting and/or correcting the error. It also minimizes the chance of crashing during error trapping by allowing you to perform error correction outside of the main error detection routine. After the execution of the RESUME statement, ER is set to a value of -1 and EL is reset to 65535, both indicating a no error condition. Error Priorities In reviewing the list of error codes for both BASIC and DOS, you may have noticed that some of them are the same. What happens in such cases? The first level of error detection is always with BASIC. Thus if you do not have a TRAP statement, and the BASIC error is encountered, the program will crash. For example, a "FILE NOT FOUND" error (BASIC error #4 and DOS error #62) should be handled by a TRAP statement. However, to turn off the blinking error light on the disk drive, you must also read the disk error channel with a statement such as: 50 ZZ=DS TABLES: Table 1: Abbreviations used in BASIC 3.5 and 7.0 disk commands Letter Meaning Comments B BANK denotes the bank number (0 to 15) on the C-128 from which memory is saved or into which a disk file is loaded D DRIVE denotes a drive number (0 or 1) of a dual disk drive. Must be 0 for a 1571 single drive L LENGTH denotes the record length in bytes for REL files P POSITION denotes the start or finish position for a memoery load or save operation U UNIT denotes the device (unit) number for a disk drive. Usually 8 or 9. Always 8 if you have only one disk drive. ==================== Table 2: BASIC workspace pointers Computer Start of BASIC Pointer End of BASIC Pointer Vic-20, C-64 $2b-$2c $2d-$2e SX-64, C-16 (43-44 dec) (45-46 dec) Plus/4 C-128, C-128D $2d-$2e $1210-$1211 (45-46 dec) (4624-4625 dec) All pointers are in lo byte-hi byte format. ===================== Table 3: Noteworthy C-128 Memory Areas in Bank 0/Bank 15 Hex Decimal Comments 0400-07ff 1024-2047 40 col text memory 0b00-0bff 2816-3071 cassette buffer 0c00-0cff 3072-3327 RS-232 input buffer 0d00-0dff 3328-3583 RS-232 output buffer 0e00-0fff 3584-4095 sprite definitions 1000-10ff 4096-4351 function key definitions 1300-1bff 4864-7167 unused (good area for short ML programs) 1c00-1fff 7168-8191 320 x 200 graphics color map 2000-3fff 8192-16383 320 x 200 graphics bit map ====================== Table 4: Values for system status variable ST Bit ST Value Comment 0 0 all OK, no error 0 1 no response while writing data (disk drive won't acknowledge) 1 2 no response while reading data (disk drive won't send data) 4 16 VERIFY error 6 64 EOF (end of read file) 7 128 device not present =======================