Chapter Twelve
I/O and You


Types of I/O Devices

Many kinds of I/O devices can be connected to your Atari computer. But there are seven specific kinds of devices that can be addressed in both Atari BASIC and Atari assembly language using specific procedures and specific commands. Each of these seven types of devices has a unique one letter abbreviation, or device name, by which it can be addressed in both Atari BASIC and Atari assembly languages. These seven types of devices, and their corresponding device names in both BASIC and assembly language are:

c12_ataricomponents.jpg

Note the colon following the letter in each of these abbreviations. The colon is an integral part of each device name, and may not be omitted.

The Eight Atari I/O Operations

In both Atari BASIC and Atari assembly language, there are eight I/O operations that can be performed using the seven abbreviations, or device names, listed above. These eight I/O operations are:

How Device Names and I/O Operations are Used Together

In both Atari BASIC and Atari assembly language, all of the I/O operations listed earlier are designed to be performed using a centralized peripheral interface system called the Central I/O Utility, or CIO. The Atari CIO system, like most peripheral interface systems, is designed to handle sequences of data bytes called files. A file may contain data, text, or both, and it may or may not be arranged by records, strings of text or data separated by end of line characters (ATASCII code $9B). Some files, such as files recorded on disks, can be given individual names (such as "D1:TESTIT.SRC). Other files, such as those used with the Atari screen editor or line printer, do not have individual names, but are addressed simply by the name of the device on which they appear, for example, "E:" or "P:"

Both Atari BASIC and Atari assembly language allow programmers to access up to eight different devices and/or files at the same time. In both BASIC and assembly language, this access is provided via eight dedicated blocks of memory that are called Input/Output Control Blocks, or IOCBS. In Atari Assembly language, just as in Atari BASIC, the eight IOCBs are numbered from 0 to 7. In both assembly language and BASIC, any free IOCB number can be assigned to any I/O device, although IOCB #0 is always assigned to the screen editor when an Atari computer is first turned on, and is the screen editor's default IOCB number.

Opening a Device

In both Atari BASIC and Atari assembly language, I/O devices are assigned IOCB numbers when they are first addressed, or opened. When a device is first opened for either read or write operations, an IOCB number must be assigned to it. Once an IOCB number has been assigned to a device, the device can be referred to by that number until a command to close the device is issued. Once a device is closed, the IOCB number that was assigned to it becomes free again, and can be used to open any other device in your computer system.

Assembly Language Lacks IOCB Commands

In Atari BASIC, specific commands are provided to open, close, read from and write to any I/O devices that may be connected to a computer. No such commands exist in 6502 assembly language. The IOCB system used in Atari computers does provide the assembly language programmer with a means of handling all of the I/O devices that can be connected to an Atari computer. It can handle it in a way that is relatively easy to manage and easy to understand.

Opening a Device Using Atari BASIC

It is not difficult to open a device or a file using Atari BASIC. To open a device or a file, all a BASIC programmer has to do is write a line using the following formula.

The following is an example of an Atari BASIC statement written using the standard IOCB formula.

As you can see, there are five components in an OPEN statement in Atari BASIC: The OPEN command itself, a series of three parameters separated by commas, and a device name plus a file name, if applicable. A mandatory "#" mark appears before the first parameter after the OPEN statement and the device name is followed by a mandatory colon. In addition, the device name and the file name, if applicable, are enclosed in mandatory quotation marks. The meanings of the five components of an OPEN statement are explained below.

  1. "OPEN" - the OPEN command.

  2. "#n" (#2 in the sample statement above)-The IOCB number. This number, as we have pointed out, ranges from 0 through 7. "#2" in this position means "IOCB #2."

  3. "n1" (8 in our example)-A code number for a specific type of input or output operation. In our sample OPEN statement, the "8" in this position is the code number for an output (open for write) operation.

  4. "n2" (O in our sample statement)-A device dependent auxiliary code sometimes used for various purposes (in this case, though, not used).

  5. "filespec"-A device name plus a file name, if applicable. In our example, "D1:TESTIT.BAS" refers to a file called TESTIT.BAS which our computer will expect to find stored on a disk in disk drive 1.

How BASIC Processes an "OPEN" Command

When your computer encounters an OPEN command while processing a BASIC program, it carries out a series of standardized operations using the values in each of the four parameters of the OPEN statement. When all of those operations are completed, BASIC jumps to a special OS subroutine called the CIO vector, or CIOV. The CIOV subroutine then automatically opens the device in question, referring to the parameters that were contained in the OPEN statement (and are now stored in certain memory locations) in order to make sure that the proper device is opened for the kind of access called for in the OPEN statement.

Advantages of Assembly Language I/O Operations

To understand how a device is opened using Atari assembly language, it's helpful to know how devices are opened using Atari BASIC. That's because BASIC programs and assembly language programs open devices in exactly the same way. The only difference is that when you open a device using BASIC, your BASIC interpreter does most of the work for you. When you use assembly language, you have to do all of the work yourself. Fortunately, there's a payoff for doing all of this extra work. When you control your system's CIO system using assembly language, you have a lot more control over the system than you do when you allow BASIC to do all the work.

Opening a Device Using Assembly Language

Now let's take a look at exactly how devices are opened, read from, written to and closed, in both Atari BASIC and Atari assembly language.

Another Look at IOCBs

As we've pointed out, the I/O operations of an Atari computer are controlled using a series of eight I/O control blocks, or IOCBS. Each of these I/O control blocks is an actual block of memory in your computer. Each IOCB is 16 bytes long, and each byte in each IOCB has a specific name and a specific function. Moreover, each byte in each IOCB has the same name, and performs the same kind of function, as the corresponding byte in every other IOCB. That's important, so let's say it again in a different way: Each byte in each IOCB in your computer has the same name, and performs the same kind of function, as the byte with the same offset in each other IOCB.

Indirect Addressing in IOCB Operations

The reason this fact is important is that indirect addressing is used quite often in IOCB operations. Indirect addressing is a technique in which a memory location is sought out by means of an offset value stored in the 6502 processor's X or Y register. Since the offsets of all of the bytes in all Atari IOCBs correspond to each other, that makes the indirect addressing mode very easy to use in Atari IOCB operations.

The 16 Bytes of an IOCB

This concept is much easier to understand when examples are given. So an actual assembly language program will be used to explain the Atari I/O system. If this program looks familiar, that's because it's almost exactly like the one you were asked to type in back in Chapter 7. It is the same one we used to print a message on the screen. If you still have that program stored on a disk, you can load it into your computer, and with just a few changes, you can turn it into an exact replica of the program below. That way you won't have to type it all over again.

PROGRAM FOR PRINTING ON THE SCREEN

PRNTSC.SRC

10 ;
20  .TITLE "PRNTSC ROUTINE"
30  .PAGE "ROUTINE FOR PRINTING ON THE SCREEN"
40 ;
50  *=$5000
60 ;
70 BUFLEN=255 ;(EXPANDED BEYOND PREVIOUS LIMITS)
80 ;
90 EOL=$9B;ATASCII CODE FOR END OF LINE CHARACTER
0100 ;
0110 OPEN=$03 ;TOKEN FOR OPENING A DEVICE OR FILE
0120 OWRIT=$0B ;TOKEN FOR "OPEN FOR WRITE OPERATIONS"
0130 PUTCHR=$0B ;TOKEN FOR "PUT CHARACTER"
0140 CLOSE=$0C ;TOKEN FOR CLOSING A DEVICE
0150 ;
0160 IOCB2=$20 ;OFFSET FOR IOCB NO.2
0170 ICCOM=$342 ;COMMAND BYTE (CONTROLS CIO OPERATIONS)
0180 ICBAL=$344 ;BUFFER ADDRESS (LOW BYTE)
0190 ICBAH=$345 ;BUFFER ADDRESS (HIGH BYTE)
0200 ICBLL=$348 ;BUFFER LENGTH (LOW BYTE)
0210 ICBLH=$349 ;BUFFER LENGTH (HIGH BYTE)
0220 ICAX1=$34A ;AUXILIARY BYTE NO.1
0230 ICAX2=$34B ;AUXILIARY BYTE NO.2
0235 ;
0240 CIOV=$E456 ;CIO VECTOR
0250 ;
0260 DEVNAM .BYTE "E:",EOL
0270 ;
0280 OSCR ;OPEN SCREEN ROUTINE
0290  LDX #IOCB2
0300  LDA #OPEN
0310  STA ICCOM,X
0320 ;
0330  LDA #DEVNAM&255
0340  STA ICBAL,X
0350  LDA #DEVNAM/256
0360  STA ICBAH,X
0370 ;
0380  LDA #OWRIT
0390  STA ICAX1,X
0400  LDA #0
0410  STA ICAX2,X
0420  JSR CIOV
0430 ;
0440  LDA #PUTCHR
0450  STA ICCOM,X
0460 ;
0470  LDA #TXTBUF&255
0480  STA ICBAL,X
0490  LDA #TXTBUF/256
0500  STA ICBAH,X
0510  RTS
0520 ;
0530 PRNT
0540  LDX #IOCB2
0550  LDA #BUFLEN&255
0560  STA ICBLL,X
0570  LDA #BUFLEN/256
0580  STA ICBLH,X
0590  JSR CIOV
0600  RTS
0605 ;
0610 CLOSED
0620  LDX #IOCB2
0630  LDA #CLOSE
0640  STA ICCOM,X
0650  JSR CIOV
0660  RTS
0680 TXTBUF=*
0690 ;
0700  *=*+BUFLEN
0710 ;
0720  .END

Download / View (Assembly source code)

"PRNTSC.SRC," Line by Line

Now we'll take a good close look at this program and see how it works, line by line. We'll start with the first three lines of the program, lines 290 through 310.

Initializing a Device for "OPEN"

Substitute literal numbers for the variables in these three lines, and this is how they will read.

These three instructions are all it takes to open a device in Atari assembly language. In order to understand what they do, you have to know something about the structure of an Atari IOCB. As we've pointed out, there are eight IOCBs in your Atari's operating system, and each one contains 16 bytes (or $10 bytes in hexadecimal notation). That means that to address IOCB #1, you have to add 16 (or $10) bytes to the address of IOCB #0 and to address IOCB #2, you have to add 32 (or $20) bytes to the address of IOCB #0. In other words, when you use the address of IOCB #0 as a reference point (as the Atari CIO system does), the offset you have to use is 32 in decimal notation, or $20 using the hexadecimal system. Here are all of the IOCB offsets used, in the Atari CIO system:

The Eight Atari IOCB Offsets

IOCBO=$00      IOCB4=$40
IOCBI=$10      IOCB5=$50
IOCB2=$20      IOCB6=$60
 IOCB3=$30      IOCB7=$70 

Now let's take another look at our literal value version of the first three lines of the PRNTSC.SRC program:

Now you can begin to see why the number $20 has been loaded into the X register in line 300. Obviously, it's going to be used as an offset in line 320, but before we move on to line 320, let's take a look at line 310, the line in between. In line 310, the accumulator is loaded with the number $03-which has been identified back in line 110 of the program as the "token for opening a device." Now what does that mean?

I/O Tokens

Well, in the Atari CIO system, each of the eight I/O operations described at the beginning of this chapter can be identified by a one-digit (hex) code, or token. Here is a complete fist of those tokens, and the operations for which they stand.

Token   Name    Function 

$03     OPEN    Open a specified device or file.
$04     OREAD   Open a device or file for read operations.
$08     OWRITE  Open a device or file for write operations.
$05     GETREC  Read a record from a specified device or file.
$07     GETCHR  Read character from specified device or file.
$09     PUTREC  Write a record to a specified device or file.
$OB     PUTCHR  Writ character from specified device or file.
$OC     CLOSE   Close a specified device or file. 

Line 310 Explained

Now you can see what happens in line 310 of the program PRNTSC.ASM. The accumulator is loaded with the number $03, the token for "OPEN". In line 320, the OPEN token is stored in the indirect acddress ICCOM,X (or $342,X). Just what is this address?

ICCOM is the name of one of the 16 bytes in an IOCB. Specifically, ICCOM is the first byte (the zero offset byte) in every IOCB. Look at line 170 of the PRNTSC.ASM program and you'll see that ICCOM is located at memory address $342, and is identified as the "command byte" in the Atari CIO system. It is called the command byte because it is the byte that must be addressed when devices are to be initialized, opened or closed. ICCOM is the byte that points to a set of subroutines in your computer's operating system that perform all of those functions.

IOCB Addresses

Since we have listed all of the Atari I/O devices, I/O commands, I/O offsets and I/O operation codes so far, we might as well provide a list of ICCOM and the rest of the 16 bytes in each of your computer's IOCBS. Here is a complete list of the bytes in each IOCB.

Byte     Adrs   Name                  Function 

ICHID    $0340  Handler I.D.          Preset by OS
ICDNO    $0341  Device Number         Preset by OS
ICCOM    $0342  Command Byte          Controls CIO operations
ICSTK    $0343  Status Byte           Returns status of operations
ICBAL    $0344  Buffer Address, Low   Holds address of text buffer
ICBAH    $0345  Buffer Address, High  Holds address of text buffer
ICFITL   $0346  Unused Pointer        Not used in programming
ICPTH    $0347  Unused Pointer        Not used in programming
ICBLL    $0348  Buffer Length, Low    Holds length of text buffer
ICBLH    $0349  Buffer Length, High   Holds length of text buffer
ICAXI    $034A  Auxiliary Byte No. 1  Picks write or read operation
ICAX2    $034B  Auxiliary Byte No. 2  Used for various purposes
ICAX3    $034C  Auxiliary Byte No. 3  Used by OS only
ICAX4    $034D  Auxiliary Byte No. 4  Used by OS only
ICAX5    $034E  Auxiliary Byte No. 5  Used by OS only
ICAX6    $034F  Auxiliary Byte No. 6  Used by OS only 

Now you can understand the operation performed in lines 300 through 320 of the PRNTSC.SRC program.

In line 290, the X register is loaded with the offset for IOCB #2: the number $20. In line 300, the accumulator is loaded with the token for the OPEN operation: the number $03. In line 310, the token of the OPEN operation (the number $03) is stored in ICCOM,X: the command byte of IOCB #2. After a few more operations, we're going to issue a "JSR CIOV" (jump to SubRoutine) statement, so our Atari will jump to the CIO vector and open IOCB #2, as we have instructed. But first, we're going to have to set a few more parameters, so our computer will know exactly what kind of operations to open IOCB #2 for. So let's zip right through the rest of this "OPEN" operation now.

In lines 330 through 360, the text buffer in IOCB #2 is loaded with the address of a variable defined in line 260 as DEVNAM. The variable DEVNAM, as you can see by looking at line 260 contains the ATASCII code for the character string "E: " the device name for the Atari screen editor. We could have opened IOCB #2 for any other I/O device in exactly the same way. If we wanted to use IOCB #2 as a printer IOCB, for example, we could have written line 260 this way:

Then in lines 330 through 360, the address of the ATASCII string "P:",EOL would be loaded in ICRAL,X. With that tiny change, the PRNTSC program, instead of opening your computer screen as an output device, would open your printer! You can also use this same programming procedure to open a specific file on a disk so that you can read from it or write to it, on either a character-by-character or a record-by-record basis. In the PRNTSC program, we could open a disk file instead of the screen editor by changing line 260 to read something like this:

Then, instead of opening the screen editor, our program would open the disk file TESTIT.BAS (provided, of course, that there was a disk drive connected to our computer and that all other necessary conditions for opening such a file existed). We have just seen two examples of the tremendous power of the Atari CIO system. While the system may seem complex at first glance, its incredible versatility is a real testament to the programming know-how of Atari's computer designers.

Moving Along

Let's continue on now with our "OPEN" operation. In lines 390 and 400, we load the number $08 the token for "open a device for a write operation" into Auxiliary Byte No. 1 of IOCB #2. We could make our program do something completely different if we stored the value $04, the token for "open read," in ICAXL,X instead of the value $08, the token for "open write" That's another demonstration of the versatility of the Atari CIO system.

We have now read lines 410 and 420, in which we clear Auxiliary Byte No. 2 of IOCB #2 (a byte that is not used in this routine) by stuffing it with a zero. Finally, in line 430, we jump to the Atari CIO vector at memory address $E456. With that operation, we have opened IOCB #2 for a write operation to the Atari screen editor. In other words, we have opened IOCB #2 to print on the screen.

Printing a Character

We have not yet actually printed a character on the screen, however. To do that, we must carry out two more sequences of I/O operations. Now that you understand how the Atari CIO system works, that will be a snap. Look at lines 450 through 610 of the PRNTSC.ASM program.

In lines 450 and 460, we store the number $0B, the token for a "put character" operation, into the command byte of IOCB #2. In lines 480 through 520, the address of the text buffer we have created especially for this program is stored in the buffer address bytes of IOCBC#2. That prepares us for the PRNT routine that starts at line 540. In the PRNT routine, which extends from line 540 to line 610, the length of our specially created text buffer is stored in the buffer length bytes of IOCB #2. Then there is another jump to the CIO vector, which automatically takes care of printing the text in the PRNTSC text buffer on your computer screen.

Closing a Device

When you open a device in assembly language (as in Atari BASIC), you must close it when you're finished with it. Otherwise, you'll cause an IOCB error, and that could cause some serious problems.

Forgetting to carry out such tasks as closing IOCBs (at the time they should be closed) can lead to program crashes and long and agonizing debugging sessions. Anyway, IOCB #2 is closed in this version of the PRNTSC program. in Lines 630 through 680, the value of $OC-the token for closing a file-is loaded into ICCOM,X. Then there's a jump to CIOV, and the Atari OS closes the IOCB.

This ends our brief glimpse into the intricacies of the central input/output system of Atari computers. But we have by no means exhausted that topic; much more information on Atari I/O is available in more advanced books than this one, and in technical reference manuals.


Return to Table of Contents | Previous Chapter | Next Chapter