The Atari 8-bit computers are outstanding in terms of flexibility. Clear interfaces in the operating system have enabled the creation of many compatible extensions and replacements. As the coder, you have to stick to some basics to ensure that all Atari users can run your program. The things you have to keep in mind are that there are:
- emulators will always behave somehow differently than the real computer, TV, or storage device
- multiple operating systems (XL-OS, QMEG-OS, HISIO-OS, ...)
- multiple CPUs (65C02, 65C816)
- multiple video systems (PAL, NTSC)
- multiple memory sizes (48k, 64k, 128k, 192k, 320k, 576k, 1088k, ...)
- multiple disk operating systems (Atari DOS 2.5, MyDOS, SpartaDOS, XDOS, ...)
- multiple storage devices (C:, D:, H:, ...)
- multiple storage media (real disk, SIO2PC, SIO2SD, SIDE, Maxflash, The!Cart, ....)
- multiple storage media access speeds (19.2kb/s, 57.6kb/s, 125kb/s)
- multiple storage media speeders and loaders (Turbo 1050, SIO2SD, ...)
The essential tips can be summarized as
- test on real hardware
- stick to the well-defined operating system addresses and vectors
- stick to legal opcodes
- check for the video system
- check for the memory size
- create self-contained executables that can be loaded from any DOS, device, medium, or menu
- pack large files and avoid cold starts to reduce the loading times
- avoid using typical memory for speeder locations and interrupts during I/O
Of course, there are exceptions to these tips. For example, a game that needs to load additional levels that people create with a level editor from a disk cannot be a self-contained executable. A 256 bytes demo will use illegal opcodes and OS entry points to stay within the size limit. But your aim should always be to try and stick to the tips because otherwise, you limit the number of people who can see and use your program.
Experience shows that three major issues lead to crashing programs and sad users:
- You develop with an emulator or non-standard operating system where BASIC is turned off by default. Your program uses the BASIC memory area RAM. You test, and everything works fine.
But the user is sad because all real Atari computers have BASIC enabled by default. So the user has to remember if and when to press OPTIONS when switching on the computer. Otherwise, the program will crash either during loading or at the start.
SOLUTION: If you require BASIC to be disabled, turn it off via your code. Don't rely on settings in the emulator, modified operating systems, or the user's imagination.
- You develop with an emulator, and your program grows and grows. You use the RAM in the BASIC area and maybe even the extended memory. You test, and the program loads instantly and works fine.
But the user is sad because all real Atari computers load with 19.2kb/s. That means a 40k program will take about 30 seconds to load. With extended RAM, this can quickly go up to several minutes.
SOLUTION: Pack your program with one of the excellent packers out there or use a built-in packing for the data in your program.
- You develop and test a great game in Europe on a PAL computer.
But the user is sad because the colors will be different, the music will play too fast, and possibly the program will crash. All Atari computers in the US are NTSC computers. That means the frame rate is 60 Hz instead of 50 Hz. As a result, you have more frames per second and less CPU time per frame. The game will crash because a new frame starts already before the game logic in the vertical blank interrupt is finished.
SOLUTION: Check for the video system type of the computer. Adapt the replay speed and possibly the logic to deal with the 60 Hz frame rate.
Creating a compatible program is easy if you know some do's and don'ts.
For example, this small and 100% compatible program will work on any 8-bit Atari in just 21 bytes.
org $2000 ; Safe memory area
start lda $d40B ; Get current screen line sta $d01a ; Set as background color to see the rainbow jmp start ; Loop run start; Set RUNADR, so START is called after loading
The following section gives detailed views and examples of what these tips mean for your code. If you need support in keeping or understanding the information described below or a tester, please get in touch with me at or on AtariAge.
Test on real hardware with real memory
Reason: All RAM is filled with zeros by default and after a cold start in the emulator. But the RAM under the BASIC area ($a000-$bfff), the OS area ($c000-cfff, $d800,$ffff), and the extended RAM banks ($4000-$7fff) are filled with random values when the real Atari is powered on. And the contents that are written in these areas are also kept after a cold start.
If your program relies on filling these memory areas with zeros, it will crash or display unexpected garbage. This can also happen in other memory areas. For example, the memory area $2000-$4fff is not zero if a program is loaded from a DOS menu. So test on real hardware and always fill the memory yourself with the values you require to be there.
Test on real hardware with real TV
Reason: The emulators like Altirra and Atari800Win offer color palettes that are not correct. A program developed on an emulator can show different colors on real Ataris.
For example, the doors in "Project M 2.0" do not have the colors red, green, and blue as in Altirra but brown, white-blue, and blue-violet.
Test on real hardware with real I/O
Reason: All real Atari computers load with 19.2kb/s. That means a 40k program will take about 30 seconds to load. With extended RAM, this can quickly go up to several minutes. In addition, there a different SIO routines, speeds, and timings. So it may also be that a modified SIO works with 125kb/s, leaving no time for any VBI or DLI code you have added.
Pack your program with one of the excellent packers out there, or use a built-in compression for the data in your program. Avoid running code during loading. On modern devices, the loading speed can be so high that people won't see what you want to show while loading anyway.
Loading and Memory Tips
The program should be delivered as an executable file and not as a complete ATR
Reason: If you create a bootable disk instead of one or multiple files, you make it impossible for the user to put several programs onto a hard disk or compilation like a disk magazine (like the ABBUC Mag) or a compilation (like the SillyPack).
This means fewer people will get your program. Also, loading executables directly works much better and faster than loading from simulated ATRs, for example, on Maxflash, "The!Cart", SIO2SD, SIDE, and other devices.
The program should be loadable from a regular DOS menu like DOS 2.5 or MyDOS.
Reason: People use many different DOS'es and storage devices with the Atari computer. DOS 2.5 and MyDOS can be considered the common denominator. If something works with them, it'll typically also work with the other DOS'es.
The program should use file names that start with an upper-case letter and are followed by upper-case letters and digits only.
Reason: Digits as the first character, underscores in file names, etc., are not supported by many standard DOS'es.
The program should load from DOS to $2000 or above.
Reason: Depending on the number of attached drives and devices, the memory below this address is typically used by DOS. If you load directly to the area below $2000, the program will overwrite these parts and not load properly.
The program should not overwrite system zero page ($00-$7f), page 1 ($100-$1ff), 4 ($400-$4ff), 5 ($500-$6ff), 6 ($600-$6ff).
Reason: These memory locations are used by software-driven speeders and file loaders of various devices. If you overwrite them, the speeder or loader will crash, and the user will have to play around with configuration settings and, in the worst case, cannot run your program.
Programmers often test with modified operating systems with built-in speeders or emulators with active speeder settings. This gives the wrong impression that loading times are no problem.
The program should not overwrite DOS ($700-$1fff) when it starts.
Reason: The computer will crash when the user presses RESET.
If you overwrite DOS, you must set the "cold start flag" (COLST=$244) to a non-zero value. But remember that booting DOS during a cold start takes significant time on a real unexpanded computer. So prevent overwriting DOS whenever possible.
The program should switch off BASIC automatically if it requires BASIC to be disabled.
Reason: Don't force the user to remember when to press OPTION and when not.
Remember that the default in many modified operating systems and emulators is that BASIC is off. On a real computer, the default is the BASIC is on. So if the area $A000-$BFFF is used already during loading, no data will be stored in the RAM, and the program will typically crash upon start. Relief the user from controlling BASIC by adding the following short INI segment at the beginning of the program file. It saves some bytes using the OPEN and CLOSE vectors from the official E: handler table instead of the CIOV.
org $2000 ; Can be overwritten by the main program
.proc loader ; Disable BASIC
lda #$c0 ; Check if RAMTOP is already OK
cmp $6a ; Prevent flickering if BASIC is already off
sta $6a ; Set RAMTOP to end of BASIC
sta $2e4 ; Set RAMSIZ also
lda $d301 ; Disable BASIC bit in PORTB for MMU
lda $a000 ; Check if BASIC ROM area is now writeable
beq ramnok ; If not, perform error handling....
lda #$01 ; Set BASICF for OS, so BASIC remains OFF after RESET
ldx #2 ; Close "E:" before re-openining it again
ldx #0 ; Open "E:" to ensure screen is not at $9C00
editor lda $e401,x ; This prevents garbage when loading up to $bc000
ramnok inc 712 ; Add your error handling here, there still is a ROM....
ini loader ; Make sure the loader is executed before the main program is loaded
org $2000 ; Start of main program
The program must not change zero page addresses $02-03 and $08-$0d.
Reason: These addresses are used by the RESET routine. If you change them, the computer will hang on RESET.
Note that older G2F versions have this bug. And real computers do not have "SHIFT-F5" as your emulator has.
The program should not overwrite the menu or DOS areas ($400-$47f, $0700-$1fff).
Reason: These areas are used by speeders, menus, and DOS. If you overwrite them, you force the user to boot again and waste time.
The program should not set or change COLDST ($244) by default
Reason: If you force a cold start, the user boots again and wastes time.
An exception to this tip applies if you cannot keep the tip "the executable should not overwrite the menu or DOS area". If you overwrite the menu or DOS area ($400-$47f, $0700-$1fff), you must set COLDST ($244) to a non-zero value. Otherwise, the computer will hang on RESET. And real computers do not have "SHIFT-F5" like your emulator has to force a cold start.
The program should auto-detect the actual extended RAM of the computer.
Reason: Different computers use different types of RAM upgrades.
Many people cannot run your program if you support a single RAM upgrade.
The program should handle different TV systems (PAL/NTSC).
Reason: computers in Europa typically use PAL, computers in the US use NTSC,
Not all users can run if your program only supports PAL or NTSC. At least you should display an appropriate message in this case so the user knows why it is not working. The best solution is to check the PAL ($d014) register and adapt the color palette and sound replay speed accordingly. For playing a PAL tune on an NTSC system, you can use a simple counter counting from 5..0 and call the sound replay only for 5..1, skipping the replay for the counter value 0.
The program should change DMA and DL only during or immediately after the vertical blank.
Reason: Changing the ANTIC registers or DMACTL ($d400) or DLISTL/H ($d402/3) while the TV beam still displays the screen causes interferences, flicking, and rolling screen on real TV with real Ataris. If DLIs are enabled, crashes are very likely, too.
You will typically not see or detect such issues on an emulator. It doesn't emulate this behavior and always uses identical timing.
The program should initialize POKEY when it starts.
Reason: When the program is loaded from an SIO device, POKEY is partly still in I/O mode and will not play sounds as you expect.
Write the value "0" to AUDCTL ($d208) and "3" to SKCTL ($d20f) to initialize POKEY. If you use the Raster Music Tracker or CMC player, this is done by the player initializations.
The program should limit the maximum total sound volume.
Reason: Each of the four channels has a volume between 0 and 15. If the sum of all volumes exceeds 32, a real Atari computer will sound distorted.