Introduction
The explorer names the addresses below in the disassembly of an Atari program and of a disk’s
boot code: sta $d01a reads sta COLBK, jsr $e456 reads
jsr CIOV. The names are the ones of the Atari Operating System User’s Manual and
the usual equates files (Mapping the Atari uses the same names). Only documented
addresses are named. Zero page from $80 up is free for programs (BASIC uses it) and
is not labelled.
The tables were checked against two sources that are independent of this page: the register
names in the comments and constants of the atari5200 emulator’s source (29 names compared),
and the jump table and handler tables in the AltirraOS ROMs, where every named entry point holds a
jump into the ROM. The comparison is the test test-atari8-labels.mjs; the descriptions
were not checked by it.
The same register can have one name when written and another when read, because the chip uses
the address for two jobs. The disassembly cannot tell a read from a write, so such an address is
named WRITE/READ, the write name first. Each chip’s registers repeat
(“mirror”) through its page: GTIA every 32 bytes through $D0FF, POKEY
every 16 bytes through $D2FF, the PIA every 4 bytes through $D3FF and
ANTIC every 16 bytes through $D4FF. Only the first copy is named.
ANTIC, $D400
| Address | Name | What |
|---|---|---|
$D400 | DMACTL | DMA control: playfield width, player and missile DMA, display list DMA (shadow SDMCTL) |
$D401 | CHACTL | Character control: blank, invert, reflect (shadow CHACT) |
$D402 | DLISTL | Display list pointer, low byte (shadow SDLSTL) |
$D403 | DLISTH | Display list pointer, high byte (shadow SDLSTH) |
$D404 | HSCROL | Horizontal fine scroll |
$D405 | VSCROL | Vertical fine scroll |
$D407 | PMBASE | High byte of the player and missile base address |
$D409 | CHBASE | High byte of the character set base address (shadow CHBAS) |
$D40A | WSYNC | Write: wait for the end of the scan line (halts the CPU) |
$D40B | VCOUNT | Read: the vertical line counter divided by two |
$D40C | PENH | Read: light pen horizontal position |
$D40D | PENV | Read: light pen vertical position |
$D40E | NMIEN | Write: NMI enable, bit 7 display list interrupt, bit 6 vertical blank |
$D40F | NMIRES/NMIST | Write: reset the NMI status. Read: NMI status |
GTIA, $D000
| Address | Name | What |
|---|---|---|
$D000 | HPOSP0/M0PF | Write: horizontal position of player 0. Read: collision of missile 0 with the playfields |
$D001 | HPOSP1/M1PF | Write: horizontal position of player 1. Read: collision of missile 1 with the playfields |
$D002 | HPOSP2/M2PF | Write: horizontal position of player 2. Read: collision of missile 2 with the playfields |
$D003 | HPOSP3/M3PF | Write: horizontal position of player 3. Read: collision of missile 3 with the playfields |
$D004 | HPOSM0/P0PF | Write: horizontal position of missile 0. Read: collision of player 0 with the playfields |
$D005 | HPOSM1/P1PF | Write: horizontal position of missile 1. Read: collision of player 1 with the playfields |
$D006 | HPOSM2/P2PF | Write: horizontal position of missile 2. Read: collision of player 2 with the playfields |
$D007 | HPOSM3/P3PF | Write: horizontal position of missile 3. Read: collision of player 3 with the playfields |
$D008 | SIZEP0/M0PL | Write: width of player 0. Read: collision of missile 0 with the players |
$D009 | SIZEP1/M1PL | Write: width of player 1. Read: collision of missile 1 with the players |
$D00A | SIZEP2/M2PL | Write: width of player 2. Read: collision of missile 2 with the players |
$D00B | SIZEP3/M3PL | Write: width of player 3. Read: collision of missile 3 with the players |
$D00C | SIZEM/P0PL | Write: width of the missiles. Read: collision of player 0 with the other players |
$D00D | GRAFP0/P1PL | Write: graphics of player 0. Read: collision of player 1 with the other players |
$D00E | GRAFP1/P2PL | Write: graphics of player 1. Read: collision of player 2 with the other players |
$D00F | GRAFP2/P3PL | Write: graphics of player 2. Read: collision of player 3 with the other players |
$D010 | GRAFP3/TRIG0 | Write: graphics of player 3. Read: joystick trigger 0 (shadow STRIG0) |
$D011 | GRAFM/TRIG1 | Write: graphics of the missiles. Read: joystick trigger 1 (shadow STRIG1) |
$D012 | COLPM0/TRIG2 | Write: colour of player and missile 0 (shadow PCOLR0). Read: trigger 2 |
$D013 | COLPM1/TRIG3 | Write: colour of player and missile 1 (shadow PCOLR1). Read: trigger 3 |
$D014 | COLPM2/PAL | Write: colour of player and missile 2 (shadow PCOLR2). Read: television standard (the low nibble is 1 on PAL and 15 on NTSC) |
$D015 | COLPM3 | Colour of player and missile 3 (shadow PCOLR3) |
$D016 | COLPF0 | Colour of playfield 0 (shadow COLOR0) |
$D017 | COLPF1 | Colour of playfield 1 (shadow COLOR1) |
$D018 | COLPF2 | Colour of playfield 2 (shadow COLOR2) |
$D019 | COLPF3 | Colour of playfield 3 (shadow COLOR3) |
$D01A | COLBK | Colour of the background (shadow COLOR4) |
$D01B | PRIOR | Priority selection and GTIA graphics modes (shadow GPRIOR) |
$D01C | VDELAY | Vertical delay of players and missiles |
$D01D | GRACTL | Graphics control: enable players, missiles and the trigger latch |
$D01E | HITCLR | Write: clear the collision registers |
$D01F | CONSOL | Console: write bit 3 clicks the speaker; read the Start, Select and Option keys |
POKEY, $D200
| Address | Name | What |
|---|---|---|
$D200 | AUDF1/POT0 | Write: frequency of audio channel 1. Read: paddle 0 |
$D201 | AUDC1/POT1 | Write: control and volume of channel 1. Read: paddle 1 |
$D202 | AUDF2/POT2 | Write: frequency of channel 2. Read: paddle 2 |
$D203 | AUDC2/POT3 | Write: control and volume of channel 2. Read: paddle 3 |
$D204 | AUDF3/POT4 | Write: frequency of channel 3. Read: paddle 4 |
$D205 | AUDC3/POT5 | Write: control and volume of channel 3. Read: paddle 5 |
$D206 | AUDF4/POT6 | Write: frequency of channel 4. Read: paddle 6 |
$D207 | AUDC4/POT7 | Write: control and volume of channel 4. Read: paddle 7 |
$D208 | AUDCTL/ALLPOT | Write: audio control (clocks, linked channels, filters). Read: the paddle scan state |
$D209 | STIMER/KBCODE | Write: restart the timers. Read: the last key code |
$D20A | SKREST/RANDOM | Write: reset the serial status. Read: a random number |
$D20B | POTGO | Write: start the paddle scan |
$D20D | SEROUT/SERIN | Write: serial output byte. Read: serial input byte |
$D20E | IRQEN/IRQST | Write: interrupt enable (shadow POKMSK). Read: interrupt status |
$D20F | SKCTL/SKSTAT | Write: serial port and keyboard control (shadow SSKCTL). Read: serial port and keyboard status |
PIA, $D300
| Address | Name | What |
|---|---|---|
$D300 | PORTA | Port A: joysticks 0 and 1 (on the 400 and 800, 2 and 3 on the other port) |
$D301 | PORTB | Port B: joysticks 2 and 3 on the 400 and 800; on the XL and XE the memory configuration (OS ROM, BASIC, banks) |
$D302 | PACTL | Port A control |
$D303 | PBCTL | Port B control (the SIO command line) |
OS entry points and handler tables
The jump table from $E450 holds three-byte jmp instructions, so the
addresses stay the same in every OS revision while the routines behind them move. The handler tables
are six vectors (each the routine address minus one) and then an initialisation routine.
| Address | Name | What |
|---|---|---|
$E400 | EDITRV | Handler table of the screen editor (E:) |
$E410 | SCRENV | Handler table of the screen (S:) |
$E420 | KEYBDV | Handler table of the keyboard (K:) |
$E430 | PRINTV | Handler table of the printer (P:) |
$E440 | CASETV | Handler table of the cassette (C:) |
$E450 | DISKIV | Disk handler initialisation |
$E453 | DSKINV | Disk interface: the disk handler entry |
$E456 | CIOV | Central input/output utility: X = IOCB number times 16 |
$E459 | SIOV | Serial input/output utility: the device control block (DCB, $0300) says what to do |
$E45C | SETVBV | Set the system timers and the vertical blank vectors |
$E45F | SYSVBV | Vertical blank immediate routine (jump here from the VVBLKI vector) |
$E462 | XITVBV | Exit vertical blank routine (jump here to finish a vertical blank routine) |
$E465 | SIOINV | SIO initialisation |
$E468 | SENDEV | Send enable routine |
$E46B | INTINV | Interrupt handler initialisation |
$E46E | CIOINV | CIO initialisation |
$E471 | BLKBDV | Blackboard (memo pad) mode |
$E474 | WARMSV | Warm start entry |
$E477 | COLDSV | Cold start entry |
$E47D | RBLOKV | Cassette read block |
$E480 | CSOPIV | Cassette open for input |
CPU vectors
| Address | Name | What |
|---|---|---|
$FFFA | NMIVEC | Non-maskable interrupt vector (the OS ROM points it at its NMI handler) |
$FFFC | RESETVEC | Reset vector |
$FFFE | IRQVEC | Interrupt request and BRK vector (the OS ROM points it at its IRQ handler) |
Zero page ($00–$7F)
| Address | Name | What |
|---|---|---|
$08 | WARMST | Warm start flag: 0 after power-up, non-zero after a reset |
$09 | BOOT? | Boot status: bit 0 a disk boot succeeded, bit 1 a cassette boot |
$0A | DOSVEC | The address DOS is started at (low byte; the DOS run vector) |
$0B | DOSVEC+1 | DOSVEC, high byte |
$0C | DOSINI | DOS initialisation address (low byte), called at reset |
$0D | DOSINI+1 | DOSINI, high byte |
$0E | APPMHI | Upper limit of application memory (low byte) |
$0F | APPMHI+1 | APPMHI, high byte |
$10 | POKMSK | Shadow of IRQEN: the POKEY interrupts that are enabled |
$11 | BRKKEY | Break key flag: 0 when the Break key was pressed |
$12 | RTCLOK | Real-time clock, high byte (counts the vertical blanks: 60 a second NTSC, 50 PAL) |
$13 | RTCLOK+1 | Real-time clock, middle byte |
$14 | RTCLOK+2 | Real-time clock, low byte |
$42 | CRITIC | Critical section flag: non-zero stops the deferred vertical blank and the timers |
$4D | ATRACT | Attract mode timer and colour mask: counts up; above 127 the colours cycle |
$4E | DRKMSK | Attract mode luminance mask |
$4F | COLRSH | Attract mode colour shift |
$52 | LMARGN | Left margin of the text screen |
$53 | RMARGN | Right margin of the text screen |
$54 | ROWCRS | Cursor row |
$55 | COLCRS | Cursor column (low byte) |
$56 | COLCRS+1 | Cursor column, high byte |
$57 | DINDEX | Current screen mode number |
$58 | SAVMSC | Address of the screen memory (low byte) |
$59 | SAVMSC+1 | SAVMSC, high byte |
$6A | RAMTOP | The number of RAM pages: the high byte of the top of RAM (a mode 0 screen is just below it) |
Page 2: shadow registers, vectors and variables
A shadow register is a copy in RAM that the operating system writes to the chip at the
next vertical blank, so a program sets COLOR4 rather than COLBK; a
program that writes the chip register directly changes it at once but loses it at the next blank.
| Address | Name | What |
|---|---|---|
$0200 | VDSLST | Display list interrupt vector (low byte) |
$0201 | VDSLST+1 | VDSLST, high byte |
$0202 | VPRCED | Serial I/O proceed line vector (low byte) |
$0204 | VINTER | Serial I/O interrupt line vector (low byte) |
$0206 | VBREAK | BRK instruction vector (low byte) |
$0208 | VKEYBD | Keyboard interrupt vector (low byte) |
$020A | VSERIN | Serial input data ready vector (low byte) |
$020C | VSEROR | Serial output data needed vector (low byte) |
$020E | VSEROC | Serial output complete vector (low byte) |
$0210 | VTIMR1 | POKEY timer 1 interrupt vector (low byte) |
$0212 | VTIMR2 | POKEY timer 2 interrupt vector (low byte) |
$0214 | VTIMR4 | POKEY timer 4 interrupt vector (low byte) |
$0216 | VIMIRQ | Immediate IRQ vector (low byte) |
$0218 | CDTMV1 | System timer 1 (16-bit, counts down once a vertical blank) |
$021A | CDTMV2 | System timer 2 |
$021C | CDTMV3 | System timer 3 |
$021E | CDTMV4 | System timer 4 |
$0220 | CDTMV5 | System timer 5 |
$0222 | VVBLKI | Immediate vertical blank vector (low byte) |
$0223 | VVBLKI+1 | VVBLKI, high byte |
$0224 | VVBLKD | Deferred vertical blank vector (low byte) |
$0225 | VVBLKD+1 | VVBLKD, high byte |
$022A | CDTMF3 | System timer 3 expired flag |
$022C | CDTMF4 | System timer 4 expired flag |
$022E | CDTMF5 | System timer 5 expired flag |
$022F | SDMCTL | Shadow of DMACTL |
$0230 | SDLSTL | Shadow of the display list pointer DLISTL: the address of the display list (low byte) |
$0231 | SDLSTH | Shadow of DLISTH: the display list address, high byte |
$0232 | SSKCTL | Shadow of SKCTL |
$0234 | LPENH | Shadow of PENH |
$0235 | LPENV | Shadow of PENV |
$026F | GPRIOR | Shadow of PRIOR |
$0270 | PADDL0 | Shadow of paddle 0 |
$0278 | STICK0 | Joystick 0 (read from PORTA by the vertical blank routine) |
$0279 | STICK1 | Joystick 1 |
$027A | STICK2 | Joystick 2 |
$027B | STICK3 | Joystick 3 |
$0284 | STRIG0 | Shadow of trigger 0 (0 when pressed) |
$0285 | STRIG1 | Shadow of trigger 1 |
$0286 | STRIG2 | Shadow of trigger 2 |
$0287 | STRIG3 | Shadow of trigger 3 |
$02C0 | PCOLR0 | Shadow of COLPM0 |
$02C1 | PCOLR1 | Shadow of COLPM1 |
$02C2 | PCOLR2 | Shadow of COLPM2 |
$02C3 | PCOLR3 | Shadow of COLPM3 |
$02C4 | COLOR0 | Shadow of COLPF0 |
$02C5 | COLOR1 | Shadow of COLPF1 |
$02C6 | COLOR2 | Shadow of COLPF2 |
$02C7 | COLOR3 | Shadow of COLPF3 |
$02C8 | COLOR4 | Shadow of COLBK, the background colour |
$02E0 | RUNAD | The run address of a binary load file (low byte): DOS jumps through it when the load is finished |
$02E1 | RUNAD+1 | RUNAD, high byte |
$02E2 | INITAD | The initialisation address of a binary load file (low byte): DOS calls it after each segment |
$02E3 | INITAD+1 | INITAD, high byte |
$02E4 | RAMSIZ | The high byte of the RAM size |
$02E5 | MEMTOP | Top of available memory (low byte) |
$02E6 | MEMTOP+1 | MEMTOP, high byte |
$02E7 | MEMLO | Bottom of available memory (low byte) |
$02E8 | MEMLO+1 | MEMLO, high byte |
$02F0 | CRSINH | Cursor inhibit: non-zero hides the cursor |
$02F1 | KEYDEL | Key debounce delay counter |
$02F2 | CH1 | The previous key code, kept by the keyboard interrupt for debounce and key repeat |
$02F3 | CHACT | Shadow of CHACTL |
$02F4 | CHBAS | Shadow of CHBASE |
$02FC | CH | The last key pressed, as a keyboard code ($FF when there is none) |
$02FE | DSPFLG | Display control characters flag |
$02FF | SSFLAG | Start and stop flag: ctrl-1 freezes the screen |
Page 3: DCB, handler table and IOCBs
| Address | Name | What |
|---|---|---|
$0300 | DDEVIC | DCB: the bus ID of the device ($31 is disk drive 1) |
$0301 | DUNIT | DCB: the unit number |
$0302 | DCOMND | DCB: the command ($52 read sector, $50 put sector, $57 write sector, $53 status) |
$0303 | DSTATS | DCB: the direction ($40 data from the device, $80 data to it); after the call, the status |
$0304 | DBUFLO | DCB: the buffer address (low byte) |
$0305 | DBUFHI | DCB: the buffer address (high byte) |
$0306 | DTIMLO | DCB: the time-out in seconds |
$0307 | DUNUSE | DCB: unused |
$0308 | DBYTLO | DCB: the number of bytes to transfer (low byte) |
$0309 | DBYTHI | DCB: the number of bytes to transfer (high byte) |
$030A | DAUX1 | DCB: the first auxiliary byte (the sector number, low byte) |
$030B | DAUX2 | DCB: the second auxiliary byte (the sector number, high byte) |
$031A | HATABS | The handler address table: three bytes per device (name, table address) |
$0340 | ICHID | IOCB 0: handler ID |
$0341 | ICDNO | IOCB 0: device number |
$0342 | ICCOM | IOCB 0: command |
$0343 | ICSTA | IOCB 0: status |
$0344 | ICBAL | IOCB 0: buffer address, low byte |
$0345 | ICBAH | IOCB 0: buffer address, high byte |
$0346 | ICPTL | IOCB 0: put byte routine address minus one, low byte |
$0347 | ICPTH | IOCB 0: put byte routine address minus one, high byte |
$0348 | ICBLL | IOCB 0: buffer length, low byte |
$0349 | ICBLH | IOCB 0: buffer length, high byte |
$034A | ICAX1 | IOCB 0: auxiliary byte 1 (the open mode) |
$034B | ICAX2 | IOCB 0: auxiliary byte 2 |
$034C | ICAX3 | IOCB 0: auxiliary byte 3 |
$034D | ICAX4 | IOCB 0: auxiliary byte 4 |
$034E | ICAX5 | IOCB 0: auxiliary byte 5 |
$034F | ICAX6 | IOCB 0: auxiliary byte 6 |
$0350 | IOCB1 | Input/output control block 1 (16 bytes, the same fields as IOCB 0) |
$0360 | IOCB2 | Input/output control block 2 (16 bytes, the same fields as IOCB 0) |
$0370 | IOCB3 | Input/output control block 3 (16 bytes, the same fields as IOCB 0) |
$0380 | IOCB4 | Input/output control block 4 (16 bytes, the same fields as IOCB 0) |
$0390 | IOCB5 | Input/output control block 5 (16 bytes, the same fields as IOCB 0) |
$03A0 | IOCB6 | Input/output control block 6 (16 bytes, the same fields as IOCB 0) |
$03B0 | IOCB7 | Input/output control block 7 (16 bytes, the same fields as IOCB 0) |