IOCB Structure
Input/Output Control Block (IOCB) structure and usage reference.
Overview
Atari's CIO (Central Input/Output) uses IOCBs to remember everything about an open "file/device handle" — what device it is, its status, where the buffer is, etc.
There are 8 IOCBs, numbered 0-7. Each IOCB is 16 bytes long.
IOCB Addresses
IOCB 0 starts at address $0340 (decimal 832). Each subsequent IOCB is 16 bytes later:
- IOCB 0: $0340-$034F (832-847)
- IOCB 1: $0350-$035F (848-863)
- IOCB 2: $0360-$036F (864-879)
- IOCB 3: $0370-$037F (880-895)
- IOCB 4: $0380-$038F (896-911)
- IOCB 5: $0390-$039F (912-927)
- IOCB 6: $03A0-$03AF (928-943)
- IOCB 7: $03B0-$03BF (944-959)
IOCB Byte Layout
IOCB 1 Layout (848-863)
Here's what each byte means for IOCB 1 (most commonly used):
| Addr (dec) | Addr (hex) | Name | Meaning |
|---|---|---|---|
| 848 | $0350 | ICHID | Handler ID (0 = closed, nonzero = open) |
| 849 | $0351 | ICDNO | Device number (R1:, D2:, etc) |
| 850 | $0352 | ICCOM | CIO command code (OPEN, GET, PUT, CLOSE, STATUS…) |
| 851 | $0353 | ICSTA | Status from last CIO operation (success or error code) |
| 852 | $0354 | ICBAL | Buffer address (low byte) |
| 853 | $0355 | ICBAH | Buffer address (high byte) |
| 854 | $0356 | ICPTL | Current data pointer (low byte) |
| 855 | $0357 | ICPTH | Current data pointer (high byte) |
| 856 | $0358 | ICBLL | Buffer length (low byte) |
| 857 | $0359 | ICBLH | Buffer length (high byte) |
| 858 | $035A | ICAX1 | AUX1 (your OPEN 2nd parameter → 12) |
| 859 | $035B | ICAX2 | AUX2 (your OPEN 3rd parameter → 0) |
| 860 | $035C | ICAX3 | AUX3 (device-specific) |
| 861 | $035D | ICAX4 | AUX4 (device-specific) |
| 862 | $035E | ICAX5 | AUX5 (device-specific) |
| 863 | $035F | ICAX6 | AUX6 (device-specific) |
IOCB Field Descriptions
ICHID (Handler Identifier)
When a channel is open, the handler I.D. contains an index to the handler table. The handler table holds the address of the device handling routines. When the channel is closed ICHID contains $FF.
After OPEN #1,12,0,"R:":
- ICHID becomes non-zero → "this channel is open"
ICDNO (Device Number)
The device number is used to distinguish between multiple devices with the same name, such as disk drives.
- R1: = device number 1
- D2: = device number 2
ICCOM (Command)
The command byte tells CIO what operation to perform.
Common commands:
- $03 = OPEN
- $05 = GET RECORD (INPUT)
- $07 = GET CHARACTER
- $09 = PUT RECORD (PRINT)
- $0B = PUT CHARACTER
- $0C = CLOSE
- $0D = STATUS
ICSTA (Status)
ICSTA (IOCB status byte) is the result code from the last CIO operation done on that IOCB.
Location: 851 decimal = $0353 (for IOCB1)
Meaning:
- 0 = OK / Success - If the last CIO call worked, PEEK(851) will almost always be 0
Non-fatal / end-of-data:
- 136 ($88) = End of File (EOF) - You'll hit this reading disk files
- 137 ($89) = Truncated record / line too long - Typical when using record/line input and the buffer was too short
Fatal errors (128-255):
- Bad IOCB / channel not open
- Device/handler not found
- Bad command
- Invalid parameter
- Timeout
- Device NAK / not responding
- Framing / overrun errors (serial)
Interpreting ICSTA:
' Simple check S = PEEK(851) IF S = 0 THEN ? "OK" ELSE ? "ERROR/STATUS="; S ' With EOF handling S = PEEK(851) IF S = 0 THEN ? "OK" IF S = 136 THEN ? "EOF" IF S > 127 AND S <> 136 THEN ? "ERROR="; S
ICBAL and ICBAH (Buffer Address)
Before a channel is opened, the buffer address bytes are set to 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.
Reading buffer address:
BUF = PEEK(852) + 256*PEEK(853) ' ICBAL + ICBAH*256
For some devices (including many R: handlers), these might be 0 or point to an internal buffer depending on how that handler implements I/O.
ICPTL and ICPTH (Put Routine Pointer)
The put routine pointer is set by CIO to point to the handler's put-byte routine. When the channel is closed the pointer points to the IOCB-closed routine. This pointer is only used by BASIC.
Reading pointer:
PTR = PEEK(854) + 256*PEEK(855) ' ICPTL + ICPTH*256
ICBLL and ICBLH (Buffer Length)
The buffer length bytes show the number of bytes in the block of memory used to store the input or output data. 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.
Reading buffer length:
LEN = PEEK(856) + 256*PEEK(857) ' ICBLL + ICBLH*256
ICAX1 through ICAX6 (Auxiliary Bytes)
The auxiliary information bytes are used to give CIO or the device any special information needed.
After OPEN #1,12,0,"R:":
- ICAX1 (858) becomes 12 (because you passed 12)
- ICAX2 (859) becomes 0
Inspecting IOCB1
OPEN #1,12,0,"R:" FOR I=848 TO 863 ? I, PEEK(I) NEXT I
Why IOCBs Exist
CIO needs a per-channel "state block" so it can do:
GET #1,A$ PUT #1,"HELLO" CLOSE #1
...without you having to re-describe the device every time.
Channel Usage
BASIC Channel Assignments
| Channel | Assignment |
|---|---|
| 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.
Common Patterns
Checking if Channel is Open
IF PEEK(848) <> 255 THEN ? "Channel 1 is open"
Reading Status
STATUS #1, ST IF PEEK(851) = 0 THEN ? "Last operation succeeded"
Getting Buffer Information
BUF_ADDR = PEEK(852) + 256*PEEK(853) BUF_LEN = PEEK(856) + 256*PEEK(857) ? "Buffer at "; BUF_ADDR; " length "; BUF_LEN
Related Topics
- CIO Reference - Central I/O operations
- OS Equates - Status codes and command codes
- Statements - FORGE I/O statements