CHAPTER 1 THE CENTRAL INPUT/OUTPUT UTILITY, (CIO) The ATARI computer uses a very easy-to-use input and output system called the Central Input/Output utility, or CIO. Nearly all input or output passes through this utility. CIO uses eight "channels" as paths for I/O. There are not really separate channels for I/O but the computer acts as if there were. Each channel is controlled by a 16 byte block of memory called an Input/Output Control Block or IOCB. The channels are used by putting the proper numbers in the proper IOCB bytes then jumping to the CIO routine. In BASIC, complete I/O operations can be as easy as typing a command such as LPRINT. In this case BASIC does all the work for you. THE CIO CHANNELS There are eight CIO channels, numbered from 0 to 7. In BASIC some channels are reserved for BASIC's use. BASIC CIO channel assignments Channel 0 Permanently assigned to the screen editor 6 Used for graphics commands 7 Used for the Cassette, disk and printer Channels 6 and 7 are free to use when they are not being used by BASIC. With machine language, all of the channels are available to the programmer. THE IOCB STRUCTURE The IOCB for channel zero starts at address $0340 (decimal 832). This is the only address you need to know. Indexing from this address is used to find all of the other bytes. Below are the names and uses of the IOCB bytes. IOCB bytes and uses: ADDRESS NAME EXPLANATION $0340 ICHID handler Identifier $0341 ICDNO device number (disk) $0342 ICCOM command $0343 ICSTA status $0344 ICBAL buffer address (low byte) $0345 ICBAH buffer address (high byte) $0346 ICPTL address of put byte $0347 ICPTH routine (used by BASIC) $0348 ICBLL buffer length (low byte) $0349 ICBLH buffer length (high byte) $034A ICAX1 auxiliary information $034B ICAX2 - $034C ICAX3 the remaining auxiliary $034D ICAX4 bytes are rarely used $034E ICAX5 - $034F ICAX6 - ICHID When a channel is open, the handler I.D. contains an index to the handler table. The handler table (to be discussed later) holds the address of the device handling routines. When the channel is closed ICHID contains $FF. ICDNO The device number is used to distinguish between multiple devices with the same name, such as disk drives. ICCOM The command byte tells CIO what operation to perform. CIO command codes HEX DEC +Open $03 3 +close $0C 12 get $07 7 put $09 11 input $05 5 print $09 9 +status request $0D 13 +*special >$0D >13 + command may be made to a closed channel * device specific commands ICSTA The status byte contains an error code if something goes wrong. If bit 7 is 0 there have been no errors. ICBAL and ICBAH Before a channel is opened, the buffer address bytes are set point to the block of memory which contains the name of the device the channel is to be opened to. Before actual input or output these bytes are set to point to the block of memory where the I/O data is stored or is to be stored. ICPTL and ICPTH The put routine pointer is set by CIO to point to the handlers' put-byte routine. When the channel is closed the pointer points to the IOCB-closed routine. This pointer is only used by BASIC. ICBLL and ICBLH The buffer length bytes show the number of bytes in the block of memory used to store the input or output data. (See ICBAL and ICBAH.) If the amount of data read during an input operation is less than the length of the buffer, the number of bytes actually read will be put in ICBLL and ICBLH by CIO. ICAX1 through ICAX6 The auxiliary information bytes are used to give CIO or the device any special information needed. OPENNING A CIO CHANNEL Before using a CIO channel it must be assigned to an I/O device. In machine language you start by putting the channel number in the four high bits of the 6502 X register (X = $30 for channel three). Next you place the necessary codes (parameters) into IOCB 0 indexed by X. The X register will cause the numbers to be offset in memory by 16 times the channel number. This puts the numbers into the correct IOCB instead of IOCB 0. Below are the parameters used to open a channel. Channel-open parameters: ICCOM open code ICBAL address of device name ICBAH in memory ICAX1 direction code ICAX2 zero The direction code byte in ICAX1 takes on the following format: ICAX1 format for opening a channel 7 6 5 4 3 2 1 0 ----------------- ICAX1 | W R | ----------------- 8 4 2 1 W 1 = open for output (write) R 1 = open for input (read) ICAX1 may have the following data CIO direction codes HEX DEC operation $04 4 input $08 8 output $0C 12 input and output (cannot change the length of a disk file) ICBAL and ICBAH point to the device name stored in memory. The device and file name must be followed by 0 or $9B (decimal 155). Once the parameters are set, jumping (JSR) to the CIO vector (CIOV) at address $E456 (58454) will cause the channel to be opened. In the following example a basic knowledge of assembly language is assumed. Routine to open channel 1 to the keyboard: ICHID = $0340 ICCOM = ICHID+2 ICAX1 = ICHID+10 ICAX2 = ICHID+11 IOCB1 = $10 channel in four high bits CIOV = $E456 OPEN = $03 OREAD = $04 ;open for input ERROR = (address of error handling routine) ; START LDX IOCB1 LDA OPEN STA ICCOM,X LDA NAME STA ICBAH,X LDA OREAD STA ICAX1,X LDA #0 STA ICAX2,X JSR CIOV BPL OK JMP ERROR ; NAME .BYTE "K:",$9B OK (program continues here) To open a CIO channel in BASIC the OPEN command is used. BASIC OPEN command format: OPEN #channel,aux1,aux2,device:file name aux1 = direction code aux2 = special code To open channel 1 to the keyboard in BASIC Type: OPEN #1,4,0,"K:" The third parameter, aux2, is a rarely used special parameter. One use is to keep the screen from erasing when changing graphics modes. The fourth parameter is the device to open the channel to. It may be either a string in quotes or a string variable. CIO device names C cassette recorder *D disk drive E screen editor K Keyboard P printer *R RS 232 I/O port S screen handler * Uses a non-resident handler loaded by the device at power-up. The device name must usually be followed by a colon. With the disk drive a file name is expected after the device name. The screen handler is used for graphics. The screen editor uses both the keyboard handler and the screen handler to work between the keyboard and screen. USING AN OPEN CHANNEL Once a channel is opened to a device you have several options: INPUT: (ICCOM = $05) The computer reads data from the device until a carriage-return is read (decimal number 155, hex $9B) or the end of the file (EOF) is reached. A carriage return is also known as an End-Of-Line or EOL. The IOCB input parameters are: IOCB input parameters: ICCOM get record code ICBAL address of buffer to ICBAH store the data in ICBLL length of the data ICALH buffer The following routine demonstrates the input command in assembly language. Some of the equates are in the channel openning example above. Input routine: GETREC = $05 BUFF = (address to store data at) BUFLEN = (number of bytes available at storage address) : LDX IOCB1 LDA GETREC STA ICCOM,X LDA < BUFF STA ICBAL,X LDA > BUFF STA ICBAH,X LDA < BUFLEN STA ICBLL,X LDA > BUFLEN STA ICBLH,X JSR CIOV BPL OK2 JMP ERROR : OK2 (continues if no errors) If the data retrieved is shorter than the prepared buffer, the number of bytes actually read will be put into ICBLL and ICBLH. In BASIC, the INPUT command is used. BASIC INPUT command format: INPUT #channel,string variable or INPUT #channel,arithmetic variable For example: INPUT #1,IN$ The above commands will cause the data from the device to be put into the specified buffer (IN$ in the BASIC example) until an EOL is reached. If the INPUT statement is used again, without closing the channel, the computer will get more data from the device until another EOL is read or the end of the file is reached. The new data will write over the old data in the input string or buffer. If an arithmetic variable is used, only numbers can be input. PRINT: (ICCOM = $09) In assembly language the print command is identical to the input command. The only difference is that the PUTREC code ($09) is stored in ICCOM. Of course the buffer bytes of the IOCB then specify the block of memory to be output from rather than input to. With the print command, EOLs within the string or buffer are ignored but an EOL is placed at the end of the data when sent to the device. In BASIC, the PRINT command is used like INPUT except you want to use a semicolon instead of a comma to separate parameters. For example: PRINT #1;OUT$ or PRINT #1;"HELLO" If you use a comma, ten space characters will be sent before the string. If the print command is used again, without closing the channel, the new data will be appended to the end of the data previously sent. Old data will not be written over. GET: (ICCOM = $07) In BASIC this command inputs a single byte of data from the device. EOLs are ignored. In BASIC, GET is used like INPUT except an arithmetic variable must be used. For example: GET #1,IN If the get command is used again the next byte from the device will be read. If the end of a file is reached an error will occur. There is no command in BASIC to input an entire file without stopping at each EOL. If you wish to ignore EOLs while reading a file to a string, you must use the GET command. Each byte of data is then put into the string by the program. EXAMPLE: 10 OPEN #1,4,0,"D:TEST" 20 TRAP 60:REM GOES TO LINE 60 WHEN END OF FILE ERROR OCCURS 30 GET #1,IN 40 IN$(LEN(IN$)+1)=CHR$(IN) 50 GOTO 30 60 CLOSE #1 In assembly language, the get command can be used to get any number of bytes from the device. It works just as INPUT does except EOLs are ignored. IOCB get-byte parameters: ICCOM get-character (single byte) code ICBAL \ ICBAH same as in input ICBLL ICBAH / Other than the ICCOM code (GETCHR = $07) this command is identical to the input command. PUT: (ICCOM = $0B) In BASIC, PUT is the opposite of GET. It outputs a single byte from a variable to the device. PUT is used the same as GET. For example: PUT #1,OUT In assembly language, the command byte of the IOCB is loaded with the put-character code (PUTCHR = $0B). Otherwise the PUT command is identical to GET. CLOSING A CHANNEL Closing a channel frees it for use by another device or for changing parameters. In assembly language the close code is put into the command byte of the IOCB then the CIOV call is made. IOCB close command: CLOSE = $0C : LDX IOCB1 LDA CLOSE STA ICCOM,X JSR CIOV In BASIC, use the CLOSE command followed by the channel number. CLOSE #1 With the disk drive, the file name is not put into the directory until the channel is closed. THE DEVICE TABLE CIO uses a jump table located at $031A (794). When a CIO call is made, CIO searches the table for the one-byte device name. The two bytes following the device name contain the address of the device handler's vector table. CIO searches the device table from the end, $033D (829) to the beginning. This way, if a custom handler has ben substituted for a resident handler, the custom handler will be found first. (custom handlers cannot be inserted directly in the place of resident handlers in the device table.) Each handler has its' own vector table. This vector table is 16 bytes long. The two-byte vectors point to the various handler routines. The vectors are stored in the vector table in the following order: Handler vector table order open close get byte put byte get stat special JMP init code (3 bytes) The open routine should validate the ICAX parameters and check for illegal commands. The close routine should send any remaining data in the buffer to the device, mark the End-Of-File and update any directories, etc. The get byte routine should get a byte from the device or the handler buffer and put it in the 6502 A register. Handlers with long timouts must monitor the break key flag and put a $80 in the 6502 Y register if the [BREAK] key is pressed. The put byte routine should send the byte in the 6502 A register to the device or handler buffer. If the buffer fills, it should be sent to the device. BASIC can call the put byte routine without using CIO. The get status routine may get 4 bytes of status information from the device and put them in DVSTAT [$02EA] to DVSTAT+3. For special commands the handler must examine the command byte and find the proper routine entry point. In all cases the status (error code) of the operation should be put in the 6502 Y register. To be compatible with all versions of the operating system, the handler must redirect DOSINI [$000C,2 (12)] for initialization upon reset. This initialization must restore the vectors in the handler vector table and jump to the origional DOSINI vector. SPECIAL COMMANDS Some devices have special CIO commands. These are known as device specific commands. In assembly language these commands are executed just as any other CIO command is. In BASIC the XIO command is used. An example of the XIO command is: XIO command code #channel,aux1,aux2,device:file name To open a channel with the XIO command instead of the OPEN command use: XIO 3 #1,4,0,"K:" Note that the above command is identical to the OPEN command except "XIO 3" is used instead of "OPEN". Also note that $03 is the IOCB open code for ICCOM. Useful database variables and OS equates DOSINI $000C,2 (12): initialization vector BRKKEY $0011 (17): break key flag ICHID $0340 (832): start of IOCBs ICDNO $0341 (833): ICCOM $0342 (834): ICSTA $0343 (835): ICBAL $0344 (836): ICBAH $0345 (837): ICPTL $0346 (838): ICPTH $0347 (839): ICBLL $0348 (840): ICBLH $0349 (841): ICAX1 $034A (842): ICAX2 $034B (843): HATABS $031A,16 (794): device handler table CIOV $E456 (58454): CIO entry vector