forge Documentation

iocb-structure

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)NameMeaning
848$0350ICHIDHandler ID (0 = closed, nonzero = open)
849$0351ICDNODevice number (R1:, D2:, etc)
850$0352ICCOMCIO command code (OPEN, GET, PUT, CLOSE, STATUS…)
851$0353ICSTAStatus from last CIO operation (success or error code)
852$0354ICBALBuffer address (low byte)
853$0355ICBAHBuffer address (high byte)
854$0356ICPTLCurrent data pointer (low byte)
855$0357ICPTHCurrent data pointer (high byte)
856$0358ICBLLBuffer length (low byte)
857$0359ICBLHBuffer length (high byte)
858$035AICAX1AUX1 (your OPEN 2nd parameter → 12)
859$035BICAX2AUX2 (your OPEN 3rd parameter → 0)
860$035CICAX3AUX3 (device-specific)
861$035DICAX4AUX4 (device-specific)
862$035EICAX5AUX5 (device-specific)
863$035FICAX6AUX6 (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

ChannelAssignment
0Permanently assigned to the screen editor
6Used for graphics commands
7Used 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