7: Beyond Basic
1200 Memory Map: An Initial Examination
Ian Chadwick

Although a short-lived product on the commercial market, the Atari 1200XL managed to make it into quite a few homes before the line was dropped to make way for the new line. Not that the 1200 was a bad product; it simply lacked several competitive features, such as expansion capability.

Compatibility with software written for 400 and 800 machines is possible only if the programs obeyed the rigid restrictions of the official operating system routines, laid out in the Atari technical manuals. Much software makes direct jumps into the OS that cause programs to crash when run on the 1200. BASIC programs usually work, but there may be difficulty with PEEK, POKE, and USR routines.

The following material is all taken from official Atari releases, including the technical notes for the 1200XL. Memory locations can be cross-referenced with the description in COMPUTE!'s Mapping the Atari when they are described as moved. This is the location these routines or locations have been moved to in the 1200, but they still perform the same function as in the 400 or 800. I have tried to provide all known ranges of values and proper explanations, usually taken from the rare 1200XL technical manual but not available in most outlets. I suggest that you try POKEing different values in these locations to see the results.

The format attempts to follow that of Mapping the Atari as closely as possible. References to 400/800 memory use relate directly to the Revision B ROMS, not always earlier versions. I trust it will prove a useful guideline for 1200 owners.

Reserved for in-house debugging routines.
400/800 use: LINZBS; used in power-up sequence.
Reserved for power-up self-testing routines.
400/800 use: see location 00.
Reserved for OS use, most likely as a buffer pointer.
400/800 use: PTIMOT, moved to 788 ($314).
Reserved for OS use.
400/800 use: PBPNT, moved to 734 ($2DE).
Reserved for OS use.
400/800 use: PBUFSZ, moved to 735 ($2DF).
Reserved for OS use.
400/800 use: PTEMP, now deleted.
Temporary buffer for loader routine. The technical notes contain extensive information about enhancements to the peripheral handling in the 1200. One inclusion is a relocating loader, used to upload peripheral handlers through the SIO. Of particular importance are the two additional device inquiries (polls) to the 1200XL. See the 1200XL Operating System Manual for more information.
400/800 use: CRETRY, moved to 668 ($29C).
Same as above.
400/800 use: DRETRY, moved to 701 ($2BD).
Temporary storage for handler loader.
400/800 use: CKEY, moved to 1001 ($3E9).
Same as above.
400/800 use: CASSBT, moved. Official sources put this, as well as CKEY, above, at 1001. I suspect it is at 1002 ($3EA) instead.
Function key definition table pointer, low byte. You can redefine the function keys alone, by setting up an eight-byte table for the keys Fl to F4 and SHIFT Fl to SHIFT F4. You then assign each byte a value (the internal code: see "Reading the Keyboard Codes" and Appendix A) to correspond to the key. This way, you can get the function keys to act as any other keys. You must, however, make sure that you do not assign to the function keys their own value (138 to 141, $8A to $8D). That is, you must not make Fl perform Fl (138, $8A); otherwise you will generate an endless loop in which the system goes to check what the key should be, sees it is the same, returns, sees there is a table to check, goes back, etc. See locations 121, 122, ($79, $7A) for information on redefining the keyboard.
400/800 use: NEWROW, moved to 757 ($2F5).
Same as above, high byte.
400/800 use: NEWCOL, moved to 758 ($2F5).
Flag for PAL or NTSC version display handler. This was previously at 53268 ($D014).
400/800 use: NEWCOL, second register, moved to 759 ($2F6).

Pointer to key definition, low byte. You can redefine almost the entire keyboard on the 1200XL by setting up a 192-byte table and POKEing the address in these two bytes. When you press a key, the system will respond with the new definition you have given it.

The table consists of three 64-byte portions: lowercase keys, SHIFT + key, CTRL + key. Each key corresponds to a byte as below:

07/07*39/27logo key
09/09 41/29 
25/19 57/39H

Note that there are intentional blanks in the table where no key correspondence exists. Using the table above, to redefine the A key, you would change the 63rd byte in each of the three contiguous parts: the first to redefine the lowercase, the second for the SHIFTed key, and the last for the CTRL and key.

You may place any value between 0 and 255 ($FF) in these bytes; values between 0 and 127 ($7F), 146 and 255 ($92 to $FF) are the ATASCII codes. The following values have special meanings to the 1200XL:

128/80Ignored as invalid key combination.
129/81 Turns the keys to inverse output (normal becomes black on colored screen).
130/82Upper/lowercase toggle.
131/83Uppercase lock.
132/84Control key lock.
133/85End of file.
134/86 to 136/88are ATASCII code.
137/89Toggles keyboard click on or off.
138/8AFunction one; that use defined by the function key description.
139/8B to 141/8Dare functions two, three, and four, respectively.
142/8ECursor to home (upper-left corner of the screen).
143/8FCursor to bottom left-hand corner of the screen.
144/90Cursor to the left margin, beginning of the physical line.
145/91Cursor to the right margin, end of the physical Line.

See locations 96,97 ($60, $61) for redefining the function keys alone, without redefining the rest of the keyboard. You cannot redefine the following keys, since they are either hardwired into the system or operate as a special case:


400/800 use: ROWINC, moved to 760 ($2F8).
Same as above, high byte.
400/800 use: COLINC, also called CLINC, moved to 761 ($2F9).
Temporary counter for loader register. See section 5.0 in the 1200XL Operating System Manual for information concerning the relocatable loader routine.
400/800 use: SPARE, not used.
Relocatable loader routine address pointers.
400/800 use: same as above.
Loader routine variable register.
400/800 use: same as above.
583-618247-26A. . . .
Reserved for future use.
400/800 use: LINBUF, now deleted from the OS.
Character set pointer, defines which character set is to be called into use at the next toggle of the CTRL-F4 keys. Initialized to 204 ($CC) to point to the international set.
400/800 use: see location 583 ($247).
Fine scroll temporary register.
400/800 use: see location 583 ($247).
Keyboard disable register. POKE with 0 to enable keyboard use, 255 to disable it. Remember that you can reenable keyboard use from the keyboard by pressing CTRL + F1. You may also disable the keyboard with the same combination. LED 1 will be on when the keyboard is disabled.
400/800 use: see location 583 ($247).
Flag for fine scroll enable in GR. 0 (text) mode. POKE with 255 for fine scrolling, 0 for coarse scrolling. Follow this POKE with a GR.0 command or an OPEN command for device E:. The display list created for fine scrolling will be one byte larger than the normal, coarse scroll list. The OS also places the address of a DLI (display list interrupt) at VDSLST (512, 513; $200, $201). The color register at 53271 ($D017) is also altered for the last visible line on the screen.
400/800 use: see location 583 ($247).
648288HI BYTE
Register for loader routine.
400/800 use: CSTAT, deleted from OS use.
Loader routine register, same as above.
400/800 use: reserved (spare).
Moved from 54 ($36).
400/800 use: TMPX1, now deleted.
Moved from 55 ($37).
400/800 use: HOLD5, now deleted.
Register for loader routines.
400/800 use: spare.
Same as above.
400/800 use: spare.
Same as above.
400/800 use: spare.
Same as above.
400/800 use: spare.
Same as above.
400/800 use: spare.
Same as above.
400/800 use: spare.
Disk sector size register. The 1200XL establishes sector size at 128 ($80) bytes at power-up or reset, but you can alter the size to any length from 1 to 65536 ($FFFF) bytes. You can also write to the disk without write-verify by using the command "P".
400/800 use: spare
Reserved, purpose unknown
400/800 use: spare.
Keyboard auto-key delay rate; the time lapsed before the auto-key repeat begins. Default is 48. POKE with the number of VBLANK intervals before the repeat begins; each VBLANK is 1/60 of a second, so a value of 60 would equal a one-second delay.
400/800 use: spare.
Keyboard auto-key rate. Default is six, which gives a rate of ten characters per second. POKE with the number of VBLANK intervals before a keystroke is repeated; at one, you will get 60 characters per second repeat rate! See the 1200XL Operating System Manual for infonnation concerning the difference between NTSC (North American) and PAL (English) system rates (NTSC has a 1/60 rate, PAL 1/50).
400/800 use: spare.
Key click disable; POKE with 255 to disable, 0 to enable. In the older machines, the only way to properly disable the click was to install an on/off switch. You may also use the CTRL-F3 keys to toggle keyboard click on and off.
400/800 use: spare.
Flag for the HELP key enable. POKE with 0 to clear it. When PEEKed, 17=HELP key pressed, 81=SHIFT+HELP pressed, and 145=CTRL+HELP pressed. HELPFG is not cleared after the HELP key has been pressed once. You must clear it yourself under program control.
400/800 use: spare.
DMA state save register. This saves the screen graphics state when you disable the screen (CTRL-F2) for faster calculations.
400/800 use: spare.
Moved from 29 ($1D).
400/800 use: spare.
Moved from 30 ($1E).
400/800 use: spare.
Loader routine handler flag.
400/800 use: spare.
These four device status registers are also used by the 1200XL to contain information sent back to the computer by the peripheral after a type three or four poll (these are new poll types; see the 1200XL Operating System Manual). The bytes will contain, in order:
746:  Low byte of the handler size, in bytes (must be an even number).
747:  High byte of the handler size.
748:  Device SIO (serial I/O) address to be used for loading.
749:  Peripheral revision number.
Character set select, as in the 400/800. Default is 224 ($E0) for domestic set; POKE with 204 ($CC) for the international set. When you press CTRL-F4, the value in CHBAS is swapped with that in CHSALT (619; $26B). If you want to select the international set for the next toggle, POKE 200 ($C8) here, rather than 204 ($CC). According to the 1200XL Operating System Manual, the OS tests CHBAS and if it finds 200 in that location, swaps the value with that in CHSALT, usually 204. When the international character set is toggled, LED 2 is lit.
Moved from 96 ($60).
400/800 use: spare.
Moved from 97, 98 ($61, $62).
400/800 use: spare.
Moved from 121 ($79).
400/800 use: spare.
Moved from 122 ($7A).
400/800 use: spare.

Option jumpers, designed to tell the OS how the system is configured. Only J1 (Bit 0) has been assigned. If Bit 0 equals zero (low), then the self-test will run. Bits 1-3 are reserved for future use, bits 4-7 are unused.

400/800 use: ADDCOR, deleted.
Moved from 28 ($1C).
400/800 use: TEMP2, moved to 787 ($313).
Power-up and reset register one.
400/800 use: reserved (spare).
Power-up and reset register two.
400/800 use: reserved (spare).
As above, register three.
400/800 use: reserved (spare).
Screen editor register.
400/800 use: reserved (spare).
Moved from 74 ($4A). 400/800 use: reserved (spare).
Moved from 75 ($4B). 400/800 use: reserved (spare).
Cartridge checksum. Likely the way the system ascertains the size (8K or 16K) of a cartridge when in place.
400/800 use: reserved (spare).
Reserved for OS variables. On power-up and coldstart, variables from 1005 to 1023 ($3ED to $3FF) are set to zero. On warmstart or reset, they are not changed.
400/800 use: reserved (spare).
Same as above.
400/800 use: reserved (spare).
Cartridge interlock register.
400/800 use: reserved (spare).
Handler chain.
400/800 use: reserved (spare).
1792-7419700-1CFB. . . .
Used by DOS when loaded, otherwise available as user RAM.
39967-409599C1F-9FFF. . . .
Display list and screen RAM. This will get moved to lower addresses if the cartridge is 16K (using up the memory from 32768 to 49151; $8000 to $BFFF). The normal 8K cartridge uses RAM between 40960 and 49151 when installed ($A000 to $BFFF). Two control lines tell the system a cartridge is installed.

OS ROM. In the 400/800, the block from 49152 to 53247 ($C000-$CFFF) was unused and unusable. Many of the interrupt handler routines have been moved into this block now, the reason for the incompatibility with 400/800 programs which jump to the old locations rather than to official vectors in RAM.

The bytes between 49152 and 49163 ($C000-$C00B) contain identification and checksum data for the ROM between 49152 and 57343 ($DFFF) using the following format:

49152/C000 Checksum low byte; sum of all of the bytes in ROM except the checksum bytes themselves.
49153/C001Checksum high byte.
491541C002 Revision date, using the form DDMMYY, where each four bits is a BCD digit. The byte has two four-bit numbers for D1 and D2 in the upper and lower halves, respectively.
49155/C003Revision date, month code, M1 and M2.
49156/C004Revision date, year code, Y1 and Y2.
49157/C005Option byte, reserved. Contains zero for the 1200XL.
49158/C006 Part number, using the format AANNNNNN, where A is an ASCII character and N is a four bit BCD digit. This byte is A1.
49159/C007Part number, A2.
49160/C008Part number, N1 and N2.
49161/C009Part number, N3 and N4.
491621C00APart number, N5 and N6.
49163/C00BRevision number.

International character set, one of two in the 1200. The other is at the same place as in the 400/800; 57344-58367 ($E000-$E3FF).
GTIA and graphics registers, as in the 400/800. The self-test code is physically located between 53248 and 55295 ($D000 to $D7FF) but moved to 20400 to 22527 ($5000 to $57FF) when called up.
53504-53759D100-D1FF. . . .
Unused in both 400/800 and 1200 versions.
POKEY registers, same as in the 400/800.
PIA registers, same as in the 400/800.

Used to control the LEDs and the memory management, enabling you to disable the OS ROM and enable the RAM. Bit 0 controls location 49152-53247 ($C000-$CFFF) and 55296-65535 ($D800-$FFFF). When set to zero, the OS is replaced by RAM. However, unless another OS has been provided, the system will crash at the next interrupt. Bit 7 controls the RAM region 20480-22527 ($5000-$57FF) and is normally enabled (set to one). If disabled (set to zero), then the OS ROM is enabled, the memory access remapped and access provided to the self-test code physically present at 53248-55295 ($D000-$D7FF). If LED 1 is on, then the keyboard is disabled. If LED 2 is on, then the international character set is selected.

400/800 use: PIA PORTB. Since there are only two controller jacks (PORTA), this is no longer used in the 1200, meaning only two game controllers may be attached at once, rather than four.

ANTIC registers, same as in 400/800.
54528-55295D500-D7FF. . . .
Unused in both 400/800 and 1200 versions of the OS. Any access read or write in the 54528 to 54783 ($0500 to $D5FF) range enables the cartridge control line CCNTL in the cartridge interface as in the 400/800.
Floating point package as in the 400/800. The 1200XL corrects a bug in the FP package which was in the REV B ROMs. You now get an error status when you try to calculate the LOG or LOG10 of zero.
Domestic character set, as in the 400/800. The international character set location is listed above. This is the default set. Register 756 ($2F4) defines which is in use (see above).

OS ROMS. There are many changes in the 1200 OS, making it quite different from the 400/800 OS, but advertised entry points and vectors have been left the same. There are five new fixed entry point vectors which have been added to the 1200XL:

58496/E480 JMP PUPDIS:   entry to power-on display.
58499/E483 JMP SLFTST:entry to the self-test code.
58502/E486 JMP PHENTR: entry to the handler, uploaded from peripheral or disk.
58505/E489 JMP PHULNK:entry to uploaded handler unlink.
58508/E48C JMP PHINIS:entry to uploaded handler initialization.

58481E471. . . .

The Atari 400/800 had a blackboard mode; the Memo Pad mode you saw when typing BYE in BASIC. This no longer exists on the 1200XL; it has been replaced by the noninteractive Atari advertisement logo.

Bytes from 65518 to 65529 ($FFEE to $FFF9) contain checksum and identification for the ROM block 57344 to 65535 ($E000 to $FFFF) in a similar format to that at location 49152 ($C000). The bytes used are as follows:

65518/FFEERevision date Dl and D2.
65519/FFEFRevision date M1 and M2.
65520/FFF0Revision date Y1 and Y2.
65521/FFFl Option byte; hardware product identifier; for the 1200XL it should read one.
65522/FFF2 to 65526/FFF6Part number using the form AANNNNNN.
65527/FFF7Revision number.
65528/FFF8Checksum byte, low byte.
65529/FFF9Checksum byte, high byte.

Bytes from 65530 to 65535 ($FFFA to $FFFF) contain power-on, RESET, NM, and IRQ vectors.

65521FFF1. . . .

If you PEEK here, you should get one and then 65527 ($FFF7) will have the revision number. If not one, then the product code will be here and 65527 will contain the OS revision number. This identifies the OS as that of the 1200XL. Accordingly, if you PEEK 65527 and 65528 ($FFF7, $FFF8) and get 221 ($DD) and 87 ($57) respectively, you have the 400/800 Revision A ROMS. If you get 243 ($F3) and 230 ($E6), you have the Revision B ROMS. PAL versions will read 214 ($D6) and 87 ($57), 34 ($22) and 88 ($58) respectively. If location 64728 ($FCD8) is not 162 ($A2) then the product is a 1200XL or future computer.

New Graphics Modes

Four new graphics modes are available on the 1200 from BASIC: GRAPHICS 12, 13, 14, and 15. These are the same as modes described in the technical manuals but previously unavailable in BASIC.

GRAPHICS 12 is ANTIC mode 4, a four-color mode (plus background). Each character on the screen is the same size as a GRAPHICS 0 character but only four pixels are displayed instead of eight as in GRAPHICS 0. It can be well used by a redefined character set. The screen has 20 lines; to obtain the full 24 lines, use GRAPHICS 12+16.

GRAPHICS 13 is ANTIC mode 5, another four-color mode (plus background), this time with characters double the physical space of the GRAPHICS 0 characters. As in GRAPHICS 12, only four pixels are displayed; the system interprets definition in the character sets by bit pairs, rather than single bits as in GRAPHICS 0. The sereen has ten lines and can be expanded to 12 by GRAPHICS 13+16. Both GRAPHICS 12 and GRAPHICS 13 use 40 bytes of screen RAM per line.

In both GRAPHICS 12 and GRAPHICS 13, the color of the screen pixel depends on the bit pair in the byte addressed. Each character can be built of eight bytes like the GRAPHICS 0 characters, but bits are paired for screen presentation. If the bits have the value below, then the color shown appears on the screen:

3/11 If Bit 7 of the character=0 (the color modifier), then PF2 is used, else if Bit 7=1, then PF3 is used.

GRAPHICS 14 is ANTIC mode 12 ($C), a two-color mode with a resolution of 160 pixels wide by 192 pixels high. This is sometimes called GRAPHICS "6½" because each line is one scan line high where GRAPHICS 6 is two scan lines high. Colors used are BAK and PF0. Only the first bit of a screen byte is used to identify the color.

GRAPHICS 15 is ANTIC mode 14 ($E), known as GRAPHICS "7½" and used in many popular commercial programs such as Datasoft's Micropainter. It is a four-color mode with a resolution of 160 across by 192 down, each mode line being one scan line high. Colors used are BAK and PF0 to PF2. Only the first two bits in a screen byte are used to identify the color of the byte.

Data for New Screen Modes

  Memory Used:
Mode Horizontal
Colors Split
12 40 20/24 5 1154 1152
13 40 10/12 5 664 660
14 160 160/192 2 4270 4296
15 160 160/192 4 8112 8138

Final Notes

If you have a copy of Mapping the Atari, you may find it useful to make a note in the margins of the new locations of interrupt and other routines as defined by the vectors. Most of these are located between 512 and 1151 ($200 to $47F). These new pointers will show you where routines have been moved in the 1200.

A small one-pixel shift in the 1200's display may cause some programs to show different colors (particularly artifact colors in GRAPHICS 8) than they do on the 400/800. Colors (but not graphics modes) now conform to those displayed by the earlier CTIA chip.

Some Revision B enhancements which are also in the 1200XL should be mentioned. First, the display handler will not clear memory beyond that indicated by RAMTOP (location 106; $6A). This means you can store data or machine language routines above the graphic display and have them remain intact when changing graphics modes. Second, you can assign a printer number from P1 up to P8. The printer handler inserts an EOL in the printer buffer if none is there, before sending the buffer to the printer on a CLOSE. This allows the printer to immediately print the last line, rather than having to force it to do so. The CIO places an EOL in the input buffer when a record longer than the buffer size is being read. This allows you to still read a portion of a record even if a large enough buffer was not provided. Finally, the screen clear code will work no matter what the cursor coordinates are.

If at all possible, try to obtain a copy of the 1200XL Operating System Manual. Much of what is vague here is explained there. There are many other, more subtle and technical differences between 400/800 use and 1200XL use. These are best explained in Atari's own manuals. The manual also contains instructions on how to redefine the Atari keyboard as a Dvorak layout and define GRAPHICS 12 and 13 characters, and it gives specific information on the new peripheral poll types and their use.

Return to Table of Contents | Previous Section | Next Section