<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://7800.8bitdev.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=MSaarna</id>
		<title>8BitDev.org - Atari 7800 Development Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://7800.8bitdev.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=MSaarna"/>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php/Special:Contributions/MSaarna"/>
		<updated>2026-08-08T07:23:48Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.28.0</generator>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1320</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1320"/>
				<updated>2026-07-13T15:27:52Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Display List data can be located anywhere in address space, and crossing of page boundaries is handled correctly. It should be noted that Maria can't read bytes fast enough during DMA to cross more than one page in any given Display List. &lt;br /&gt;
&lt;br /&gt;
Display Lists must be stored in console RAM (or a device capable of similar performance) due to Maria reading Display List bytes with a short 2-cycle window, rather than the 3-cycle window used for reading graphical data.&lt;br /&gt;
&lt;br /&gt;
It's an atypical use-case, but it should be noted that Maria is also able to correctly deal with graphic objects that straddle a page boundary.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each DLL entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. &lt;br /&gt;
&lt;br /&gt;
Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one Display List to specify a set of raster graphics. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15 lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
It should be noted that any of the 3 byte DLL bytes can cross a page boundary without issue.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1319</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1319"/>
				<updated>2026-07-12T17:54:22Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses 0x1800 to 0x27FF. They are also partly accessible (shadowed) at addresses 0x0040 visibleKangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''Color Register Layout'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
| Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
| Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
| Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''AUDF# Effect On Frequency'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| ... || ... || ... || ... || ... || ...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| ... || ... || ... || ... || ...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''SWCHB Register Bits'''&lt;br /&gt;
|-&lt;br /&gt;
! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
| P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
| none&lt;br /&gt;
| none&lt;br /&gt;
| Pause. 0=pressed, 1=released&lt;br /&gt;
| none&lt;br /&gt;
| Game Select. 0=pressed, 1=released&lt;br /&gt;
| Game Start. 0=pressed, 1=released&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+'''Device Mappings, address lines'''&lt;br /&gt;
! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from 0x1800 - 0x27FF appear in zero, and first pages. The last entry indicates that the last 2K block (0x2000 - 0x27FF) is repeated at 0x2800. For encryption purposes, the 120 bytes from 0xFF80 - 0xFFF7 must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+'''Memory Map, absolute'''&lt;br /&gt;
! Locations !! Device&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0000 to 001F || TIA Registers&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0020 to 003F || MARIA Registers&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0100 to 013F || Shadow of Page 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0200 to 027F || Shadowed&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0280 to 02FF || 6532 Ports&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0300 to 037F || Shadowed&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1800 to 203F || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2100 to 213F || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2140 to 21FF || Block One Shadow&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2200 to 27FF || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 1000px;&amp;quot;&lt;br /&gt;
|+'''DMA Timing'''&lt;br /&gt;
! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
|-&lt;br /&gt;
| DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
|-&lt;br /&gt;
| DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
|-&lt;br /&gt;
| process 4-byte DL header || 8 cycles&lt;br /&gt;
|-&lt;br /&gt;
| process 5-byte DL header || 10 cycles&lt;br /&gt;
|-&lt;br /&gt;
| direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
|-&lt;br /&gt;
| indirect 1-byte read || 6 cycles&lt;br /&gt;
|-&lt;br /&gt;
| indirect 2-byte read || 9 cycles&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
             134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
   NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1318</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1318"/>
				<updated>2026-07-12T17:51:05Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses 0x1800 to 0x27FF. They are also partly accessible (shadowed) at addresses 0x0040 visibleKangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''Color Register Layout'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
| Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
| Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
| Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''AUDF# Effect On Frequency'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| ... || ... || ... || ... || ... || ...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| ... || ... || ... || ... || ...&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''SWCHB Register Bits'''&lt;br /&gt;
|-&lt;br /&gt;
! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
| P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
| none&lt;br /&gt;
| none&lt;br /&gt;
| Pause. 0=pressed, 1=released&lt;br /&gt;
| none&lt;br /&gt;
| Game Select. 0=pressed, 1=released&lt;br /&gt;
| Game Start. 0=pressed, 1=released&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+'''Device Mappings, address lines'''&lt;br /&gt;
! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from 0x1800 - 0x27FF appear in zero, and first pages. The last entry indicates that the last 2K block (0x2000 - 0x27FF) is repeated at 0x2800. For encryption purposes, the 120 bytes from 0xFF80 - 0xFFF7 must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+'''Memory Map, absolute'''&lt;br /&gt;
! Locations !! Device&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0000 to 001F || TIA Registers&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0020 to 003F || MARIA Registers&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0100 to 013F || Shadow of Page 0&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0200 to 027F || Shadowed&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0280 to 02FF || 6532 Ports&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0300 to 037F || Shadowed&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 1800 to 203F || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2100 to 213F || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2140 to 21FF || Block One Shadow&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2200 to 27FF || RAM&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
|+'''DMA Timing'''&lt;br /&gt;
! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
|-&lt;br /&gt;
| DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
|-&lt;br /&gt;
| DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
|-&lt;br /&gt;
| process 4-byte DL header || 8 cycles&lt;br /&gt;
|-&lt;br /&gt;
| process 5-byte DL header || 10 cycles&lt;br /&gt;
|-&lt;br /&gt;
| direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
|-&lt;br /&gt;
| indirect 1-byte read || 6 cycles&lt;br /&gt;
|-&lt;br /&gt;
| indirect 2-byte read || 9 cycles&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
             134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
   NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1317</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1317"/>
				<updated>2026-07-12T15:38:18Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Display List data can be located anywhere in address space, and crossing of page boundaries is handled correctly. It should be noted that Maria can't read bytes fast enough during DMA to cross more than one page in any given Display List. &lt;br /&gt;
&lt;br /&gt;
Display Lists must be stored in console RAM (or a device capable of similar performance) due to Maria reading Display List bytes with a short 2-cycle window, rather than the 3-cycle window used for reading graphical data.&lt;br /&gt;
&lt;br /&gt;
It's an atypical use-case, but it should be noted that Maria is also able to correctly deal with graphic objects that straddle a page boundary.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each DLL entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. &lt;br /&gt;
&lt;br /&gt;
Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one Display List to specify a set of raster graphics. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15 lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
It should be noted that any of the 3 byte DLL bytes can cross a page boundary without issue.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1316</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1316"/>
				<updated>2026-07-12T15:07:35Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Display List data can be located anywhere in address space, and crossing of page boundaries is handled correctly. It should be noted that Maria can't read bytes fast enough during DMA to cross more than one page in any given Display List. &lt;br /&gt;
&lt;br /&gt;
Display Lists must be stored in console RAM (or a device capable of similar performance) due to Maria reading Display List bytes with a short 2-cycle window, rather than the 3-cycle window used for reading graphical data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each DLL entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. &lt;br /&gt;
&lt;br /&gt;
Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one Display List to specify a set of raster graphics. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15 lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
It should be noted that any of the 3 byte DLL bytes can cross a page boundary without issue.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1315</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1315"/>
				<updated>2026-07-12T14:47:12Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Display List data can be located anywhere in address space, and crossing of page boundaries is handled correctly. It should be noted that Maria can't read bytes fast enough during DMA to cross more than one page in any given Display List. &lt;br /&gt;
&lt;br /&gt;
Display Lists must be stored in console RAM (or a device capable of similar performance) due to Maria reading Display List bytes with a short 2-cycle window, rather than the 3-cycle window used for reading graphical data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1314</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1314"/>
				<updated>2026-07-12T14:40:57Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Display List data can be located anywhere in address space, and crossing of page boundaries is handled correctly. It should be noted that Maria can't read bytes fast enough during DMA to cross more than one page in any given Display List. &lt;br /&gt;
&lt;br /&gt;
Display Lists must be stored in console RAM (or a device capable of similar performance) due to Maria reading Display List bytes with a short 2-cycle window, rather than the 3-cycles used for reading graphics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1313</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1313"/>
				<updated>2026-07-12T14:24:43Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Due to limits of access speed and available DMA time, Display List data can cross only one page boundary. Additionally, Display Lists must be in RAM (or a device capable of similar performance), due to Maria's quick 2-cycle access of Display List bytes.&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1312</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1312"/>
				<updated>2026-07-12T14:22:11Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Due to limits of access speed and available DMA time, a Display List can cross only one page boundary. Additionally, Display Lists must be in RAM (or a device capable of similar performance), due to Maria's quick 2-cycle access of Display List bytes.&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLL data can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1311</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1311"/>
				<updated>2026-07-12T13:18:56Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Due to limits of access speed and available DMA time, a Display List can cross only one page boundary. Additionally, Display Lists must be in RAM (or a device capable of similar performance), due to Maria's quick 2-cycle access of Display List bytes.&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLLs can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1310</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1310"/>
				<updated>2026-07-12T13:00:15Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
Due to limits of access speed and available DMA time, a Display List can cross only one page boundary. Additionally, Display Lists must be in RAM (or a device capable of similar performance), due to Maria's quick 2-cycle access speed of Display List bytes.&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLLs can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1309</id>
		<title>7800 Software Guide</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Software_Guide&amp;diff=1309"/>
				<updated>2026-07-12T12:53:33Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCTION==&lt;br /&gt;
The 7800 is a product which combines the ATARI 2600 hardware with a new graphics chip called MARIA. The entire 2600 library of cartridges will run on the 7800 as they do on the 2600, but new cartridges designed to access the improved hardware will be able to take advantage of a large number of improvements.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF THE 7800==&lt;br /&gt;
&lt;br /&gt;
Ignoring the 2600 environment, which is identical to the ATARI 2600, the 7800 environment is characterized by the following:&lt;br /&gt;
&lt;br /&gt;
* (2) 6116's&lt;br /&gt;
** 4K bytes of RAM&lt;br /&gt;
* 6532&lt;br /&gt;
** I/O&lt;br /&gt;
* TIA&lt;br /&gt;
** sounds&lt;br /&gt;
** some input ports.&lt;br /&gt;
* Expanded cartridge slot&lt;br /&gt;
* SALLY (6502)&lt;br /&gt;
** microprocessor running at 1.79 MHz.&lt;br /&gt;
* MARIA&lt;br /&gt;
** all video&lt;br /&gt;
&lt;br /&gt;
Additionally, there is a protection circuit which verifies that each cartridge has the correct encrypted data before enabling 7800 mode. Encryption will be covered in another document, but see Appendix 1, 7800 Memory Map, for information about reserving space for encryption.&lt;br /&gt;
&lt;br /&gt;
===6116's===&lt;br /&gt;
There are two (2) 6116 2Kx8 RAM chips on the 7800 PC board. Together they occupy addresses x '1800' to x'27FF'. They are also partly accessible (shadowed) at addresses x '0040' – x '00ff' and x '0140' - x '00FF' to extend zero page (quick access) RAM and first page (stack) RAM. Refer to the memory map appendix for further information.&lt;br /&gt;
&lt;br /&gt;
===6532===&lt;br /&gt;
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers. Its functions are more limited because its speed is not fast enough for normal operation. Any access to this chip (joystick and switch I/O) will cause the microprocessor to slow to 1.19 MHz. The ports and switches connected through the 6532 are: joysticks (directional), pause, game select, game reset, and difficulty switches. The 6532 can be used to generate output through the joystick ports as well. For address information on 6532 ports and switches, refer to Appendix 2, Standard 7800 Equates.&lt;br /&gt;
&lt;br /&gt;
===TIA===&lt;br /&gt;
The TIA is only partly accessible in 7800 mode. While it occupies addresses x'0000' - x'003F' in 2600 mode, only the section at x'0000' - x'001F' is available in 7800 mode. The only significant (useable) registers of these are the sound related registers and the input ports (fire buttons, paddle controllers). Any access to the TIA will cause the processor to slow from 1.79 MHz to 1.19 MHz.&lt;br /&gt;
&lt;br /&gt;
===Cartridge Slot===&lt;br /&gt;
The cartridge slot is larger for 7800 mode cartridges. The additional lines are: three (3) address lines (now all 16 address lines appear on the cartridge connector); the READ/WRITE line, so that RAM may be added to any cartridge very simply; the phase 2 clock line in order to add another microprocessor on&lt;br /&gt;
the cartridge and have it synchronized with the existing Sally chip; an audio line so that one may mix in audio signals generated on the cartridge; a composite video line, so that external video signals may be included; and the HALT line, to enable the cartridge to distinguish MARIA ROM accesses from SALLY ROM accesses.&lt;br /&gt;
&lt;br /&gt;
===SALLY (6502)===&lt;br /&gt;
This is the microprocessor, which is also used in the ATARI 5200. The only thing special about the Sally chip is that it has a HALT line, which allows the functionality described above.&lt;br /&gt;
&lt;br /&gt;
===MARIA===&lt;br /&gt;
This is the custom chip which is the heart of the 7800. It handles all graphics and video including the VSYNC and VBLANK signals.&lt;br /&gt;
&lt;br /&gt;
==Overview of MARIA==&lt;br /&gt;
===Graphics===&lt;br /&gt;
MARIA does not employ the concepts of players, missiles, and playfield, as do the 2600 and 5200. Instead MARIA uses an approach to graphics commonly used in coin-operated games. Each raster of the display may be thought of as a bit map. This map is contained in an area of the MARIA chip called the Line RAM. Information is first stored into the Line RAM, then later read from Line RAM and displayed on the screen.&lt;br /&gt;
&lt;br /&gt;
Consider for a moment just one raster of display. One would compose this raster's graphics by storing data into Line RAM. This is done by specifying what data should be put at what horizontal location. Graphics may be specified in small pieces, and overlapped. The order in which pieces of a raster are specified determines object priority with the last object specified on top.&lt;br /&gt;
&lt;br /&gt;
When graphics data is specified to be stored into Line RAM, it will reference any one of eight (8) color palettes. Each pixel of data will take on any one of three (3) colors from the specified palette, or may be turned off (transparent). Again, the Line RAM contains only one raster of graphics information. There are actually two Line RAM buffers. While one is being read (displayed), the other is being written for display in the next raster. This means that the construction of graphics for a raster may take as long as, but no longer than, one raster, and that graphics must be stored into Line RAM on a raster by raster basis.&lt;br /&gt;
&lt;br /&gt;
The only limit to the number, and size of objects on one scan line is the amount of time it takes to load each into Line RAM, as all loading must occur during one scan line.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
For NTSC consoles, there are a total of 263 rasters per frame (~1/60th second). The &amp;quot;visible&amp;quot; screen (during which MARIA attempts display) starts on raster 16 and ends on raster 258. The area found visible on all television sets starts on raster 41 and ends on raster 233, 192 scan lines later. Any display outside this area may not appear on all televisions. See Appendix 4, Frame Timing, for more details. For PAL consoles, there are a total of 313 rasters per frame. (~1/50th per second). The “visible” screen starts on raster 16 and ends on raster 308. The area vound visible on television sets starts on raster 41 and ends on raster 281, 240 scan lines later. As with NTSC, any display outside this area my not appear on all televisions.&lt;br /&gt;
&lt;br /&gt;
Display is accomplished automatically by MARIA and consists of two tasks: constructing the Line RAM, and displaying the graphics. These happen simultaneously in MARIA. Construction of Line RAM is automatically initiated every raster by MARIA, and is directed by a predefined list of instructions called the Display List. Line RAM construction occurs through a process called DMA (Direct Memory Access). This means that the 6502 (SALLY) processing is suspended while MARIA comes in and interrogates the RAM and ROM for Display List and graphics information. DMA will occur every &amp;quot;visible&amp;quot; scan line and lasts no longer than one scan line. Because the Line RAM being constructed is displayed on the following scan line, MARIA will read each Display List one line before it is actually displayed. All Line RAM is cleared on a line by line basis and BACKGRND color will be displayed if no data is written.&lt;br /&gt;
&lt;br /&gt;
====Display List====&lt;br /&gt;
DMA is mainly concerned with reading the Display List. This is a list of instructions for where to find graphics data, where to put it on the screen, and other details for constructing a scan line. The Display List is made up of many &amp;quot;headers.&amp;quot; Most headers are four (4) bytes long (the exeption is discussed later). If the second byte of a header is zero, it indicates the end of the Display List, and DMA will stop allowing the 6502 to continue processing. The format of the header is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''4-byte DL Entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Color Palette (0-7)&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width (1-31) is the 2's complement of the object's width. Measured in bytes, not pixels.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each header is concerned with one graphics item, which can be any width. If ten objects should appear on a scan line, the Display List for that scan line would be ten (10) headers long, followed by two (2) bytes, the first of which is ignored, and the second of which should be zero to end DMA.&lt;br /&gt;
&lt;br /&gt;
A Display List may cross only one page boundary, so it can be no more than 512 bytes long. Additionally, Display Lists must be in RAM, due to the required access time.&lt;br /&gt;
&lt;br /&gt;
====Display List List====&lt;br /&gt;
&lt;br /&gt;
MARIA locates the Display Lists by reading a Display List List (referred to as DLL from now on). This list is a series of 3 byte entries. Each entry points to a Display List. Included in each entry is a value called OFFSET, which indicates how many rasters should use the specified Display List. OFFSET is decremented at the end of each raster until it becomes negative, which indicates that the next DLL entry should now be read and used. Each time graphics data is to be fetched OFFSET is added to the specified High address byte, to determine the actual address where the data should be found. This allows one display list to specify many rasters of graphics. Without OFFSET the only approach to graphics is to have a Display List for each raster, and a DLL for each Display List. Not only would this use a lot of RAM, but it would also take quite a bit of processing time to manipulate these Display Lists when objects move. Because OFFSET is added to HIGH address byte, each raster of graphics for an object must be separated by x'100' bytes, or one page.&lt;br /&gt;
&lt;br /&gt;
The group of rasters specified by one DLL entry is called a &amp;quot;zone.&amp;quot; Again, the number of rasters in a zone equals OFFSET+1. Larger zones mean less RAM is needed for DLLs, Display Lists and Character Maps (see DMA MODES below). But upon consideration of how to use zones, you will realize that to achieve smooth vertical motion each stamp must be padded at top and bottom with zeros. For example, if the top raster of an object is to appear on the last line of a 16 high zone, it must have 15&lt;br /&gt;
lines of zeros above it. If that object is 8 pixels (2 bytes) wide, and its top line of data is located at x'CF04', then you will need two bytes of zeros at x'D004', x'D104', x'D304',..., and x'DE04' (remember that OFFSET decrements). As this can add up to many pages of zeros, you can specify that MARIA should interpret certain data as zeros, even if it isn't. This is called &amp;quot;Holey DMA&amp;quot; because DMA will see &amp;quot;holes&amp;quot; in the data that aren't really there. This can be enabled and disabled on a zone by zone basis via a DLL entry. Holey DMA has been aimed at 8 or 16 raster zones, but will have the same effect for other zone sizes. MARIA can be told to interpret odd 4K blocks as zeros, for 16 high zones, or odd 2K blocks as zeros for 8 high zones. This will only work for addresses above x '8000'. This means that these blocks can hold meaningful code, or tables, or graphics data used in a zone where Holey DMA is not on.&lt;br /&gt;
&lt;br /&gt;
One of the bits of a DLL entry tells MARIA to generate a Display List Interrupt (DLI) for that zone. The interrupt will actually occur following DMA on the last line of the PREVIOUS zone. This interrupt is non-maskable, and causes the processor to go to the address specified by the NMI vector at x 'FFFA' and x 'FFFB'. This interrupt in no way affects DMA, so processing will still be suspended at the beginning of the next raster.&lt;br /&gt;
&lt;br /&gt;
The format of a 3 byte DLL entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''3-byte DLL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | DLI: List Interrupt flag. 0=no DLI for this zone. 1=DLI after DMA on the last line of the previous zone. &lt;br /&gt;
 | H16: 16-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | H8: 8-line Holey DMA enable. 0=Holey DMA disabled. 1=Holey DMA enabled.&lt;br /&gt;
 | 0&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Offset: The height of the zone, minus 1. &lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High DL Address: DLLs can cross as many page boundaries as desired. A DLL must be stored in RAM, due to required access time.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low DL Address&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===MODES===&lt;br /&gt;
====DMA Modes====&lt;br /&gt;
There are two modes for specifying graphics data. The first, called Direct mode, is what has just been explained, where a Header (in the Display List) points directly to graphics data.&lt;br /&gt;
&lt;br /&gt;
The other mode is called Indirect or Character/Tile mode, and is somewhat different in that the Header points to a Character Map, which in turn points to graphics data. Indirect mode is selected by every header that requires it via an extended (5 byte long) header. The format of this header is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''5-byte DL entry'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! &amp;amp;nbsp;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 0&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Low Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 1&lt;br /&gt;
 | Write Mode bit: 0=160x2 or 320x1, 1=160x4 or 320x2.&lt;br /&gt;
 | 1&lt;br /&gt;
 | Indirect mode bit: 0=direct, 1=indirect mode.&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 | 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 2&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | High Address of graphics data.&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 3&lt;br /&gt;
 | colspan=&amp;quot;3&amp;quot; | Palette:&lt;br /&gt;
 | colspan=&amp;quot;5&amp;quot; | Width:&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! byte 4&lt;br /&gt;
 | colspan=&amp;quot;8&amp;quot; | Horizontal Position: X location on the screen where left edge of graphics is to be placed. Values 0-159 cover the visible screen, while other values are off-screen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
There is an added bonus to five byte headers. Because the end of DMA is indicated by the presence of a zero in the second byte of a header, and in a five byte header the width byte is not the second but the fourth, a width of zero is valid in an extended header, and will be interpreted as a value of 32.&lt;br /&gt;
&lt;br /&gt;
Indirect mode, when selected, only lasts as long as the corresponding header is being processed. MARIA will return to Direct mode before the next header is read.&lt;br /&gt;
&lt;br /&gt;
In indirect mode, the width indicates how many Character Map references to make, where each Character Map entry points to one byte of graphics data (the Character Map can point to two (2) consecutive bytes of graphics; see CTRL under REGISTERS). The idea behind Character (Indirect) mode is to specify a great amount of graphics with only one Header. The graphics start at the horizontal location specified by the Header and each character (graphics referred to by one Character Map entry) is inserted to the right of the previous one. One Character may be changed without affecting the others by altering the Character Map entry corresponding to that character. This is ideally suited for backgrounds such as the maze and dots in Ms. Pacman.&lt;br /&gt;
&lt;br /&gt;
The Character Map is composed by W entries, where W is the specified width and each entry is one byte long. Each entry is a Low address byte of a character, and the High address byte is specified by the Character Base register (see CHARBASE under REGISTERS). This means that each character on a scan line must have the same high address byte (sit on the same 256 byte page).&lt;br /&gt;
&lt;br /&gt;
=====Display Modes=====&lt;br /&gt;
The normal display mode is 160 mode, where the screen is divided into 160 pixels horizontally. Typically graphics are done in 160x2 mode, where there are two color bits specified for each pixel, and these two color bits refer to one of the eight palettes. Alternately, one may specify graphics in 160x4 mode, where there are four color bits per pixel. In this mode, each byte of graphics data would specify only two (2) pixels of graphics. If higher resolution is preferred, 320x1 mode is the common choice, where the screen is divided into 320 pixels horizontally and each pixel has one color bit. A more colorful 320x2 mode is also available with two color bits per pixel.&lt;br /&gt;
&lt;br /&gt;
Selection of a particular mode is accomplished through two separate operations: specification of WRITE MODE, and specification of READ MODE. WRITE MODE is specified via the extended (5 byte) header, as described above. READ MODE is specified via the CTRL register. Both of these specifications will remain in effect until respecified. WRITE MODE is not initialized by MARIA on power-up, and must be initialized by the cartridge before any display occurs.&lt;br /&gt;
&lt;br /&gt;
The reason for specifying WRITE MODE via an extended header, is to allow the programmer to change from 160x2 to 160x4 (or from 320x2 to 320x1, or vice-versa) during the DMA for a particular scan line. For more information about modes see CTRL under REGISTERS.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
The location of the MARIA registers which control the display is shown in Appendix 1, 7800 Memory Map.&lt;br /&gt;
&lt;br /&gt;
=====Palettes=====&lt;br /&gt;
The palette registers are used to specify colors for the graphics. There are eight palettes, and each&lt;br /&gt;
contains three colors. The colors themselves are specified in the form:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Color/Chroma&lt;br /&gt;
 | colspan=&amp;quot;4&amp;quot; | Luminosity&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
4 bits of color information and 4 bits of luminosity provide a total of 256 available hues.&lt;br /&gt;
&lt;br /&gt;
The palette registers are labeled P0C1, P0C2, P0C3, P1C1, P1C2, P1C3, P2C1, P2C2, P2C3, ... P7C1, P7C2, P7C3. A pixel whose two color bits are &amp;quot;10&amp;quot; and which refers to palette three (3) would be colored based on the value in P3C2. Color zero of any palette is transparent. Additionally, there is a&lt;br /&gt;
register called BACKGRND used to specify background color. All the palette and BACKGRND registers are write-only.&lt;br /&gt;
&lt;br /&gt;
=====OFFSET ($38)=====&lt;br /&gt;
The OFFSET register is a 4 bit value which gets added, automatically , to the high address byte on any graphics data fetch, whether Direct or Indirect. This register is internal to MARIA, and is set by each Display List List entry.&lt;br /&gt;
&lt;br /&gt;
=====CHARBASE ($34)=====&lt;br /&gt;
The CHARBASE register serves to specify the high address for any graphics data fetch in Character (Indirect) mode. As you recall, The Character Map (pointed to by the Header in the Display List) specifies the low address bytes of graphics data. Each of these low address bytes is concatenated with the sum of CHARBASE + OFFSET, to give the full 16 bit addresses of where the graphics data should be found. The CHARBASE register is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====DPPH ($2C)=====&lt;br /&gt;
DPPH stands for Display List Pointer Pointer High, and this is the register which contains the high address byte of the Display List List. This register is WRITE ONLY. The Display List List may cross as many page boundaries as desired. This register (and DPPL) should be written to before DMA is turned on. Once DMA is on, DPPH and DPPL may be written at any time, as they are only read at the beginning of the screen.&lt;br /&gt;
&lt;br /&gt;
=====DPPL ($30)=====&lt;br /&gt;
This register is used to specify the low address byte of the Display List List. It too, is WRITE ONLY.&lt;br /&gt;
&lt;br /&gt;
=====MSTAT ($28)=====&lt;br /&gt;
MSTAT is a READ ONLY register which communicates the status of Vertical Blank via bit 7 (MSB). When this bit is 1 VBLANK is on. When VBLANK turns off, DMA will begin according to your Display List. This transition occurs at raster 16 of the frame.&lt;br /&gt;
&lt;br /&gt;
=====CTRL ($3C)=====&lt;br /&gt;
The CTRL register is a WRITE ONLY register used to control many of the modes of MARIA. Through this register one can control whether the background color extends off the edge of the TV (horizontally), beyond the area where graphics may be positioned; or whether the background color stops at the horizontal limits of graphics and this border area appears black. This border area is an area which appears undependably on various television sets.&lt;br /&gt;
&lt;br /&gt;
CTRL also specifies whether characters (in Character mode) are one or two bytes wide. That is, in Character (Indirect) mode, whether one, or two bytes of graphics data should be fetched at the address pointed to by the Character Map entry and CHARBASE. The advantage of two byte characters is that the same number of pixels can be specified with half as many Character Map entries. The disadvantage is that when changing one character, twice as much of the screen is affected.&lt;br /&gt;
&lt;br /&gt;
This register also controls whether the color burst signal is generated or not. If color burst is turned off, the graphics are, of course, displayed in black and white, but with a greater clarity than if the gray scale colors (x'00' - x'0F') were used.&lt;br /&gt;
&lt;br /&gt;
Another bit of CTRL enables &amp;quot;Kangaroo&amp;quot; mode which eliminates transparency, so that any pixel of color &amp;quot;0&amp;quot; will be background color, rather than transparent. For the derivation of this name see the ATARI coin-op game Kangaroo.&lt;br /&gt;
&lt;br /&gt;
DMA may be turned on or off via the CTRL register. At power-up DMA is off, and must be turned on by the cartridge. This should not be done until after DPPL and DPPH have been stored (so that DMA doesn't try to read a DLL from an undefined location). DMA should be turned on DURING VBLANK, and never during the screen (rasters 16-258). If DMA is off the screen will continue to display the background color.&lt;br /&gt;
&lt;br /&gt;
Finally, CTRL is where the READ MODE portion of the graphics mode is selected (remember the WRITE MODE portion is selected via an extended header). WRITE mode controls the way data is written into Line RAM, and READ mode controls the way Line RAM is interpreted and translated to the screen. Because READ MODE affects the scan line being displayed, changes to READ MODE should happen at the beginning of the scan line to be affected.&lt;br /&gt;
&lt;br /&gt;
The WRITE MODE selects between 160x2/160x4 or 320x1/320x2. The Read mode selects between 320A/320C, 320B/320D, or 160A/160B, as the following table illustrates:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 50%; max-width: 320px;&amp;quot;&lt;br /&gt;
 |+'''Graphics Mode Selection'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! MODE !! Write Mode (in DL entry) !! Read Mode (in CTRL)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160A || 0 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 160B || 1 || 00&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320A || 0 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320B || 1 || 10&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320C || 1 || 11&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 320D || 0 || 10&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a true 320x1 mode. Pixels that are &amp;quot;on&amp;quot; refer to color two (2) of the specified palette. Pixels that are off are transparent (or background color if “Kangaroo&amp;quot; mode is on). In 320B mode, which is a 320x2 display mode, only the most significant palette bit is read. This means that either palette zero (0) of palette four (4) is used. If &amp;quot;Kangaroo&amp;quot; mode is off, transparency will work differently for modes. Consider a pair of 320-size pixels which make up one 160-size pixel. If either pixel of the pair is off, it will not be transparent, but will take on background color instead. If both pixels are off, they will be transparent. With &amp;quot;Kangaroo&amp;quot; mode on, things work as one would expect them to work in this mode. Another factor concerning 320 modes is that the horizontal positioning still happens like 160 mode. This means that in 320 modes, objects can only be positioned in 2 pixel increments.&lt;br /&gt;
&lt;br /&gt;
320C and 320D are display modes somewhat similar to 320B and 320A, respectively. They are what you would get if you changed WRITE mode without changing READ mode (such as changing modes during a scan line). If you were in 320A mode, and wanted to include a character with more colors on the line, changing modes would give you 320C mode. Likewise, changing from 320B on the fly would give you 320D mode. The way data is interpreted for 320C and 320D will be explained later on.&lt;br /&gt;
&lt;br /&gt;
In 160x4 mode, again only the most significant palette bit is read (note that 160x4 and 320B share the same WRITE mode sense). Because there are more color bits than each palette can handle, the palettes are combined in 160x4 mode so you may choose between the combinations of 0-3 and 4-7. The net result of 160x4 mode is twelve (12) colors, where color one (1) is P0C1 or P4C1, two (2) is P0C2 or P4C2, five (5) is P1C1 or P5C1, six (6) is P1C2 or P5C2, etc. and colors 0, 4, 8, and 12 are transparent.&lt;br /&gt;
&lt;br /&gt;
The CTRL register is arranged as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 90%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Color Register Layout'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | Color Kill: 0=normal color, 1=no color burst signal&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | DMA Control: 0,1=TEST DO NOT USE, as it could break the console. 2=normal DMA. 3=no DMA&lt;br /&gt;
 | Character Width: 0=single byte characters, 1=double byte characters&lt;br /&gt;
 | Border Control: 0=black screen border, 1=BACKGRND color border&lt;br /&gt;
 | Kangaroo Mode: 0=regular transparency, 1=kangaroo mode with no transparency&lt;br /&gt;
 | colspan=&amp;quot;2&amp;quot; | Read Mode: 0=160A/160B 1=N/A 2=320B/320D 3=320A/320C&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The coding of graphics data is straightforward for most of these modes. In 160A mode, each pair of bits is arranged so that the leftmost pixel's color is specified by the most significant pair of bits, and the rightmost pixel by the least significant pair of bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             76      54      32      10&lt;br /&gt;
                 ___     ___     ___     ___&lt;br /&gt;
pixels          |   |   |   |   |   |   |   |&lt;br /&gt;
                |___|   |___|   |___|   |___|&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |          160x2&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In 160B mode, the data is read as follows: the left pixel's color is specified by bits 3,2,7,6 (where 3 is MSB, 6 is LSB). The right pixel is specified by bits 1,0,5,4 (where 1 is MSB, 4 is LSB).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits             3276                    1054&lt;br /&gt;
                 ___                     ___&lt;br /&gt;
pixels          |   |                   |   |&lt;br /&gt;
                |___|                   |___|&lt;br /&gt;
                  |                       |&lt;br /&gt;
                  +---------------+       |&lt;br /&gt;
                  |               |       |          160x4&lt;br /&gt;
                  |       +---------------+&lt;br /&gt;
                  |       |       |       |&lt;br /&gt;
                 / \     / \     / \     / \&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphic       |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
320A mode is a direct mapping like 160x2, except that each bit specifies the color of one pixel. Note that while the table illustrates the bit to pixel relationship with different colors for each pixel+bit pair, 320A is a monochrome mode.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits            7   6   5   4   3   2   1   0&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |     320A(x1)&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The 320 modes get more complicated as we go on. The 320B mode bit to pixel mapping works as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bits           73        62      51        40&lt;br /&gt;
               ___       ___     ___       ___&lt;br /&gt;
pixels        |   |     |   |   |   |     |   |&lt;br /&gt;
              |___|     |___|   |___|     |___|&lt;br /&gt;
                |\       / \     / \       /|&lt;br /&gt;
                | \     /   \   /   \     / |&lt;br /&gt;
                |  \   /     \ /     \   /  |&lt;br /&gt;
                |   \ /       \       \ /   |&lt;br /&gt;
                |    /       / \       \    |&lt;br /&gt;
                |   | \     /   \     / |   |&lt;br /&gt;
                |   |  \   /     \   /  |   |&lt;br /&gt;
                |   |   \ /       \ /   |   |     320B(x2)&lt;br /&gt;
                |   |    /         \    |   |&lt;br /&gt;
                |   |   | \       / |   |   |&lt;br /&gt;
                |   |   |  \     /  |   |   |&lt;br /&gt;
                |   |   |   \   /   |   |   |&lt;br /&gt;
                |   |   |    \ /    |   |   |&lt;br /&gt;
                |   |   |     /     |   |   |&lt;br /&gt;
                |   |   |    / \    |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320C mode allows more colors than 320A, but cannot really be called 320x2. In this mode, some of the graphics data goes to specifying palettes, which is somewhat non-standard. If a pixel is on, it is color two (2), and if it is off, it is transparent, or background color (same as 320A and 320B). The palette is determined by combining the most significant palette. The palette for the leftmost pixel is specified by P2,D3, and D2 (where P means a palette bit, and D means graphics data bit), and the graphics are specified by D7. The next pixel right uses the same palette, and uses D6 for data. The next pixel right uses a palette specified by P2, D1, and D0, and uses D5 for data. The rightmost pixel uses the same palette, but D4 for data. The mapping for 320C mode is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits                         &amp;lt;P2&amp;gt;&amp;lt;D3&amp;gt;&amp;lt;D2&amp;gt;  &amp;lt;P2&amp;gt;&amp;lt;D1&amp;gt;&amp;lt;D0&amp;gt;&lt;br /&gt;
                             \__________/  \__________/ &lt;br /&gt;
color                             |             /&lt;br /&gt;
bits           D7  D6  D5  D4     |            /&lt;br /&gt;
                                  |           /&lt;br /&gt;
pixels          _   _   _   _     |          /&lt;br /&gt;
               | | | | | | | |    |         /&lt;br /&gt;
               |_| |_| |_| |_|    |        /&lt;br /&gt;
                |   |   |   |     |       |&lt;br /&gt;
                |   |   |   |     |       |      320C&lt;br /&gt;
                |   |   |   |    / \     / \&lt;br /&gt;
graphics       _|___|___|___|___|___|___|___|_&lt;br /&gt;
byte          |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
320D mode is a little confusing, too. Every pixel refers to the same palette but palette bits affect the color of the pixels. The only palette bit used for palette definition is the most significant bit (same as 320B), so only palettes zero (0) and four (4) will be referenced. For color selection there is really more than one bit per pixel. The graphics data bits are used as follows: each is the most significant bit for a two bit pair. But the least significant bit of this pair is either P0 or P1 (where P again means palette bit).&lt;br /&gt;
&lt;br /&gt;
If the specified palette is 0 or 4 (where P1 and P0 are zero), this is a normal 320x1 mode, like 320A. But if the specified palette is 5, palette 4 will be used, and certain pixels will be either color 1 or 3, and others will be 0 or 2. A picture is worth a thousand words, so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
palette&lt;br /&gt;
bits           P2  P2  P2  P2  P2  P2  P2  P2&lt;br /&gt;
&lt;br /&gt;
color          DP  DP  DP  DP  DP  DP  DP  DP&lt;br /&gt;
bits           71  60  51  40  31  20  11  00&lt;br /&gt;
               _______________________________&lt;br /&gt;
pixels        |   |   |   |   |   |   |   |   |&lt;br /&gt;
              |___|___|___|___|___|___|___|___|&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
                |   |   |   |   |   |   |   |    320D&lt;br /&gt;
                |   |   |   |   |   |   |   |&lt;br /&gt;
               _|___|___|___|___|___|___|___|_&lt;br /&gt;
graphics      |   |   |   |   |   |   |   |   |&lt;br /&gt;
byte          |___|___|___|___|___|___|___|___|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF TIA==&lt;br /&gt;
===Sound===&lt;br /&gt;
In TIA there are two audio circuits for generating sound. They are identical but completely independent and can be operated simultaneously to produce sound effects through the TV speaker. Each audio circuit has three registers that control a noise-tone generator (what kind of sound), a frequency selection (high or low pitch of the sound), and a volume control.&lt;br /&gt;
&lt;br /&gt;
====Tone====&lt;br /&gt;
The noise-tone generator is controlled by writing to the 4 bit audio control registers (AUDC0, AUDC1). The values written cause different kinds of sounds to be generated. Some are pure tones like a flute, others have various &amp;quot;noise&amp;quot; content like a rocket, motor, or explosion. Even though the TIA hardware manual lists the sounds created by each value, some experimentation will be necessary to find &amp;quot;your sound&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Frequency====&lt;br /&gt;
Frequency selection is controlled by writing to a 5 bit audio frequency register (AUDF0, AUDF1). The value written is used to divide a 30KHz reference frequency creating a higher or lower pitch of whatever type of sound is created by the noise-tone generator. By combining the pure tones available from the noise-tone generator with frequency selection, a wide range of tones can be generated.&lt;br /&gt;
&lt;br /&gt;
====Volume====&lt;br /&gt;
Volume is controlled by writing to a 4 bit audio volume register (AUDV0, AUDV1). Writing 0 to these registers turns sound off completely, and writing any value up to 15 increases the volume accordingly.&lt;br /&gt;
&lt;br /&gt;
====Registers====&lt;br /&gt;
&lt;br /&gt;
=====AUDF0/1 ($17/$18)=====&lt;br /&gt;
These addresses write data into the audio frequency divider registers.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDF# Effect On Frequency'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0 !! 30 KHz base frequency...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || 1 || divided by 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 0 || divided by 3&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || 1 || divided by 30&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 0 || divided by 31&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 1 || divided by 32&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDC0/1 ($15/$16)=====&lt;br /&gt;
These addresses write data into the audio control registers which control the noise content and additional division of the audio output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDC# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! sound basis (divisor size, polycounter size)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || divided by 1&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || divided by 15, 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 1 || 5-bit poly to 4-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 0 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 0 || 1 || divided by 2. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 1 || 1 || 1 || 5-bit poly, div 2&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 0 || 9-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 0 || 1 || 5-bit poly&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 0 || divided by 31. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 0 || 1 || 1 || last 4-bits high&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 0 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 0 || 1 || divided by 6. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || divided by 93. pure&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || 5-bit poly, div 6&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====AUDV0/1 ($19/$1A)=====&lt;br /&gt;
&lt;br /&gt;
These addresses write data into the audio volume registers which set the pull down impedance driving the audio output pads.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''AUDV# Effect On Sound Content'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0 !! audio output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 0 || no output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 0 || 1 || lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0 || 0 || 1 || 0 || next to lowest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | ... || ... || ... || ... || ...&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 0 || next to highest output current&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || 1 || 1 || 1 || highest output current&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=====Input Ports INPT0/1/2/3=====&lt;br /&gt;
&lt;br /&gt;
The TIA input ports are used for joystick fire buttons, reading paddle positions, and the keyboard controller. See the &amp;quot;Port A - Hand Controllers&amp;quot; section of the 6532 Overview for more detail.&lt;br /&gt;
&lt;br /&gt;
==OVERVIEW OF 6532==&lt;br /&gt;
===The I/O Ports===&lt;br /&gt;
The two ports (Port A and Port B) are 8 bits wide and can be set for either input or output. Port A is used to interface to various hand-held controllers but Port B is dedicated to reading the status of the console switches and joystick buttons. &lt;br /&gt;
&lt;br /&gt;
====Port B - Console Switches and Joystick Buttons - SWCHB ($282)====&lt;br /&gt;
&lt;br /&gt;
Port B is read by addressing SWCHB (HEX 282) to determine the status of all the console switches according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHB Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P1 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | P0 difficulty switch. 0=(B)asic, 1=(A)dvanced&lt;br /&gt;
 | none&lt;br /&gt;
 | none&lt;br /&gt;
 | Pause. 0=pressed, 1=released&lt;br /&gt;
 | none&lt;br /&gt;
 | Game Select. 0=pressed, 1=released&lt;br /&gt;
 | Game Start. 0=pressed, 1=released&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Bits 2 and 4 are used to enable/disable the 2-button joystick mode. More details on this are in the Joystick Controllers section.&lt;br /&gt;
&lt;br /&gt;
====Port A – Hand Controllers - SWCHA ($281)====&lt;br /&gt;
&lt;br /&gt;
Port A is under full software control to be configured as an input or an output port. It can then be used to read or control various hand-held controllers with the data bits defined differently depending on the type of controller used.&lt;br /&gt;
&lt;br /&gt;
=====Setting for Input or Output=====&lt;br /&gt;
&lt;br /&gt;
Port A has an 8 bit wide Data Direction Register (DDR) that is written to at CTLSWA (HEX 281) to set each individual pin of Port A to either input or output. The Port A pins are labeled PA0 thru PA7, and writing a &amp;quot;0&amp;quot; to a pins' DDR bit sets that pin as input, and a &amp;quot;1&amp;quot; sets it as an output. For example,&lt;br /&gt;
writing all 0's to CTLSWA (the DDR for Port A) sets PA0 thru PA7 (all 8 pins of Port A) as inputs. If F0 (11110000) were written to CTLSWA then PA7, PA6, PA5 &amp;amp; PA4 would be outputs, and PA3, PA2, PA1 &amp;amp; PA0 would be inputs.&lt;br /&gt;
&lt;br /&gt;
=====Inputting and Outputting=====&lt;br /&gt;
&lt;br /&gt;
Once the DDR has set the pins of Port A for input or output they may be read or written to by addressing SWCHA (HEX 280).&lt;br /&gt;
&lt;br /&gt;
=====Joystick Controllers=====&lt;br /&gt;
&lt;br /&gt;
Two joysticks can be read by configuring the entire port as input and reading the data at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''SWCHA Register Bits'''&lt;br /&gt;
 |-&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 right&lt;br /&gt;
 | P0 left&lt;br /&gt;
 | P0 down&lt;br /&gt;
 | P0 up&lt;br /&gt;
 | P1 right&lt;br /&gt;
 | P1 left&lt;br /&gt;
 | P1 down&lt;br /&gt;
 | P1 up&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;0&amp;quot; in a data bit indicates the joystick has been moved to close that switch. All &amp;quot;1's&amp;quot; in a player's nibble indicates that the joystick is not moving.&lt;br /&gt;
&lt;br /&gt;
You can read single-button joystick button state from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT4 || P0 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT5 || P1 || Bit 7=0 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your game requires both joystick fire buttons, you need to turn on two-button mode by performing this initial setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LDA #$14&lt;br /&gt;
STA CTLSWB ; set bits 2 and 4 of PORT B for output&lt;br /&gt;
LDA #0&lt;br /&gt;
STA SWCHB ; output 0 on bits 2 and 4 of PORT B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After which, the joystick button state can be read from these TIA registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPT Single-Button Reading'''&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 ! Register !! Button !! Bit&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT0 || P0, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT1 || P0, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT2 || P1, right button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | INPT3 || P1, left button || Bit 7=1 if the button is pushed&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Reading in two button mode when the console has a one button joystick plugged-in isn't recommended, and may be harmful to the console if done for an extended period. A two button game should check for one button presses via INPT4/5, and if detected the game should turn off two button support for that joystick by setting the appropriate SWCHB bits high. (bit 2=player 0 joystick, bit 4=player 1 joystick)&lt;br /&gt;
&lt;br /&gt;
=====Paddle (pot) Controllers=====&lt;br /&gt;
&lt;br /&gt;
Only the paddle triggers are read from the 6532. The paddles themselves are read at INPT0 thru INPT3 of the TIA. The paddle triggers can be read at SWCHA according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Paddle Button Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 button&lt;br /&gt;
 | P1 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 | P2 button&lt;br /&gt;
 | P3 button&lt;br /&gt;
 | N/A&lt;br /&gt;
 | N/A&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Keyboard Controllers=====&lt;br /&gt;
The keyboard controller has 12 buttons arranged into 4 rows and 3 columns. A signal is sent to a row, then the columns are checked to see if a button is pushed, then the next row is signaled and all columns sensed, etc. until the entire keyboard is scanned and sensed. The 6532 sends the signals to the rows, and the columns are sensed by reading INPT0, INPT1, and INPT4 of the TIA. With Port A configured as an output port, the data bits will send a signal to the keyboard controller rows according to the following table:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! bit 7 !! bit 6 !! bit 5 !! bit 4 !! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | P0 fourth row&lt;br /&gt;
 | P0 third row&lt;br /&gt;
 | P0 second row&lt;br /&gt;
 | P0 first row&lt;br /&gt;
 | P1 fourth row&lt;br /&gt;
 | P1 third row&lt;br /&gt;
 | P1 second row&lt;br /&gt;
 | P1 first row&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Note: a delay of 400 microseconds is necessary between writing to this port and reading the TIA input ports.&lt;br /&gt;
&lt;br /&gt;
===Register Summary===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''Keyboard Controller Reading'''&lt;br /&gt;
 ! Address !! Mnemonic !! Purpose&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $280 || SWCHA || Port A, input or output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $281 || CTLSWA || Port A DDR, 0=input, 1=output&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $282 || SWCHB || Port B, console switches&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | $283 || CTLSWB || Port B DDR&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==INPTCTRL REGISTER ($01)==&lt;br /&gt;
&lt;br /&gt;
The INPTCTRL register is responsible for switching and locking the 7800 into either 2600 or 7800 mode. It's a write-only register mapped to $0000-$001F, and controlled by external circuitry.&lt;br /&gt;
INPTCTRL's address range overlaps TIA's address range. As a consequence, once this register is set you need to also set the lock bit (see below) before you can use the TIA.&lt;br /&gt;
&lt;br /&gt;
There are 4 bits in the register:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;table-layout: fixed; width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''INPTCTRL Bits'''&lt;br /&gt;
 ! bit 3 !! bit 2 !! bit 1 !! bit 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | TIA-EN: 1 = enable TIA video pull-ups (video output is TIA instead of MARIA) and also disables 2 button joystick mode, 0 = disable TIA video pull-ups (video output is MARIA instead of TIA).&lt;br /&gt;
 | EXT: 0 = enable BIOS at $8000-$FFFF, 1 = disable BIOS / enable cartridge&lt;br /&gt;
 | MARIA Enable: 1 = enable MARIA (also enables system RAM), 0 = disable MARIA&lt;br /&gt;
 | Lock Mode: When set to 1 this bit locks the control register so that no more writes will affect it. The only way to clear the lock is to power cycle the console.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
In addition to the functions controlled by the register bits, INPTCTRL also controls the HALT input to the 6502. When the 7800 is first powered up HALT is blocked from getting to the 6502, but after 2 writes to the control register (the data written doesn’t make a difference), the HALT input will be enabled.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 1: 7800 MEMORY MAP==&lt;br /&gt;
&lt;br /&gt;
The memory map of the 7800, graphically illustrated on the next page, is in many ways similar to that of the 2600, with the addition not only of MARIA, but also of 4K of RAM. This RAM is shadowed (responds to other addresses) in zero, first, second, and third pages, the first two of these being significant. You will notice the absence of the 128 bytes of 6532 RAM that make up zero page RAM in the 2600. This is because of a speed discrepancy with the 6532. It's RAM has moved to an area in page four (4) and may not exist in future versions of the MARIA chip, so it should not be used.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Device Mappings, address lines'''&lt;br /&gt;
 ! &amp;amp;nbsp; !! &amp;amp;nbsp; !! From !! To&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1 || TIA || 0000 00XX 0000 0000 || 0000 00XX 0001 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2 || MARIA || 0000 00XX 0010 0000 || 0000 00XX 0011 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3 || 6532 Ports || 0000 001X 1XX0 0000 || 0000 001X 1XX1 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 4 || 6532 RAM (don't use) || 0000 010X 1000 0000 || 0000 010X 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 5 || RAM || 0001 1000 0000 0000 || 0010 0111 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 6 || RAM Shadow || 00X0 000A 0100 0000 || 00X0 000A 1111 1111&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 7 || RAM Shadow || 0010 X000 0000 0000 || 0010 X111 1111 1111&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where X means &amp;quot;Don't Care&amp;quot;, and A means the bits may be 1 or 0, but are not ignored. Entries 5 and 6 indicate that pieces of RAM from x'1800' - x'27FF' appear in zero, and first pages. The last entry indicates that the last 2K block (x'2000' - x'27FF') is repeated at x'2800'. For encryption purposes, the 120 bytes from x'FF80' - x'FFF7' must be left free. Put FFs in this area until encrypted.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |+'''Memory Map, absolute'''&lt;br /&gt;
 ! Locations !! Device&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0000 to 001F || TIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0020 to 003F || MARIA Registers&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0040 to 00FF || RAM (6116 Block Zero)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0100 to 013F || Shadow of Page 0&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0140 to 01FF || RAM (6116 Block One)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0200 to 027F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0280 to 02FF || 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0300 to 037F || Shadowed&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0380 to 03FF || Shadowed 6532 Ports&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0400 to 047F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0480 to 04FF || 6532 RAM. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0500 to 057F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0580 to 05FF || 6532 RAM Shadow. Don't Use&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 0600 to 17FF || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 1800 to 203F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2040 to 20FF || Block Zero Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2100 to 213F || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2140 to 21FF || Block One Shadow&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2200 to 27FF || RAM&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 2800 to 2FFF || Unavailable for mapping by external devices. (BIOS conflict)&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | 3000 to FF7F || Available for mapping by external devices&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FF80 to FFF7 || Reserved for cart encryption signature&lt;br /&gt;
 |- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
 | FFF8 to FFFF || Reserved for startup flags and 6502 vectors&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 2: STANDARD 7800 EQUATES==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;****** 00-1F ********* TIA REGISTERS ******************&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01     ;Input control                                write-only&lt;br /&gt;
&lt;br /&gt;
INPT0    = $08     ;Paddle Control Input 0                       read-only&lt;br /&gt;
INPT1    = $09     ;Paddle Control Input 1                       read-only&lt;br /&gt;
INPT2    = $0A     ;Paddle Control Input 2                       read-only&lt;br /&gt;
INPT3    = $0B     ;Paddle Control Input 3                       read-only&lt;br /&gt;
&lt;br /&gt;
; ** some common alternate names for INPT0/1/2/3&lt;br /&gt;
INPT4B   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4A   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5B   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5A   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
INPT4R   = $08     ;Joystick 0 Fire 0                            read-only&lt;br /&gt;
INPT4L   = $09     ;Joystick 0 Fire 1                            read-only&lt;br /&gt;
INPT5R   = $0A     ;Joystick 1 Fire 0                            read-only&lt;br /&gt;
INPT5L   = $0B     ;Joystick 1 Fire 1                            read-only&lt;br /&gt;
&lt;br /&gt;
INPT4    = $0C     ;Player 0 Fire Button Input                   read-only&lt;br /&gt;
INPT5    = $0D     ;Player 1 Fire Button Input                   read-only&lt;br /&gt;
&lt;br /&gt;
AUDC0    = $15     ;Audio Control Channel 0                      write-only&lt;br /&gt;
AUDC1    = $16     ;Audio Control Channel 1                      write-only&lt;br /&gt;
AUDF0    = $17     ;Audio Frequency Channel 0                    write-only&lt;br /&gt;
AUDF1    = $18     ;Audio Frequency Channel 1                    write-only&lt;br /&gt;
AUDV0    = $19     ;Audio Volume Channel 0                       write-only&lt;br /&gt;
AUDV1    = $1A     ;Audio Volume Channel 1                       write-only&lt;br /&gt;
&lt;br /&gt;
;****** 20-3F ********* MARIA REGISTERS ***************&lt;br /&gt;
&lt;br /&gt;
BACKGRND = $20     ;Background Color                             write-only&lt;br /&gt;
P0C1     = $21     ;Palette 0 - Color 1                          write-only&lt;br /&gt;
P0C2     = $22     ;Palette 0 - Color 2                          write-only&lt;br /&gt;
P0C3     = $23     ;Palette 0 - Color 3                          write-only&lt;br /&gt;
WSYNC    = $24     ;Wait For Sync                                write-only&lt;br /&gt;
P1C1     = $25     ;Palette 1 - Color 1                          write-only&lt;br /&gt;
P1C2     = $26     ;Palette 1 - Color 2                          write-only&lt;br /&gt;
P1C3     = $27     ;Palette 1 - Color 3                          write-only&lt;br /&gt;
MSTAT    = $28     ;Maria Status                                 read-only&lt;br /&gt;
P2C1     = $29     ;Palette 2 - Color 1                          write-only&lt;br /&gt;
P2C2     = $2A     ;Palette 2 - Color 2                          write-only&lt;br /&gt;
P2C3     = $2B     ;Palette 2 - Color 3                          write-only&lt;br /&gt;
DPPH     = $2C     ;Display List List Pointer High               write-only&lt;br /&gt;
P3C1     = $2D     ;Palette 3 - Color 1                          write-only&lt;br /&gt;
P3C2     = $2E     ;Palette 3 - Color 2                          write-only&lt;br /&gt;
P3C3     = $2F     ;Palette 3 - Color 3                          write-only&lt;br /&gt;
DPPL     = $30     ;Display List List Pointer Low                write-only&lt;br /&gt;
P4C1     = $31     ;Palette 4 - Color 1                          write-only&lt;br /&gt;
P4C2     = $32     ;Palette 4 - Color 2                          write-only&lt;br /&gt;
P4C3     = $33     ;Palette 4 - Color 3                          write-only&lt;br /&gt;
CHARBASE = $34     ;Character Base Address                       write-only&lt;br /&gt;
P5C1     = $35     ;Palette 5 - Color 1                          write-only&lt;br /&gt;
P5C2     = $36     ;Palette 5 - Color 2                          write-only&lt;br /&gt;
P5C3     = $37     ;Palette 5 - Color 3                          write-only&lt;br /&gt;
OFFSET   = $38     ;Unused - Store zero here                     write-only&lt;br /&gt;
P6C1     = $39     ;Palette 6 - Color 1                          write-only&lt;br /&gt;
P6C2     = $3A     ;Palette 6 - Color 2                          write-only&lt;br /&gt;
P6C3     = $3B     ;Palette 6 - Color 3                          write-only&lt;br /&gt;
CTRL     = $3C     ;Maria Control Register                       write-only&lt;br /&gt;
P7C1     = $3D     ;Palette 7 - Color 1                          write-only&lt;br /&gt;
P7C2     = $3E     ;Palette 7 - Color 2                          write-only&lt;br /&gt;
P7C3     = $3F     ;Palette 7 - Color 3                          write-only&lt;br /&gt;
&lt;br /&gt;
;****** 280-2FF ******* PIA PORTS AND TIMERS ************&lt;br /&gt;
&lt;br /&gt;
SWCHA    = $280    ;P0, P1 Joystick Directional Input            read-write&lt;br /&gt;
SWCHB    = $282    ;Console Switches                             read-write&lt;br /&gt;
CTLSWA   = $281    ;I/O Control for SCHWA                        read-write&lt;br /&gt;
SWACNT   = $281    ;VCS name for above                           read-write&lt;br /&gt;
CTLSWB   = $283    ;I/O Control for SCHWB                        read-write&lt;br /&gt;
SWBCNT   = $283    ;VCS name for above                           read-write&lt;br /&gt;
&lt;br /&gt;
INTIM    = $284    ;Iterval Timer Read                           read-only&lt;br /&gt;
TIM1T    = $294    ;Set 1    CLK Interval (838   nsec/interval)  write-only&lt;br /&gt;
TIM8T    = $295    ;Set 8    CLK Interval (6.7   usec/interval)  write-only&lt;br /&gt;
TIM64T   = $296    ;Set 64   CLK Interval (63.6  usec/interval)  write-only&lt;br /&gt;
T1024T   = $297    ;Set 1024 CLK Interval (858.2 usec/interval)  write-only&lt;br /&gt;
TIM64TI  = $29E    ;Interrupt timer 64T                          write-only&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 3: DMA TIMING==&lt;br /&gt;
&lt;br /&gt;
There is some uncertainty as to the number of cycles DMA will require, because the internal MARIA chip timing resolution is 7.16 MHz, while the 6502 runs at either 1.79 MHz or 1.19MHz. As a result, it is not known how many extra cycles will be needed in DMA startup/shutdown to make the 6502 happy.&lt;br /&gt;
&lt;br /&gt;
It is even possible for the 6502 to be in the middle of a long (TIA or 6532) access when it is to be halted, so the uncertainty goes up to about 5 cycles.&lt;br /&gt;
&lt;br /&gt;
All times listed below refer to 7.16 MHz cycles.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 80%; max-width: 640px;&amp;quot;&lt;br /&gt;
 |+'''DMA Timing'''&lt;br /&gt;
 ! Event !! MARIA Cycle Cost !! Comments&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, last line in zone || 24 cycles || rowspan=&amp;quot;2&amp;quot; | The DMA start-up may be delayed if the 6502 clock isn't at the end of a cycle when DMA begins. Up to 3 additional cycles are lost for DMA if the 6502 is at normal speed, or up to 5 additional cycles are lost if the 6502 happens to be slowed down for TIA access. DMA start-up delay usually occurs every other scanline, since a scanline length is 113.5 6502 cycles long.&lt;br /&gt;
 |-&lt;br /&gt;
 | DMA start-up and shutdown, other lines in zone || 16 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 4-byte DL header || 8 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | process 5-byte DL header || 10 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | direct graphics data read || 3 cycles || per byte of data read&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 1-byte read || 6 cycles&lt;br /&gt;
 |-&lt;br /&gt;
 | indirect 2-byte read || 9 cycles&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
If holey DMA is enabled and graphics reads would reside in a DMA hole, only 3 cycles of penalty for the graphic read is incurred, whatever the sprite width is.&lt;br /&gt;
&lt;br /&gt;
The end of VBLANK is made up of a DMA startup plus a Long shutdown.&lt;br /&gt;
&lt;br /&gt;
DMA does not begin until 7 CPU (1.79 MHz) cycles into each scan line. The significance of this is that there is enough time to change a color, or change CTRL before DMA begins, and during HBLANK (before display begins). This figure should, however, be included in any DMA usage calculations.&lt;br /&gt;
&lt;br /&gt;
Another timing consideration is there is one MPU (7.16 MHz) cycle between DMA shutdown and generation of a DLI.&lt;br /&gt;
&lt;br /&gt;
==APPENDIX 4: FRAME TIMING==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             33.5 cycles @1.79 MHz       80 cycles @1.79 MHz&lt;br /&gt;
              134 cycles @7.16 MHz      320 cycles @7.16 MHz&lt;br /&gt;
    NTSC    &amp;lt;--67 pixels--&amp;gt; &amp;lt;-----------160 pixels-------------&amp;gt;   PAL&lt;br /&gt;
     ______|_______________|____________________________________|_____&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      16   |&amp;lt;---HBLANK----&amp;gt;|               VBLANK               |   16&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
______v____|_______________|__________________v_________________|___v______&lt;br /&gt;
 ^    ^    |               |                  ^                 |   ^    ^&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    25   |               |                  |                 |   25   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
243  192   |               |               VISIBLE              |  242  293&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |   -v----|---------------|------------------|-----------------|---v-   |&lt;br /&gt;
 |    ^    |               |                  |                 |   ^    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    26   |               |                  |                 |   26   |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
 |    |    |               |                  |                 |   |    |&lt;br /&gt;
_v____v____|_______________|__________________v_________________|___v____v_&lt;br /&gt;
      ^    |               |                  ^                 |   ^&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      4    |               |               VBLANK               |   4&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
      |    |               |                  |                 |   |&lt;br /&gt;
     _v____|_______________|__________________v_________________|___v_&lt;br /&gt;
           |&amp;lt;-------------------227 pixels---------------------&amp;gt;|&lt;br /&gt;
           |                    454 cycles @7.16 Mhz            |&lt;br /&gt;
                              113.5 cycles @1.79 MHz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=RIOT_limitations_and_workarounds&amp;diff=1308</id>
		<title>RIOT limitations and workarounds</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=RIOT_limitations_and_workarounds&amp;diff=1308"/>
				<updated>2026-07-05T17:41:12Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The 7800 Software Guide has the following to say about the RIOT chip...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...without a lot of technical explanation as to why this is. In fact, if you test this RIOT functionality, at first it would seem to be working just fine. However the longer you test with real world examples, you would discover that the RIOT timers and RAM are indeed sometimes unreliable.&lt;br /&gt;
&lt;br /&gt;
The Memory Map appendix of the Software Guide goes into a little more detail, blaming the RIOT RAM reliability issue on speed differences. While this may be true for access at Maria speeds, at 6502 speeds this explanation isn't the whole story.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why RIOT timers and RAM are unreliable in 7800 mode==&lt;br /&gt;
&lt;br /&gt;
There's are two main reasons why accessing RIOT timers and RAM is unreliable - DMA, and Maria's own logic failings.&lt;br /&gt;
&lt;br /&gt;
===DMA===&lt;br /&gt;
&lt;br /&gt;
When Maria halts the 6502 for DMA, it doesn't have a corresponding halt line for the RIOT chip, so RIOT continues to run while the 6502 is halted. If the halt begins in the middle of RIOT access, the address and write enable asserted by the 6502 will disappear on RIOT mid-operation.&lt;br /&gt;
&lt;br /&gt;
This may manifest differently on different consoles, with some consoles being seemly immune to the issue, likely due to rate of transition (hang-time) of the relevant lines when the 6502 is halted.&lt;br /&gt;
&lt;br /&gt;
The heavier the DMA is while you attempt to access RIOT timers or RAM, the more likely it is that you'll run into issues. Conversely, the reliability issues go away if Maria has DMA turned off. In fact, the 7800 BIOS actually turns off DMA and uses RIOT RAM to boot into 2600 mode.&lt;br /&gt;
&lt;br /&gt;
===Logic Problems===&lt;br /&gt;
&lt;br /&gt;
When the 6502 accesses TIA or RIOT addresses, Maria is responsible for slowing down the clock it feeds to these chips, as well as managing the chip enable and write enable lines. It seems to do a great job keeping track of the timing required for regular 6502 access modes - Absolute, Absolute Indexed, Indirect Indexed - but Maria's internal counters that manage the timings of the various lines go completely haywire when you try to execute code out of RIOT RAM.&lt;br /&gt;
&lt;br /&gt;
==Making RIOT timer and RAM operations more reliable==&lt;br /&gt;
&lt;br /&gt;
The easiest way to make the RIOT timer writes reliable in 7800 mode (without having to turn off DMA) is to double-check the value you've just tried to write, and repeat it if required...&lt;br /&gt;
&lt;br /&gt;
  Repeat64T&lt;br /&gt;
    lda #10&lt;br /&gt;
    sta TIM64T&lt;br /&gt;
    lda INTIM&lt;br /&gt;
    cmp #9 ; immediately reading the value returns what you stored, less 1.&lt;br /&gt;
    bne Repeat64T&lt;br /&gt;
&lt;br /&gt;
If you're checking INTIM during the visible screen, it should also be noted that DMA may make it difficult to catch the exact moment when 0 is reached, because the timer will switch to single-cycle resolution at the time. In this case you can either work with an offset value (e.g. add 10 to the timer value you want when setting the timer, and then act accordingly when INTIM is at 10 or less.) or you can use the RIOT interrupts, and just check TIMINT instead of INTIM.&lt;br /&gt;
&lt;br /&gt;
In theory you could take the same approach with RIOT RAM reads and writes, but in practise checking the consistency of reads and writes isn't tenable. If you wish to use RIOT RAM, it should probably be kept to periods of VBLANK, or when DMA is disabled.&lt;br /&gt;
&lt;br /&gt;
==Authorship==&lt;br /&gt;
&lt;br /&gt;
RIOT Limitations and Workarounds was written by Mike Saarna (aka RevEng) as original content for 7800.8bitdev.org.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Common_Emulator_Development_Issues&amp;diff=1304</id>
		<title>Common Emulator Development Issues</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Common_Emulator_Development_Issues&amp;diff=1304"/>
				<updated>2026-06-04T00:13:29Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==ROMs That Can Cause Issues With Incomplete Emulation==&lt;br /&gt;
&lt;br /&gt;
* Choplifter. If the line between the horizon isn't in the correct place, or moves, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Choplifter. If there's a glitch zone high in the sky, it means your TIA address space doesn't emulate a floating bus correctly.&lt;br /&gt;
* One On One. If the player can't advance past the option menu with a button press, it means the RIOT 2-button implementation is incomplete. The game does a partial 2-button setup, relying on default RIOT state.&lt;br /&gt;
* Worm! If the game can't be started at all, it means that the RIOT 2-button implementation is incompete. The game does a partial 2-button setup, relying on default RIOT state.&lt;br /&gt;
* Xenophobe. If the bottom row of the titlescreen graphic is the incorrect color, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Xenophobe. If all of the main action screen glitches periodically, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Ninja Golf. If the player number selection screen has squished graphics (displaying 160A graphics at 160B) then you need to account for non-zero DL terminators. Maria ignores bits 7 and 5, so your terminator check should be for &amp;quot;!(value &amp;amp; 0x5F)&amp;quot;.&lt;br /&gt;
* Crossbow. If all graphics appear garbled/in wrong mode then you need to account for non-zero DL terminators. Maria ignores bits 7 and 5, so your terminator check should be for &amp;quot;!(value &amp;amp; 0x5F)&amp;quot;.&lt;br /&gt;
* Planet Smashers. If the background starfield is replaced by glitched graphics, you aren't checking the entire 8000-BFFF range for the bankswitch hotspot. This game uses the BFFF hotspot. &lt;br /&gt;
* Alien Brigade. Corruption in the main screen can be caused by missing or incorrect DMA cycle penalties, whenever lots of objects are displayed in this game. &lt;br /&gt;
* Summer Games. If the Platform Diving event has a flickering line between the stands and pool deck, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Ace Of Aces. If the top line of sky bounces around, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Karateka. If during the second enemy stage, there is flickering in the bottom right area and/or the power meter, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* BallBlazer. If the music track is missing a voice, it's likely the Pokey random number generation is missing or broken.&lt;br /&gt;
* Pole Position II. If the track selection by joystick only allows selection between tracks 2 and 4, two emulation issues are the cause. 1. The first frame isn't starting in VBLANK -or- DMA is inaccurate. 2. The emulation host controls are only being populated in SWCHA once per frame. (The gory details - the PPII track selection routine reads SWCHA twice and assumes the same result for both. If that assumption is false, any move left will be undone when you stop moving left. On real hardware this isn't a likely event. On emulation with timing that splits the two SWCHA reads across frames, and only updates SWCHA contents once per frame, it's a guaranteed circumstance.) &lt;br /&gt;
* Klax. If the game starts up with black screen. you might need to change where the emulator starts in the screen, similar to Pole Position II. The Klax proto has a race condition, and has hit-or-miss startup on (some) real consoles too.&lt;br /&gt;
* Tower Toppler. If graphics are striped and ugly, it's due to missing composite video effects. On a composite video display, pixels that alternate intensity at 320 resolution should appear as a continuous area of &amp;quot;artifacting&amp;quot; color.&lt;br /&gt;
* Legend of Silverpeak. (homebrew) If the game crashes, you need to bankswitch to bank 0 prior to starting emulation.&lt;br /&gt;
* E.X.O. (homebrew) If some musical notes are silent or off-key, the pokey emulation needs cycle-accurate emulation of 16-bit joined channels, 1.79Mhz audio channels, two-tone, and &amp;quot;low pass&amp;quot; filtering. See the pokey section of [https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf The Altirra Hardware Reference Manual]. Accurate pokey emulations, for reference source, include Altirra (original), MAME/A7800 (original), JS7800 (prosystem derived).&lt;br /&gt;
* A.R.T.I. (homebrew) If some musical notes are silent or off-key, the pokey emulation needs cycle-accurate emulation of 16-bit joined channels, 1.79Mhz audio channels, two-tone, and &amp;quot;low pass&amp;quot; filtering. See the pokey section of [https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf The Altirra Hardware Reference Manual]. Accurate pokey emulations, for reference source, include Altirra (original), MAME/A7800 (original), JS7800 (prosystem derived).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ROMs That May Be Reported As Bugs, But Aren't==&lt;br /&gt;
* Tower Toppler. If the game keeps skipping levels, this is part of a level-skip feature that's activated by the difficulty switch position.&lt;br /&gt;
* Xenophobe. During the play player one level completion stats the last line of the ship is displayed in 320A instead of 160A like the rest of the ship. The result of this is last line appears as a series of alternating pixels.&lt;br /&gt;
* Commando. If the game doesn't play Pokey music, you have a dump with a bad A78 header.&lt;br /&gt;
* Xevious. If the ship shoots missiles and bombs, even when a 2-button stick is used, it's due to the difficulty switch position. This is a selectable feature.&lt;br /&gt;
* Super Huey UH-IX.  Flickering line at the lower right-side portion of the screen, between outside view and console.  Occurs under original hardware.&lt;br /&gt;
* Water Ski.  A rope 'ghost' line flickers to the left and right of where the actual real rope line is located.  Occurs under original hardware.&lt;br /&gt;
* Sentinel. Background music missing.  Check difficulty switches position.&lt;br /&gt;
* Super Skateboardin'.  Missing background melody.  Toggles via difficulty switches.&lt;br /&gt;
* Ikari Warriors.  No background music.  Music presence set by difficulty switches.&lt;br /&gt;
* Missing In Action.  Keeps rotating through start of level or player invincible.  Invincibility, taking damage, and level select are determined by difficulty switch settings.&lt;br /&gt;
* Bentley Bear's Crystal Quest.  Doesn't jump or walks too slow, can't run.  Check difficulty switch settings.  Set the Left Switch to the right &amp;amp; set the Right Switch to the left.&lt;br /&gt;
* Rikki &amp;amp; Vikki.  Sound effects volume too low or too high.  Difficulty switch settings control TIA (Sound effects) amplitude.&lt;br /&gt;
* Crazy Brix.  Controls not responding, can't start a game, or game freeze.  Check difficulty switches, tells game what controller types to expect.&lt;br /&gt;
* Armor Attack II.  Second button does not accelerate vehicle.  Difficulty switch setting toggle between pressing Up on joystick or Button 2 to accelerate.&lt;br /&gt;
* Galaxian.  Player's ship fires too fast or too slow.  Shot speed determined by difficulty switches.&lt;br /&gt;
* Plutos.  Always starts a 2 Player game.  Difficulty switch settings determine whether 1 Player or 2 Players simultaneous game.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Common_Emulator_Development_Issues&amp;diff=1303</id>
		<title>Common Emulator Development Issues</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Common_Emulator_Development_Issues&amp;diff=1303"/>
				<updated>2026-06-04T00:11:22Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==ROMs That Can Cause Issues With Incomplete Emulation==&lt;br /&gt;
&lt;br /&gt;
* Choplifter. If the line between the horizon isn't in the correct place, or moves, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Choplifter. If there's a glitch zone high in the sky, it means your TIA address space doesn't emulate a floating bus correctly.&lt;br /&gt;
* One On One. If the player can't advance past the option menu with a button press, it means the RIOT 2-button implementation is incomplete. The game does a partial 2-button setup, relying on default RIOT state.&lt;br /&gt;
* Worm! If the game can't be started at all, it means that the RIOT 2-button implementation is incompete. The game does a partial 2-button setup, relying on default RIOT state.&lt;br /&gt;
* Xenophobe. If the bottom row of the titlescreen graphic is the incorrect color, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Xenophobe. If all of the main action screen glitches periodically, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Ninja Golf. If the player number selection screen has squished graphics (displaying 160A graphics at 160B) then you need to account for non-zero DL terminators. Maria ignores bits 7 and 5, so your terminator check should be for &amp;quot;!(value &amp;amp; 0x5F)&amp;quot;.&lt;br /&gt;
* Crossbow. If all graphics appear garbled/in wrong mode then you need to account for non-zero DL terminators. Maria ignores bits 7 and 5, so your terminator check should be for &amp;quot;!(value &amp;amp; 0x5F)&amp;quot;.&lt;br /&gt;
* Planet Smashers. If the background starfield is replaced by glitched graphics, you aren't checking the entire 8000-BFFF range for the bankswitch hotspot. This game uses the BFFF hotspot. &lt;br /&gt;
* Alien Brigade. Corruption in the main screen can be caused by missing or incorrect DMA cycle penalties, whenever lots of objects are displayed in this game. &lt;br /&gt;
* Summer Games. If the Platform Diving event has a flickering line between the stands and pool deck, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Ace Of Aces. If the top line of sky bounces around, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* Karateka. If during the second enemy stage, there is flickering in the bottom right area and/or the power meter, it means that DMA cycle penalties or timing aren't accurate.&lt;br /&gt;
* BallBlazer. If the music track is missing a voice, it's likely the Pokey random number generation is missing or broken.&lt;br /&gt;
* Pole Position II. If the track selection by joystick only allows selection between tracks 2 and 4, two emulation issues are the cause. 1. The first frame isn't starting in VBLANK -or- DMA is inaccurate. 2. The emulation host controls are only being populated in SWCHA once per frame. (The gory details - the PPII track selection routine reads SWCHA twice and assumes the same result for both. If that assumption is false, any move left will be undone when you stop moving left. On real hardware this isn't a likely event. On emulation that splits the two reads across frames, and only updates SWCHA once per frame, it's a guaranteed circumstance.) &lt;br /&gt;
* Klax. If the game starts up with black screen. you might need to change where the emulator starts in the screen, similar to Pole Position II. The Klax proto has a race condition, and has hit-or-miss startup on (some) real consoles too.&lt;br /&gt;
* Tower Toppler. If graphics are striped and ugly, it's due to missing composite video effects. On a composite video display, pixels that alternate intensity at 320 resolution should appear as a continuous area of &amp;quot;artifacting&amp;quot; color.&lt;br /&gt;
* Legend of Silverpeak. (homebrew) If the game crashes, you need to bankswitch to bank 0 prior to starting emulation.&lt;br /&gt;
* E.X.O. (homebrew) If some musical notes are silent or off-key, the pokey emulation needs cycle-accurate emulation of 16-bit joined channels, 1.79Mhz audio channels, two-tone, and &amp;quot;low pass&amp;quot; filtering. See the pokey section of [https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf The Altirra Hardware Reference Manual]. Accurate pokey emulations, for reference source, include Altirra (original), MAME/A7800 (original), JS7800 (prosystem derived).&lt;br /&gt;
* A.R.T.I. (homebrew) If some musical notes are silent or off-key, the pokey emulation needs cycle-accurate emulation of 16-bit joined channels, 1.79Mhz audio channels, two-tone, and &amp;quot;low pass&amp;quot; filtering. See the pokey section of [https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf The Altirra Hardware Reference Manual]. Accurate pokey emulations, for reference source, include Altirra (original), MAME/A7800 (original), JS7800 (prosystem derived).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ROMs That May Be Reported As Bugs, But Aren't==&lt;br /&gt;
* Tower Toppler. If the game keeps skipping levels, this is part of a level-skip feature that's activated by the difficulty switch position.&lt;br /&gt;
* Xenophobe. During the play player one level completion stats the last line of the ship is displayed in 320A instead of 160A like the rest of the ship. The result of this is last line appears as a series of alternating pixels.&lt;br /&gt;
* Commando. If the game doesn't play Pokey music, you have a dump with a bad A78 header.&lt;br /&gt;
* Xevious. If the ship shoots missiles and bombs, even when a 2-button stick is used, it's due to the difficulty switch position. This is a selectable feature.&lt;br /&gt;
* Super Huey UH-IX.  Flickering line at the lower right-side portion of the screen, between outside view and console.  Occurs under original hardware.&lt;br /&gt;
* Water Ski.  A rope 'ghost' line flickers to the left and right of where the actual real rope line is located.  Occurs under original hardware.&lt;br /&gt;
* Sentinel. Background music missing.  Check difficulty switches position.&lt;br /&gt;
* Super Skateboardin'.  Missing background melody.  Toggles via difficulty switches.&lt;br /&gt;
* Ikari Warriors.  No background music.  Music presence set by difficulty switches.&lt;br /&gt;
* Missing In Action.  Keeps rotating through start of level or player invincible.  Invincibility, taking damage, and level select are determined by difficulty switch settings.&lt;br /&gt;
* Bentley Bear's Crystal Quest.  Doesn't jump or walks too slow, can't run.  Check difficulty switch settings.  Set the Left Switch to the right &amp;amp; set the Right Switch to the left.&lt;br /&gt;
* Rikki &amp;amp; Vikki.  Sound effects volume too low or too high.  Difficulty switch settings control TIA (Sound effects) amplitude.&lt;br /&gt;
* Crazy Brix.  Controls not responding, can't start a game, or game freeze.  Check difficulty switches, tells game what controller types to expect.&lt;br /&gt;
* Armor Attack II.  Second button does not accelerate vehicle.  Difficulty switch setting toggle between pressing Up on joystick or Button 2 to accelerate.&lt;br /&gt;
* Galaxian.  Player's ship fires too fast or too slow.  Shot speed determined by difficulty switches.&lt;br /&gt;
* Plutos.  Always starts a 2 Player game.  Difficulty switch settings determine whether 1 Player or 2 Players simultaneous game.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:YIQ-7800-warmup.gif&amp;diff=1302</id>
		<title>File:YIQ-7800-warmup.gif</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:YIQ-7800-warmup.gif&amp;diff=1302"/>
				<updated>2026-01-07T05:41:58Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: MSaarna uploaded a new version of File:YIQ-7800-warmup.gif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Atari 7800 color values shifting as the console warms up, overlaid on Y=0.5 IQ colorspace.&lt;br /&gt;
&lt;br /&gt;
Original U-V color plane underlay created by wikipedia.org user Tonyle.&lt;br /&gt;
&lt;br /&gt;
== Licensing ==&lt;br /&gt;
{{cc-by-sa-3.0}}&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:YIQ-7800-warmup.gif&amp;diff=1301</id>
		<title>File:YIQ-7800-warmup.gif</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:YIQ-7800-warmup.gif&amp;diff=1301"/>
				<updated>2026-01-07T05:36:06Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: MSaarna uploaded a new version of File:YIQ-7800-warmup.gif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Atari 7800 color values shifting as the console warms up, overlaid on Y=0.5 IQ colorspace.&lt;br /&gt;
&lt;br /&gt;
Original U-V color plane underlay created by wikipedia.org user Tonyle.&lt;br /&gt;
&lt;br /&gt;
== Licensing ==&lt;br /&gt;
{{cc-by-sa-3.0}}&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=The_7800_Minnie_sound_chip&amp;diff=1300</id>
		<title>The 7800 Minnie sound chip</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=The_7800_Minnie_sound_chip&amp;diff=1300"/>
				<updated>2026-01-07T00:54:54Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
&lt;br /&gt;
[[File:Minnie_die_shot_01.jpg|thumb|A die shot of the Minnie prototype]]&lt;br /&gt;
Minnie (GCC 1730) was a soundchip designed by GCC as an in-cart audio solution for the 7800 console. &lt;br /&gt;
&lt;br /&gt;
The original plan for the 7800 console was to include an onboard sound solution (in addition to TIA audio) but the Maria die space set aside for audio was needed for other core functionality. So GCC added an audio line to the 7800 cartridge port, and began adapting their previous work on the Gumby soundchip (a soundchip design previously developed for their Spring project) into a new Mini-Gumby soundchip, the &amp;quot;Minnie&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Although the Minnie design was completed - prototype chips were produced, and a &amp;quot;Minnie Rag&amp;quot; demo sang out within the walls at GCC - the chip ultimately never made it to production, due to the Warner sale of Atari to Jack Tramiel, which marked an end to GCC's relationship with Atari.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Capability Overview==&lt;br /&gt;
&lt;br /&gt;
The Minnie design is quite unique compared to other contemporary sound chips. The synthesis technique employed is Digital Wave Synthesis, where sample data is used to represent one cycle of the sound. There  were two rows of sample data and 3 predefined waveform rows, so the chip could also be driven in a Wavetable Synthesis fashion.&lt;br /&gt;
&lt;br /&gt;
Adjustable sound parameters include very fine-grained volume and frequency controls, and a noise parameter. The noise parameter could be used to adjust the wave phase of any of the voices in varying levels, achieving modulation effects ranging from slight frequency instability through to pitched noise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
* 3 voices&lt;br /&gt;
* 16-bit frequency resolution&lt;br /&gt;
* 28kHz sample rate with dynamic range of 10 bits&lt;br /&gt;
* 2 arbitrary 64-byte waveforms stored in on-chip ROM, which could differ per-game&lt;br /&gt;
* 3 standard waveforms: triangle, square, sawtooth&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Minnie and TIA audio was summed together, which added another 2 voices to the system, suitable for sound effects and percussion effects.&lt;br /&gt;
&lt;br /&gt;
Minnie relied on the CPU to adjust volume for achieving sound envelopes. This would have commonly occurred once per frame, along with any other sound parameter adjustments desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The GCC Minnie Documentation==&lt;br /&gt;
[[Media:Minnie_Subsystem_Top-Level_Specification_-_GCC-1730_(MGspec_19840221_sjg).pdf|The Minnie Subsystem Top-Level Specification]].&lt;br /&gt;
&lt;br /&gt;
[[Media:MiniGumby Sound_Synthesis_System,_Analog_Output_Section_Specification_-_GCC_1730_(analog_output_spec_19840203_sjg).pdf|MiniGumby Sound Synthesis System, Analog Output Section Specification.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Thanks==&lt;br /&gt;
Many thanks to Steve Golson, who provided the GCC technical documentation this article is based on. The documentation was found by Steve, in the personal files of Gary Boone.&lt;br /&gt;
&lt;br /&gt;
If you're at all interested in the GCC side of Atari history, or the 7800 at a technical level, you owe it to yourself to view Steve's talks and papers at: https://trilobyte.com/papers/&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:Minnie_die_shot_01.jpg&amp;diff=1299</id>
		<title>File:Minnie die shot 01.jpg</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:Minnie_die_shot_01.jpg&amp;diff=1299"/>
				<updated>2026-01-07T00:51:09Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: A die shot of GCC's Minnie sound chip&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A die shot of GCC's Minnie sound chip&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1298</id>
		<title>The SuperGame Format</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1298"/>
				<updated>2026-01-03T18:10:42Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SuperGame Format ==&lt;br /&gt;
&lt;br /&gt;
=== General Info ===&lt;br /&gt;
&lt;br /&gt;
The SuperGame cart mapper was created by GCC/Atari, and is still in use by modern homebrewers. The actual feature specification of SuperGame is a bit loose. The following is a quote from Eckhard Stolberg's [[ATARI 7800 BANKSWITCHING GUIDE]].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [...]there are several different types of Atari's SuperGame&lt;br /&gt;
  bankswitching. It basically consists of 8 16KB banks (0-7)&lt;br /&gt;
  that can be mapped in at $8000-$bfff. Bank 7 always is fixed&lt;br /&gt;
  at $c000-$ffff. To map in a chosen bank into $8000-$bfff you&lt;br /&gt;
  write it's bank number (0-7) to any address between $8000-bfff.&lt;br /&gt;
  The contend of $4000-$7fff differs between different variations&lt;br /&gt;
  of this type:&lt;br /&gt;
  &lt;br /&gt;
  Some games have nothing connected in this area and return only&lt;br /&gt;
  random data.&lt;br /&gt;
  &lt;br /&gt;
  Some games have bank 6 fixed at this area.&lt;br /&gt;
  &lt;br /&gt;
  Some games have 16K of extra ROM there. Those games are 144K&lt;br /&gt;
  in size and are marked as 78S9 in the list.&lt;br /&gt;
  &lt;br /&gt;
  Some games have either 8K of RAM at $6000-$7fff or 16K of&lt;br /&gt;
  RAM at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games have a POKEY chip mapped in at this area. It&lt;br /&gt;
  has 16 addresses that get repeated all the way between $4000&lt;br /&gt;
  and $7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games only have 4 ROM banks at $8000-$bfff (0-3). Banks&lt;br /&gt;
  4-7 either return the same data as banks 0-3 or completely&lt;br /&gt;
  random data. PAL Karateka is a special case. It only uses&lt;br /&gt;
  banks 4-7. Banks 0-3 are random data and bank 6 is also fixed&lt;br /&gt;
  at $4000-$7fff.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you generate rom files, any extra hardware features at $4000 can just be flagged via the A78 header, with the exception of having an extra 16K bank of rom placed there - for that you need to add an extra bank at the start of your rom with it's ORG being $4000, in addition to A78 header flagging.&lt;br /&gt;
&lt;br /&gt;
=== A basic 128k 7800 SuperGame Skeleton ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ; basic 128k 7800 supergame skeleton, with no rom@4000.&lt;br /&gt;
  ; banks 1-7 live at $8000-BFFF in 6502 address space&lt;br /&gt;
  ; bank 8 lives at $C000-FFFF in 6502 address space&lt;br /&gt;
  &lt;br /&gt;
  ORG       $8000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
 &lt;br /&gt;
  ; bank 1 code goes here ($8000-$BFFF)&lt;br /&gt;
 &lt;br /&gt;
  ORG       $C000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
&lt;br /&gt;
  ; bank 2 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $10000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 3 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $14000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 4 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $18000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 5 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $1C000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 6 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $20000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 7 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $24000&lt;br /&gt;
  RORG     $C000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 8 code goes here ($C000-$FFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $27FF8&lt;br /&gt;
  RORG     $FFF8&lt;br /&gt;
  ; 7800 bytes and 6502 vectors go here&lt;br /&gt;
  .byte.b  $FF     ; region verification. $FF=all regions&lt;br /&gt;
  .byte.b  $F7     ; high nibble: encryption check from $N000 to $FF7F.&lt;br /&gt;
  .word.w  NMI&lt;br /&gt;
  .word.w  START&lt;br /&gt;
  .word.w  IRQ&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1297</id>
		<title>The SuperGame Format</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1297"/>
				<updated>2026-01-03T18:09:58Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SuperGame Format ==&lt;br /&gt;
&lt;br /&gt;
=== General Info ===&lt;br /&gt;
&lt;br /&gt;
The SuperGame cart mapper was created by GCC/Atari, and is still in use by modern homebrewers. The actual feature specification of SuperGame is a bit loose. The following is a quote from Eckhard Stolberg's [[ATARI 7800 BANKSWITCHING GUIDE]].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [...]there are several different types of Atari's SuperGame&lt;br /&gt;
  bankswitching. It basically consists of 8 16KB banks (0-7)&lt;br /&gt;
  that can be mapped in at $8000-$bfff. Bank 7 always is fixed&lt;br /&gt;
  at $c000-$ffff. To map in a chosen bank into $8000-$bfff you&lt;br /&gt;
  write it's bank number (0-7) to any address between $8000-bfff.&lt;br /&gt;
  The contend of $4000-$7fff differs between different variations&lt;br /&gt;
  of this type:&lt;br /&gt;
  &lt;br /&gt;
  Some games have nothing connected in this area and return only&lt;br /&gt;
  random data.&lt;br /&gt;
  &lt;br /&gt;
  Some games have bank 6 fixed at this area.&lt;br /&gt;
  &lt;br /&gt;
  Some games have 16K of extra ROM there. Those games are 144K&lt;br /&gt;
  in size and are marked as 78S9 in the list.&lt;br /&gt;
  &lt;br /&gt;
  Some games have either 8K of RAM at $6000-$7fff or 16K of&lt;br /&gt;
  RAM at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games have a POKEY chip mapped in at this area. It&lt;br /&gt;
  has 16 addresses that get repeated all the way between $4000&lt;br /&gt;
  and $7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games only have 4 ROM banks at $8000-$bfff (0-3). Banks&lt;br /&gt;
  4-7 either return the same data as banks 0-3 or completely&lt;br /&gt;
  random data. PAL Karateka is a special case. It only uses&lt;br /&gt;
  banks 4-7. Banks 0-3 are random data and bank 6 is also fixed&lt;br /&gt;
  at $4000-$7fff.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you generate rom files, any extra hardware features at $4000 can just be flagged via the A78 header, with the exception of having an extra 16K bank of rom placed there - for that you need to add an extra bank at the start of your rom with it's ORG being $4000, in addition to A78 header flagging.&lt;br /&gt;
&lt;br /&gt;
=== A basic 7800 SuperGame Skeleton ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ; basic 128k supergame skeleton, with no rom@4000.&lt;br /&gt;
  ; banks 1-7 live at $8000-BFFF in 6502 address space&lt;br /&gt;
  ; bank 8 lives at $C000-FFFF in 6502 address space&lt;br /&gt;
  &lt;br /&gt;
  ORG       $8000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
 &lt;br /&gt;
  ; bank 1 code goes here ($8000-$BFFF)&lt;br /&gt;
 &lt;br /&gt;
  ORG       $C000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
&lt;br /&gt;
  ; bank 2 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $10000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 3 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $14000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 4 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $18000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 5 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $1C000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 6 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $20000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 7 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $24000&lt;br /&gt;
  RORG     $C000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 8 code goes here ($C000-$FFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $27FF8&lt;br /&gt;
  RORG     $FFF8&lt;br /&gt;
  ; 7800 bytes and 6502 vectors go here&lt;br /&gt;
  .byte.b  $FF     ; region verification. $FF=all regions&lt;br /&gt;
  .byte.b  $F7     ; high nibble: encryption check from $N000 to $FF7F.&lt;br /&gt;
  .word.w  NMI&lt;br /&gt;
  .word.w  START&lt;br /&gt;
  .word.w  IRQ&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1296</id>
		<title>The SuperGame Format</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1296"/>
				<updated>2026-01-03T18:08:40Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SuperGame Format ==&lt;br /&gt;
&lt;br /&gt;
=== General Info ===&lt;br /&gt;
&lt;br /&gt;
The SuperGame cart mapper was created by GCC/Atari, and is still in use by modern homebrewers. The actual feature specification of SuperGame is a bit loose. The following is a quote from Eckhard Stolberg's [[ATARI 7800 BANKSWITCHING GUIDE]].&lt;br /&gt;
&lt;br /&gt;
  [...]there are several different types of Atari's SuperGame&lt;br /&gt;
  bankswitching. It basically consists of 8 16KB banks (0-7)&lt;br /&gt;
  that can be mapped in at $8000-$bfff. Bank 7 always is fixed&lt;br /&gt;
  at $c000-$ffff. To map in a chosen bank into $8000-$bfff you&lt;br /&gt;
  write it's bank number (0-7) to any address between $8000-bfff.&lt;br /&gt;
  The contend of $4000-$7fff differs between different variations&lt;br /&gt;
  of this type:&lt;br /&gt;
  &lt;br /&gt;
  Some games have nothing connected in this area and return only&lt;br /&gt;
  random data.&lt;br /&gt;
  &lt;br /&gt;
  Some games have bank 6 fixed at this area.&lt;br /&gt;
  &lt;br /&gt;
  Some games have 16K of extra ROM there. Those games are 144K&lt;br /&gt;
  in size and are marked as 78S9 in the list.&lt;br /&gt;
  &lt;br /&gt;
  Some games have either 8K of RAM at $6000-$7fff or 16K of&lt;br /&gt;
  RAM at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games have a POKEY chip mapped in at this area. It&lt;br /&gt;
  has 16 addresses that get repeated all the way between $4000&lt;br /&gt;
  and $7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games only have 4 ROM banks at $8000-$bfff (0-3). Banks&lt;br /&gt;
  4-7 either return the same data as banks 0-3 or completely&lt;br /&gt;
  random data. PAL Karateka is a special case. It only uses&lt;br /&gt;
  banks 4-7. Banks 0-3 are random data and bank 6 is also fixed&lt;br /&gt;
  at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
When you generate rom files via assembly, any extra hardware features at $4000 can be flagged via the A78 header, with the exception of having an extra 16K bank of rom placed there - for that you need to add an extra bank at the start of your rom with it's ORG being $4000, in addition to A78 header flagging.&lt;br /&gt;
&lt;br /&gt;
=== A basic 7800 SuperGame Skeleton ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ; basic 128k supergame skeleton, with no rom@4000.&lt;br /&gt;
  ; banks 1-7 live at $8000-BFFF in 6502 address space&lt;br /&gt;
  ; bank 8 lives at $C000-FFFF in 6502 address space&lt;br /&gt;
  &lt;br /&gt;
  ORG       $8000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
 &lt;br /&gt;
  ; bank 1 code goes here ($8000-$BFFF)&lt;br /&gt;
 &lt;br /&gt;
  ORG       $C000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
&lt;br /&gt;
  ; bank 2 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $10000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 3 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $14000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 4 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $18000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 5 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $1C000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 6 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $20000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 7 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $24000&lt;br /&gt;
  RORG     $C000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 8 code goes here ($C000-$FFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $27FF8&lt;br /&gt;
  RORG     $FFF8&lt;br /&gt;
  ; 7800 bytes and 6502 vectors go here&lt;br /&gt;
  .byte.b  $FF     ; region verification. $FF=all regions&lt;br /&gt;
  .byte.b  $F7     ; high nibble: encryption check from $N000 to $FF7F.&lt;br /&gt;
  .word.w  NMI&lt;br /&gt;
  .word.w  START&lt;br /&gt;
  .word.w  IRQ&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1295</id>
		<title>The SuperGame Format</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=The_SuperGame_Format&amp;diff=1295"/>
				<updated>2026-01-03T18:07:59Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;== SuperGame Format ==  === General Info ===  The SuperGame cart mapper was created by GCC/Atari, and is still in use by modern homebrewers. The actual feature specification o...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SuperGame Format ==&lt;br /&gt;
&lt;br /&gt;
=== General Info ===&lt;br /&gt;
&lt;br /&gt;
The SuperGame cart mapper was created by GCC/Atari, and is still in use by modern homebrewers. The actual feature specification of SuperGame is a bit loose. The following is a quote from Eckhard Stolberg's [[ATARI 7800 BANKSWITCHING GUIDE]].&lt;br /&gt;
&lt;br /&gt;
  [...]there are several different types of Atari's SuperGame&lt;br /&gt;
  bankswitching. It basically consists of 8 16KB banks (0-7)&lt;br /&gt;
  that can be mapped in at $8000-$bfff. Bank 7 always is fixed&lt;br /&gt;
  at $c000-$ffff. To map in a chosen bank into $8000-$bfff you&lt;br /&gt;
  write it's bank number (0-7) to any address between $8000-bfff.&lt;br /&gt;
  The contend of $4000-$7fff differs between different variations&lt;br /&gt;
  of this type:&lt;br /&gt;
  &lt;br /&gt;
  Some games have nothing connected in this area and return only&lt;br /&gt;
  random data.&lt;br /&gt;
  &lt;br /&gt;
  Some games have bank 6 fixed at this area.&lt;br /&gt;
  &lt;br /&gt;
  Some games have 16K of extra ROM there. Those games are 144K&lt;br /&gt;
  in size and are marked as 78S9 in the list.&lt;br /&gt;
  &lt;br /&gt;
  Some games have either 8K of RAM at $6000-$7fff or 16K of&lt;br /&gt;
  RAM at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games have a POKEY chip mapped in at this area. It&lt;br /&gt;
  has 16 addresses that get repeated all the way between $4000&lt;br /&gt;
  and $7fff.&lt;br /&gt;
&lt;br /&gt;
  Some games only have 4 ROM banks at $8000-$bfff (0-3). Banks&lt;br /&gt;
  4-7 either return the same data as banks 0-3 or completely&lt;br /&gt;
  random data. PAL Karateka is a special case. It only uses&lt;br /&gt;
  banks 4-7. Banks 0-3 are random data and bank 6 is also fixed&lt;br /&gt;
  at $4000-$7fff.&lt;br /&gt;
&lt;br /&gt;
When you generate rom files via assembly, any extra hardware features at $4000 can be flagged via the A78 header, with the exception of having an extra 16K bank of rom placed there - for that you need to add an extra bank at the start of your rom with it's ORG being $4000, in addition to A78 header flagging.&lt;br /&gt;
&lt;br /&gt;
=== A basic 7800 SuperGame Skeleton ===&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
  ; basic 128k supergame skeleton, with no rom@4000.&lt;br /&gt;
  ; banks 1-7 live at $8000-BFFF in 6502 address space&lt;br /&gt;
  ; bank 8 lives at $C000-FFFF in 6502 address space&lt;br /&gt;
  &lt;br /&gt;
  ORG       $8000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
 &lt;br /&gt;
  ; bank 1 code goes here ($8000-$BFFF)&lt;br /&gt;
 &lt;br /&gt;
  ORG       $C000&lt;br /&gt;
  RORG      $8000&lt;br /&gt;
&lt;br /&gt;
  ; bank 2 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $10000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 3 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $14000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 4 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $18000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 5 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $1C000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 6 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $20000&lt;br /&gt;
  RORG     $8000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 7 code goes here ($8000-$BFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $24000&lt;br /&gt;
  RORG     $C000&lt;br /&gt;
  &lt;br /&gt;
  ; bank 8 code goes here ($C000-$FFFF)&lt;br /&gt;
  &lt;br /&gt;
  ORG      $27FF8&lt;br /&gt;
  RORG     $FFF8&lt;br /&gt;
  ; 7800 bytes and 6502 vectors go here&lt;br /&gt;
  .byte.b  $FF     ; region verification. $FF=all regions&lt;br /&gt;
  .byte.b  $F7     ; high nibble: encryption check from $N000 to $FF7F.&lt;br /&gt;
  .word.w  NMI&lt;br /&gt;
  .word.w  START&lt;br /&gt;
  .word.w  IRQ&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_Tutorials_and_Guides&amp;diff=1294</id>
		<title>7800 Tutorials and Guides</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_Tutorials_and_Guides&amp;diff=1294"/>
				<updated>2026-01-03T17:54:04Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Once you've read through an understood the [[7800 Software Guide]] and [[7800 Assembly Quick-Start]], the documents listed in this entry will help you master more advanced topics.&lt;br /&gt;
&lt;br /&gt;
==7800 Development Documents==&lt;br /&gt;
&lt;br /&gt;
===General Topics===&lt;br /&gt;
&lt;br /&gt;
The Atari authored [[7800 Software Guide]] is still the best place for learning about the 7800 hardware and development.&lt;br /&gt;
&lt;br /&gt;
The [[A78 Header Specification]] covers the purpose and various fields in the A78 header.&lt;br /&gt;
&lt;br /&gt;
The [https://atariage.com/forums/topic/333208-old-world-a78-format-10-31-primer/ Old World A78 Format Primer] covers v1.0 to v3.1 A78 header usage, with the intention of clarifying how the header should be parsed by emulators and flash-carts.&lt;br /&gt;
&lt;br /&gt;
See [[The SuperGame Format]] for a brief synopsis of how to create games compatible with the SuperGame mapper, a format created by GCC/Atari and still in use by homebrews today.&lt;br /&gt;
&lt;br /&gt;
[[Introduction to the MAME debugger]] covers basic usage of the built-in MAME debugger, an indispensable tool for the 7800 coder.&lt;br /&gt;
&lt;br /&gt;
[[Debugging On Ancient Game Platforms]] has suggestions on what to do when your homebrew project isn't going so well.&lt;br /&gt;
&lt;br /&gt;
===MARIA Focused===&lt;br /&gt;
&lt;br /&gt;
[[Atari 7800 Color Documentation]] covers how the 7800 generates its colors, with specific consideration to color selection for homebrew authors.&lt;br /&gt;
&lt;br /&gt;
[[Maria Display Structure Overview]] is a graphical overview of DL and DLL memory structures used to create the display.&lt;br /&gt;
&lt;br /&gt;
[[Importing Bitmap Graphics into Assembly Source Code with BMP7800]] covers the utility from Bob DeCrescenzo (aka PacManPlus)&lt;br /&gt;
&lt;br /&gt;
[[Maximizing 7800 Sprites]] discusses techniques that can be used for games that need a maximum number of moving objects.&lt;br /&gt;
&lt;br /&gt;
[https://7800.8bitdev.org/images/3/3c/7800_Software_Guide_-_The_Podcast_-_Graphics_Overview%2C_DLs%2C_DLLs%2C_etc.mp3 The 7800 Software Guide Podcast] is a bit of fun. It's an AI podcast generated with [https://notebooklm.google/ Google's NotebookLM tool].&lt;br /&gt;
&lt;br /&gt;
===TIA Sound===&lt;br /&gt;
&lt;br /&gt;
Eckhard Stolberg's [[Atari 2600 VCS Sound Frequency and Waveform Guide]] covers TIA musical frequencies.&lt;br /&gt;
&lt;br /&gt;
[[The Perceptual Tuning Primer]] covers an easy technique to keep TIA music sounding in tune.&lt;br /&gt;
&lt;br /&gt;
The [[Tune2600 Introduction]] covers using Thomas Jentzsch's Tune2600 utility to select your notes.&lt;br /&gt;
&lt;br /&gt;
[[TIA Arpeggio Tips]] provides helpful information for implementing arpeggios in your music.&lt;br /&gt;
&lt;br /&gt;
===6532 RIOT===&lt;br /&gt;
&lt;br /&gt;
[[RIOT limitations and workarounds]] contains info on using the RIOT RAM and Timers in 7800 mode.&lt;br /&gt;
&lt;br /&gt;
==General 6502 Assembly Documents==&lt;br /&gt;
&lt;br /&gt;
The [[6502 opcodes for hackers]] reference lists 6502 opcodes, valid modes, cycles, useful illegal opcodes, etc.&lt;br /&gt;
&lt;br /&gt;
[[6502 Beginner Tips]] contains useful information and references if you're new to 6502 assembly.&lt;br /&gt;
&lt;br /&gt;
[[6502 Advanced Tips]] contains information for seasoned 6502 coders.&lt;br /&gt;
&lt;br /&gt;
External links:&lt;br /&gt;
&lt;br /&gt;
[http://www.6502.org/tutorials/6502opcodes.html Opcodes] in more detail&lt;br /&gt;
&lt;br /&gt;
[http://www.6502.org/tutorials/compare_instructions.html Compare Instructions] in even-more detail&lt;br /&gt;
&lt;br /&gt;
[http://www.6502.org/tutorials/compare_beyond.html Advanced Comparisons] by Bruce Clark, including alternatives to CMP/CPX/CPY, signed comparisons, and multibyte comparisons&lt;br /&gt;
&lt;br /&gt;
[http://nesdev.com/6502guid.txt Another overview], this one from NESdev, containing detail on addressing modes and status flags&lt;br /&gt;
&lt;br /&gt;
[https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations Assembly Optimizations] from NESdev&lt;br /&gt;
&lt;br /&gt;
[http://web.archive.org/web/20130316101738/http://mycorner.no-ip.org/6502/shorts/index.html 6502 Shorts] by Lee Davison&lt;br /&gt;
&lt;br /&gt;
[http://web.archive.org/web/20130316101732/http://mycorner.no-ip.org/6502/code/index.html 6502 Routines] also by Lee Davison&lt;br /&gt;
&lt;br /&gt;
[http://wilsonminesco.com/6502primer/PgmTips.html Tips for Programming] by Garth Wilson&lt;br /&gt;
&lt;br /&gt;
[http://www.6502.org/tutorials/interrupts.html Investigating Interrupts], all you need to know and more about interrupts, by Garth Wilson&lt;br /&gt;
&lt;br /&gt;
[http://wilsonminesco.com/SelfModCode/ Self-Modifying Code] by Garth Wilson&lt;br /&gt;
&lt;br /&gt;
[https://www.esocop.org/docs/MOS6510UnintendedOpcodes-20152412.pdf NMOS 6510 Unintended Opcodes] is an excellent overview of the undocumented/illegal opcodes on the 6502/6510.&lt;br /&gt;
&lt;br /&gt;
==External Hardware Documents==&lt;br /&gt;
&lt;br /&gt;
===General===&lt;br /&gt;
The [[Atari 7800 Hardware Interfacing Guide For Programmers]] page is a good primer for programmers aspiring to working with hardware.&lt;br /&gt;
&lt;br /&gt;
===POKEY===&lt;br /&gt;
Atari's internal [[POKEY C012294 Documentation]] covers POKEY in formal manner.&lt;br /&gt;
&lt;br /&gt;
[[Detecting POKEY]] provides one method of detecting the presence of the POKEY chip.&lt;br /&gt;
&lt;br /&gt;
[[The POKEY Note Table]] is a handy guide to note frequencies by Bobby Clark, aka Synthpopalooza. Both 8-bit and 16-bit modes are covered.&lt;br /&gt;
&lt;br /&gt;
7800 games can use the [https://github.com/VinsCool/RASTER-Music-Tracker RMT - Raster Music Tracker], originally developed by Radek Štěrba, currently maintained by Vin Samuel, with a [https://forums.atariage.com/topic/22877-rmt-pokey-player-for-the-7800/ 7800 driver port courtesy of Eckhard Stolberg.] &lt;br /&gt;
&lt;br /&gt;
[https://asma.atari.org/ ASMA SAP Archive] contains SAP format wrapped Atari songs, some of which are SAP wrapped RMT files. You can download [[Media:ASMA_SAP_RMT_Files.zip|a collection of RMT based ASMA SAP files here]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===XM, The 7800 Expansion Module===&lt;br /&gt;
&lt;br /&gt;
The [https://web.archive.org/web/20200813143026/http://www.7800xm.com/XMdevelopers.htm XM Developers page] has the official XM developer information.&lt;br /&gt;
&lt;br /&gt;
The [[YM2151 Programming]] page has technical information on the YM2151 and the XM.&lt;br /&gt;
&lt;br /&gt;
The [[OPM Instrument Collection]] page is a good source of instruments for the YM2151.&lt;br /&gt;
&lt;br /&gt;
The [[YM2151 Detection]] page has code for detecting the YM2151 on the 7800. (XM or stand-alone)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===AtariVox===&lt;br /&gt;
[[AtariVox for the 7800]] covers details for accessing the AtariVox peripheral.&lt;br /&gt;
&lt;br /&gt;
The [https://7800.8bitdev.org/webapps/speakalator.html Speakalator Web App] can be used for authoring AtariVox phrases. It requires a chromium engine based browser to connect to your AtariVox via a TTL serial port.&lt;br /&gt;
&lt;br /&gt;
===High Score Cart===&lt;br /&gt;
The [[HSC Layout]] describes the NVRAM layout for the HSC Cart.&lt;br /&gt;
&lt;br /&gt;
===SNES2Atari===&lt;br /&gt;
[[SNES2Atari]] contains implementation information for connecting SNES controllers to the 7800, and othr Atari consoles.&lt;br /&gt;
&lt;br /&gt;
==Miscellaneous Documents==&lt;br /&gt;
&lt;br /&gt;
[[Bankset Bankswitching]] gives an overview of the homebrew bankswitching scheme.&lt;br /&gt;
&lt;br /&gt;
[[The Atari 7800 BEAD Executable Specification]] covers how 7800 B78 executables are formatted.&lt;br /&gt;
&lt;br /&gt;
[[Common Emulator Development Issues]] covers some of the games that may cause quirks in new emulators.&lt;br /&gt;
&lt;br /&gt;
Eckhard Stolberg's [[ATARI 7800 BANKSWITCHING GUIDE]] is the bank-switching bible for the 7800.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Creating Bluish Noise With Minimal Compute]] covers the uses of blue noise, and how to inexpensively generate it on older platforms.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1291</id>
		<title>Assembly Source Code</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1291"/>
				<updated>2025-08-21T16:08:09Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Assembly Source Code ==&lt;br /&gt;
The following source code files will compile on DASM, making them useful for both studying and modifying.&lt;br /&gt;
&lt;br /&gt;
=== [[7800_NTSC_BIOS]] ===&lt;br /&gt;
''The NTSC BIOS does a bit of sanity checking, verifies if the inserted cart is cryptographically signed for 7800 mode, and then either locks the console into 2600 mode or passes on control to the cart.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[7800 PAL BIOS]] ===&lt;br /&gt;
''The PAL BIOS lacks the cryptographic checks of the NTSC BIOS, due to US munition laws that made export of cryptographic technology illegal. Instead the PAL BIOS runs some heuristics to determine if the cart is 2600 or 7800, like looking for 2600 cart ROM mirrors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[JOUST 7800 NTSC Source Code]] ===&lt;br /&gt;
''A complete disassembly of the finest 8-bit port of Joust.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=JOUST_7800_NTSC_Source_Code&amp;diff=1290</id>
		<title>JOUST 7800 NTSC Source Code</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=JOUST_7800_NTSC_Source_Code&amp;diff=1290"/>
				<updated>2025-08-21T01:20:49Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;==Joust 7800 NTSC Source Code==  This reverse engineered 7800 Joust code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.   &amp;lt;pre&amp;gt;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Joust 7800 NTSC Source Code==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 Joust code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Disassembly of Joust NTSC for the Atari 7800 console&lt;br /&gt;
;&lt;br /&gt;
; 2025-08-20 - Mike Saarna&lt;br /&gt;
;   * Initial public release. &lt;br /&gt;
;     * Game logic and all routines identified and documented.&lt;br /&gt;
;&lt;br /&gt;
; &amp;quot;Our goal at GCC was to bring arcade-quality games home. With the 7800,&lt;br /&gt;
; we wanted it to feel as close as possible to what you remembered from&lt;br /&gt;
; the arcade.&amp;quot;&lt;br /&gt;
;                                                   --Steve Golson, GCC&lt;br /&gt;
;&lt;br /&gt;
; Joust 7800 is a faithful recreation of the arcade classic. The brilliant&lt;br /&gt;
; minds at GCC reverse engineered the original game to craft this stellar &lt;br /&gt;
; port. To produce this disassembly I had to reverse engineer a cloaked&lt;br /&gt;
; machine-generated listing, revealing GCC’s masterful work. Reverseception.&lt;br /&gt;
;&lt;br /&gt;
;                                                   --Mike Saarna&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; NOTABLE GAME DESIGN FEATURES:&lt;br /&gt;
;&lt;br /&gt;
; 1. Game Object System:&lt;br /&gt;
;    The game manages all on-screen entities (players, enemies, eggs, &lt;br /&gt;
;    pterodactyls) through a powerful &amp;quot;Game Object&amp;quot; system. Instead of unique&lt;br /&gt;
;    code for each entity, properties like position, velocity, and state are&lt;br /&gt;
;    stored in parallel arrays in RAM. A single index represents a specific &lt;br /&gt;
;    object. The game logic iterates through these objects, applying common &lt;br /&gt;
;    routines for physics, rendering, and AI. &lt;br /&gt;
;&lt;br /&gt;
; 2. Event Scheduler (ES):&lt;br /&gt;
;    The ESRoutineScheduler system manages timed and sequential game events &lt;br /&gt;
;    without introducing purpose-specific code in the main game loop. It uses &lt;br /&gt;
;    a list of timers and function pointers. When a timer expires, its &lt;br /&gt;
;    corresponding routine is executed. This allows for complex, multi-frame &lt;br /&gt;
;    sequences like the dissolving platforms, lava rising, and timed text &lt;br /&gt;
;    messages to occur gracefully in the background while the main game action&lt;br /&gt;
;    continues.&lt;br /&gt;
;&lt;br /&gt;
; 3. Sprites for the upcoming frame are added to render lists, in a format&lt;br /&gt;
;    for eventual quick dumping to the DLs. This is a sort of pseudo double-&lt;br /&gt;
;    buffer functionality.&lt;br /&gt;
;&lt;br /&gt;
; 4. 16-bit Sub-Pixel Physics:&lt;br /&gt;
;    To achieve smooth, arcade-accurate movement, the game uses 16-bit values&lt;br /&gt;
;    for object coordinates and velocities. This allows for fine-grained &lt;br /&gt;
;    control over acceleration and movement.&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; TIA/MARIA/RIOT Hardware Registers &lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
INPTCTRL = $01&lt;br /&gt;
INPT4    = $0C&lt;br /&gt;
INPT5    = $0D&lt;br /&gt;
AUDC0    = $15&lt;br /&gt;
AUDF0    = $17&lt;br /&gt;
AUDV0    = $19&lt;br /&gt;
AUDV1    = $1A&lt;br /&gt;
BACKGRND = $20&lt;br /&gt;
P0C1     = $21&lt;br /&gt;
P0C2     = $22&lt;br /&gt;
P0C3     = $23&lt;br /&gt;
WSYNC    = $24&lt;br /&gt;
P1C1     = $25&lt;br /&gt;
P1C2     = $26&lt;br /&gt;
P1C3     = $27&lt;br /&gt;
MSTAT    = $28&lt;br /&gt;
P2C1     = $29&lt;br /&gt;
P2C2     = $2A&lt;br /&gt;
P2C3     = $2B&lt;br /&gt;
DPPH     = $2C&lt;br /&gt;
P3C1     = $2D&lt;br /&gt;
P3C2     = $2E&lt;br /&gt;
P3C3     = $2F&lt;br /&gt;
DPPL     = $30&lt;br /&gt;
P4C1     = $31&lt;br /&gt;
P4C2     = $32&lt;br /&gt;
P4C3     = $33&lt;br /&gt;
CHARBASE = $34&lt;br /&gt;
P5C1     = $35&lt;br /&gt;
P5C2     = $36&lt;br /&gt;
P5C3     = $37&lt;br /&gt;
OFFSET   = $38&lt;br /&gt;
P6C1     = $39&lt;br /&gt;
P6C2     = $3A&lt;br /&gt;
P6C3     = $3B&lt;br /&gt;
CTRL     = $3C&lt;br /&gt;
P7C1     = $3D&lt;br /&gt;
P7C2     = $3E&lt;br /&gt;
P7C3     = $3F&lt;br /&gt;
SWCHA    = $0280&lt;br /&gt;
SWACNT   = $0281&lt;br /&gt;
SWCHB    = $0282&lt;br /&gt;
SWBCNT   = $0283&lt;br /&gt;
&lt;br /&gt;
; ****************** VARIABLES&lt;br /&gt;
&lt;br /&gt;
P0Score          = $40  ; to $42&lt;br /&gt;
P0ExtraLifeScore = $43  ; to $44  Score threshold for bonus life award&lt;br /&gt;
P1Score          = $45  ; to $47&lt;br /&gt;
P1ExtraLifeScore = $48  ; to $49  Score threshold for bonus life award&lt;br /&gt;
&lt;br /&gt;
PlayerCount = $4A&lt;br /&gt;
DemoMode    = $4B&lt;br /&gt;
&lt;br /&gt;
Difficulty           = $4C&lt;br /&gt;
TimerHi              = $4D&lt;br /&gt;
TimerLo              = $4E&lt;br /&gt;
IncrementingRandSeed = $4F&lt;br /&gt;
&lt;br /&gt;
P0LastFire    = $50&lt;br /&gt;
P1LastFire    = $51&lt;br /&gt;
P0CurrentFire = $52&lt;br /&gt;
P1CurrentFire = $53&lt;br /&gt;
&lt;br /&gt;
MenuJoyDebounceTimer    = $54&lt;br /&gt;
MenuSelectDebounceTimer = $55&lt;br /&gt;
MenuResetTimer          = $56&lt;br /&gt;
PrevPausedState         = $57&lt;br /&gt;
PrevResetState          = $58&lt;br /&gt;
PrevSelectState         = $59&lt;br /&gt;
&lt;br /&gt;
TempPoint5ACurrentESRoutineLo  = $5A&lt;br /&gt;
TempPointLo5A                  = $5A&lt;br /&gt;
TempPoint5ACurrentESRoutineHi  = $5B&lt;br /&gt;
TempPointHi5B                  = $5B&lt;br /&gt;
&lt;br /&gt;
TempPoint5CLo = $5C&lt;br /&gt;
TempPoint5DHi = $5D&lt;br /&gt;
&lt;br /&gt;
; Note that I've defined aliases for temps that are reused for&lt;br /&gt;
; various routines, to help maintain clarity in local routines.&lt;br /&gt;
&lt;br /&gt;
Temp5E                        = $5E&lt;br /&gt;
Temp5EGfxDataLo               = $5E&lt;br /&gt;
TempPterryCoordY              = $5E&lt;br /&gt;
TempSavedYForHunterBirdSpawn  = $5E&lt;br /&gt;
Temp5F                        = $5F&lt;br /&gt;
Temp5FGfxDataHi               = $5F&lt;br /&gt;
TempPterryCoordX              = $5F&lt;br /&gt;
Temp60                        = $60&lt;br /&gt;
Temp60ScoreAdd                = $60&lt;br /&gt;
Temp60PaletteAndWidth         = $60&lt;br /&gt;
TempPterryScoreValue          = $60&lt;br /&gt;
Temp60MinPhysicsXSpeedIndex   = $60&lt;br /&gt;
&lt;br /&gt;
Temp61                      = $61&lt;br /&gt;
Temp61ScoreAdd              = $61&lt;br /&gt;
Temp61SpriteXCoord          = $61&lt;br /&gt;
Temp61MaxPhysicsXSpeedIndex = $61&lt;br /&gt;
&lt;br /&gt;
Temp62                   = $62&lt;br /&gt;
Temp62ScoreAdd           = $62&lt;br /&gt;
Temp62MaxFallSpeed       = $62&lt;br /&gt;
Temp63                   = $63&lt;br /&gt;
Temp63SpriteYCoord       = $63&lt;br /&gt;
Temp63MaxRiseSpeedNeg    = $63&lt;br /&gt;
Temp64                   = $64&lt;br /&gt;
Temp64SpriteYOffset      = $64&lt;br /&gt;
Temp64WeightFactor       = $64&lt;br /&gt;
Temp65                   = $65&lt;br /&gt;
Temp66                   = $66&lt;br /&gt;
&lt;br /&gt;
TempCollisionOverlap = $67  ; the magnitude of overlap from collision checks&lt;br /&gt;
&lt;br /&gt;
Temp68 = $68&lt;br /&gt;
Temp69 = $69&lt;br /&gt;
&lt;br /&gt;
Temp6ASFXIndex = $6A&lt;br /&gt;
&lt;br /&gt;
SFXChannel0Index = $6B  ; Current sound effect playing on audio channel 0&lt;br /&gt;
SFXChannel1Index = $6C  ; Current sound effect playing on audio channel 1&lt;br /&gt;
&lt;br /&gt;
BridgeBurningWidth      = $6D&lt;br /&gt;
ESTemp6E                = $6E&lt;br /&gt;
ESTemp6ELavaRiseCounter = $6E&lt;br /&gt;
&lt;br /&gt;
; ??? = $6F  appears unused&lt;br /&gt;
&lt;br /&gt;
LeftFlameAnimationIndex  = $70&lt;br /&gt;
RightFlameAnimationIndex = $71&lt;br /&gt;
&lt;br /&gt;
TitleColorIndex           = $70&lt;br /&gt;
TitleColorChangeCountdown = $71&lt;br /&gt;
&lt;br /&gt;
EggsPresentCount = $72&lt;br /&gt;
ColorCycleIndex  = $72  ; reused for title screen&lt;br /&gt;
EnemyBirdCount   = $73&lt;br /&gt;
ColorChangeTimer = $73  ; reused for title screen&lt;br /&gt;
&lt;br /&gt;
TrollState = $74  ; 0=hiding in lave, $FF=jumping out, $02=holding a bird&lt;br /&gt;
&lt;br /&gt;
TrollXCoord      = $75&lt;br /&gt;
TrollYCoord      = $76&lt;br /&gt;
TrollTargetIndex = $77&lt;br /&gt;
TrollGfxOffset   = $78&lt;br /&gt;
&lt;br /&gt;
PterryCountdownLo     = $79&lt;br /&gt;
EasterEggJoyDownCount = $79&lt;br /&gt;
PterryCountdownHi     = $7A&lt;br /&gt;
EasterEggJoyLeftCount = $7A&lt;br /&gt;
PterryAliveCount      = $7B&lt;br /&gt;
&lt;br /&gt;
EnemyAITargetDelayBase   = $7C&lt;br /&gt;
TrollPullingVelocity     = $7D&lt;br /&gt;
TrollMinimumGrabYCoord   = $7E&lt;br /&gt;
TrollMinimumTargetYCoord = $7F&lt;br /&gt;
&lt;br /&gt;
BirdPhysicsIndexMinByType = $80  ; to $84&lt;br /&gt;
BirdPhysicsIndexMaxByType = $85  ; to $89&lt;br /&gt;
&lt;br /&gt;
; Eggs collected so far, to a max of 3. Used as an index to determine value&lt;br /&gt;
; of egg pickup. This gets reset on death or new wave.&lt;br /&gt;
P0EggPointLevel = $8A&lt;br /&gt;
P1EggPointLevel = $8B&lt;br /&gt;
&lt;br /&gt;
P0Lives = $8C&lt;br /&gt;
P1Lives = $8D&lt;br /&gt;
&lt;br /&gt;
GamePacingTimer = $8E  ; ensures game logic runs every other frame&lt;br /&gt;
DemoTimer       = $8F&lt;br /&gt;
&lt;br /&gt;
GameEndDelayTimer      = $90&lt;br /&gt;
EnemyIsSpawning        = $91&lt;br /&gt;
PlatformPresentBitmask = $92&lt;br /&gt;
&lt;br /&gt;
Level    = $93&lt;br /&gt;
LevelBCD = $94&lt;br /&gt;
&lt;br /&gt;
GameActiveFlag = $95  ; 0=normal, 1=game is ending&lt;br /&gt;
&lt;br /&gt;
; Game logic writes sprite data to a render list, and then the render list is &lt;br /&gt;
; used to update the DL in one shot.&lt;br /&gt;
RenderListCount = $96  ; The number of sprites in the render list&lt;br /&gt;
RenderListDirty = $97  ; A flag to indicate if the render list was&lt;br /&gt;
                       ; updated since the last DL update.&lt;br /&gt;
&lt;br /&gt;
LevelWasSurvived   = $98  ; keep track to award survival points&lt;br /&gt;
PlayersWereATeam   = $99  ; keep track to award team points&lt;br /&gt;
PlayerWasGladiator = $9A  ; keep track to award gladiator points&lt;br /&gt;
PterryWave         = $9B&lt;br /&gt;
&lt;br /&gt;
IsEggWave        = $9C&lt;br /&gt;
PlatformsInLevel = $9D&lt;br /&gt;
&lt;br /&gt;
; The PlatformPresentBitmask from the previous wave...&lt;br /&gt;
OldPlatformPresentBitmask = $9E&lt;br /&gt;
&lt;br /&gt;
MaxActiveEnemyIndex = $9F&lt;br /&gt;
&lt;br /&gt;
SpawnPlatformDissolved0 = $A0&lt;br /&gt;
SpawnPlatformDissolved1 = $A1&lt;br /&gt;
SpawnPlatformDissolved2 = $A2&lt;br /&gt;
SpawnPlatformDissolved3 = $A3&lt;br /&gt;
&lt;br /&gt;
MaxEnemyBirdCount = $A4&lt;br /&gt;
&lt;br /&gt;
EggWaveEnemyType = $A5&lt;br /&gt;
&lt;br /&gt;
P0DeathState = $A6&lt;br /&gt;
P1DeathState = $A7&lt;br /&gt;
&lt;br /&gt;
; When a player bird dies, there's an explostion/particle cloud. &lt;br /&gt;
; These are the Coordinates for the cloud.&lt;br /&gt;
PlayerExplosionXCoord = $A8  ; to $A9&lt;br /&gt;
PlayerExplosionYCoord = $AA  ; to $AB&lt;br /&gt;
&lt;br /&gt;
; A collection of event scheduler (ES) routine indexes.&lt;br /&gt;
ESRoutineIndex = $AC  ; to $BD&lt;br /&gt;
&lt;br /&gt;
; A collection of event scheduler (ES) routine timers.&lt;br /&gt;
ESRoutineTimer = $BE  ; to $CF 18 timers total&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GameObjectState = $D0&lt;br /&gt;
  ; $D0 | P0 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird&lt;br /&gt;
  ; $D1 | P1 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird&lt;br /&gt;
  ; $D2 - $D9 | EnemyBird(8) 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird $14=bird seeking rider&lt;br /&gt;
  ; $DA - $DC | Pterry(3) 0=dead A=normal B=charging C=leaving&lt;br /&gt;
  ; $DD - $E8 | Egg(12) 0=none 1=egg 2=hatching 3=rider+shell 4=rider&lt;br /&gt;
PterryState1 = $DA&lt;br /&gt;
PterryState2 = $DB&lt;br /&gt;
PterryState3 = $DC&lt;br /&gt;
EggState     = $DD&lt;br /&gt;
&lt;br /&gt;
GameObjectAIMode = $E9&lt;br /&gt;
  ; $E9 : P0&lt;br /&gt;
  ; $EA : P1&lt;br /&gt;
  ; $EB - $F2 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
GameObjectAlive = $F3&lt;br /&gt;
  ; $F3 : P0&lt;br /&gt;
  ; $F4 : P1&lt;br /&gt;
  ; $F5 - $FC : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
NMIModeFlag = $FD&lt;br /&gt;
  ; $00: Normal game NMI (in-game, title screen animation) - sound, input, render list processing.&lt;br /&gt;
  ; $01: 320A portion of split screen NMI mode. Automatically changes NMIModeFlag to $FF. &lt;br /&gt;
  ; $FF: 160A portion of split screen NMI mode. Automatically changes NMIModeFlag to $01.&lt;br /&gt;
&lt;br /&gt;
  ; When a player bird enters a platform a bit low, it initiates a bounce/skip&lt;br /&gt;
  ; across the platform instead of walking. 0=not skipping, 1=skipping&lt;br /&gt;
GameObjectPlatformSkipState = $14A&lt;br /&gt;
  ; $14A : P0&lt;br /&gt;
  ; $14B : P1&lt;br /&gt;
  ; $14C - $153 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
GameObjectXCoordHi = $154&lt;br /&gt;
  ; $154 : P0&lt;br /&gt;
  ; $155 : P1&lt;br /&gt;
  ; $156 - $15D : EnemyBird(8)&lt;br /&gt;
  ; $15E - $160 : Pterry(3)&lt;br /&gt;
  ; $161 - $16C : Egg(12)&lt;br /&gt;
EggX = $161&lt;br /&gt;
&lt;br /&gt;
GameObjectYCoordHi = $16D&lt;br /&gt;
  ; $16D : P0&lt;br /&gt;
  ; $16E : P1&lt;br /&gt;
  ; $16F - $176 : EnemyBird(8)&lt;br /&gt;
  ; $177 - $179 : Pterry(3)&lt;br /&gt;
  ; $17A - $185 : Egg(12)&lt;br /&gt;
EggY = $17A&lt;br /&gt;
&lt;br /&gt;
  ; The palette+width used to eventually render the bird.&lt;br /&gt;
BirdObjectPaletteAndWidth = $186&lt;br /&gt;
  ; $186 : P0&lt;br /&gt;
  ; $187 : P1&lt;br /&gt;
  ; $188 - $18F : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
PaletteInRam = $0190           ; to $01A7&lt;br /&gt;
P0C1_Ram     = $0190&lt;br /&gt;
P0C2_Ram     = $0191&lt;br /&gt;
P0C3_Ram     = $0192&lt;br /&gt;
P1C1_Ram     = $0193&lt;br /&gt;
P1C2_Ram     = $0194&lt;br /&gt;
P1C3_Ram     = $0195&lt;br /&gt;
P2C1_Ram     = $0196&lt;br /&gt;
P2C2_Ram     = $0197&lt;br /&gt;
P2C3_Ram     = $0198&lt;br /&gt;
P3C1_Ram     = $0199&lt;br /&gt;
P3C2_Ram     = $019A&lt;br /&gt;
P3C3_Ram     = $019B&lt;br /&gt;
P4C1_Ram     = $019C&lt;br /&gt;
P4C2_Ram     = $019D&lt;br /&gt;
P4C3_Ram     = $019E&lt;br /&gt;
P5C1_Ram     = $019F&lt;br /&gt;
P5C2_Ram     = $01A0&lt;br /&gt;
P5C3_Ram     = $01A1&lt;br /&gt;
P6C1_Ram     = $01A2&lt;br /&gt;
P6C2_Ram     = $01A3&lt;br /&gt;
P6C3_Ram     = $01A4&lt;br /&gt;
P7C1_Ram     = $01A5&lt;br /&gt;
P7C2_Ram     = $01A6&lt;br /&gt;
P7C3_Ram     = $01A7&lt;br /&gt;
&lt;br /&gt;
Platform56GfxLo        = $1A13&lt;br /&gt;
Platform56PaletteWidth = $1A14&lt;br /&gt;
Platform4GfxLo         = $1A6D&lt;br /&gt;
Platform4PaletteWidth  = $1A6E&lt;br /&gt;
Platform0GfxLo         = $1D43&lt;br /&gt;
Platform0PaletteWidth  = $1D44&lt;br /&gt;
&lt;br /&gt;
Platform4XCoordinate   = $1A70  ; DL object's X coordinate&lt;br /&gt;
SpawnPoint4XCoordinate = $1A74  ; DL object's X coordinate&lt;br /&gt;
&lt;br /&gt;
Platform5XCoordinate = $1A16   ; DL object's X coordinate&lt;br /&gt;
Platform6XCoordinate = $1A1A   ; DL object's X coordinate&lt;br /&gt;
&lt;br /&gt;
Platform0XCoordinate = $1D46   ; DL object's X coordinate&lt;br /&gt;
&lt;br /&gt;
EasterEggXCoordinate1 = $1D96&lt;br /&gt;
EasterEggXCoordinate2 = $1DF0&lt;br /&gt;
EasterEggXCoordinate3 = $1E4B&lt;br /&gt;
&lt;br /&gt;
; DL X-coordinate bytes for menu texts.&lt;br /&gt;
MenuTwoPlayerTextXCoord  = $1EA5&lt;br /&gt;
MenuDifficultyTextXCoord = $1EFF&lt;br /&gt;
MenuOnePlayerTextXCoord  = $1F59&lt;br /&gt;
&lt;br /&gt;
BridgeRightGfxByte1  = $1F4F&lt;br /&gt;
BridgeLeftGfxByte1   = $1F53&lt;br /&gt;
BridgeRightGfxByte2  = $1F57&lt;br /&gt;
BridgeLeftGfxByte2   = $1F5B&lt;br /&gt;
BridgeRightGfxByte3  = $1FA5&lt;br /&gt;
BridgeLeftGfxByte3   = $1FA9&lt;br /&gt;
&lt;br /&gt;
; I think these are probably just graphics data hi bytes of lava sprites &lt;br /&gt;
; in a larger DL for the bottom level, and the lava level for each gets &lt;br /&gt;
; raised by changing them to scroll them out a DMA hole.&lt;br /&gt;
&lt;br /&gt;
LeftLavaLevelWave3  = $1FB0&lt;br /&gt;
RightLavaLevelWave3 = $1FAC&lt;br /&gt;
&lt;br /&gt;
LeftLavaLevelWave2  = $1FC3&lt;br /&gt;
RightLavaLevelWave2 = $1FC7&lt;br /&gt;
&lt;br /&gt;
LeftLavaLevelWave1  = $1FD9&lt;br /&gt;
RightLavaLevelWave1 = $1FDD&lt;br /&gt;
&lt;br /&gt;
  ; Used to derive bird walk cycle frame&lt;br /&gt;
GameObjectFootstepAnimIndex = $1FF2&lt;br /&gt;
  ; $1FF2 : P0&lt;br /&gt;
  ; $1FF3 : P1&lt;br /&gt;
  ; $1FF4 - $1FFB : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
GameObjectFootstepAnimTimer = $1FFC&lt;br /&gt;
  ; $1FFC : P0&lt;br /&gt;
  ; $1FFD : P1&lt;br /&gt;
  ; $1FFE - $2005 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
UnusedBirdObjectArray1 = $2006&lt;br /&gt;
  ; A bird object sized array that gets cleared with others,&lt;br /&gt;
  ; but it's never actually used after that.&lt;br /&gt;
  ; $2006 : P0&lt;br /&gt;
  ; $2007 : P1&lt;br /&gt;
  ; $2008 - $200F : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
  ; A bird timer delaying AI target re-evaluation&lt;br /&gt;
GameObjectAITargetDelayTimer = $2010&lt;br /&gt;
  ; $2010 : P0&lt;br /&gt;
  ; $2011 : P1&lt;br /&gt;
  ; $2012 - $2019 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
GameObjectSpawnPlatformIndex = $201A&lt;br /&gt;
  ; $201A : P0&lt;br /&gt;
  ; $201B : P1&lt;br /&gt;
  ; $201C - $2023 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
BirdInvulnerable = $2024  ; to 2025&lt;br /&gt;
  ; When the bird spawns on a platform, this flag cycles:&lt;br /&gt;
  ; $FF, $02, $02, $01, $01, $00, $00&lt;br /&gt;
  ; $2024 : P0&lt;br /&gt;
  ; $2025 : P1&lt;br /&gt;
  ; $2026 - $202D : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
  ; When the player tries to reverse direction when running on a platform,&lt;br /&gt;
  ; it initiates a skid until the bird comes to a stop. This location holds&lt;br /&gt;
  ; the skid direction/flag, or zero when not-skidding.&lt;br /&gt;
GameObjectSkidDirection = $202E&lt;br /&gt;
  ; $202E : P0&lt;br /&gt;
  ; $202F : P1&lt;br /&gt;
  ; $2030 - $2037 : EnemyBird(8)&lt;br /&gt;
P0SkidDirection = $202E&lt;br /&gt;
P1SkidDirection = $202F&lt;br /&gt;
&lt;br /&gt;
MessageLine0Enable = $2038&lt;br /&gt;
&lt;br /&gt;
; $2040 to $20FF: 7800 console ram block 0 shadow&lt;br /&gt;
&lt;br /&gt;
MessageLine0Timer = $2108&lt;br /&gt;
MessageLine1Timer = $2109&lt;br /&gt;
MessageLine2Timer = $210A&lt;br /&gt;
MessageLine3Timer = $210B&lt;br /&gt;
&lt;br /&gt;
; These unused player state bytes are cleared but never used.&lt;br /&gt;
UnusedPlayerStateArray = $210C ; to $210D&lt;br /&gt;
&lt;br /&gt;
TempSpawnUnsafeCounter = $2110 ; to $2113&lt;br /&gt;
&lt;br /&gt;
P0JoyDelay = $2114&lt;br /&gt;
P1JoyDelay = $2115&lt;br /&gt;
&lt;br /&gt;
P0FireDebounce = $2116&lt;br /&gt;
P1FireDebounce = $2117&lt;br /&gt;
&lt;br /&gt;
; $2140 to $21FF: 7800 console ram block 1 shadow&lt;br /&gt;
&lt;br /&gt;
; Character strings for the animated titlescreen border&lt;br /&gt;
TitleBorderStr0 = $2200&lt;br /&gt;
TitleBorderStr1 = $2201&lt;br /&gt;
TitleBorderStr2 = $2202&lt;br /&gt;
TitleBorderStr3 = $2203&lt;br /&gt;
TitleBorderStr4 = $2204       ; to $2223&lt;br /&gt;
TitleBorderStr5 = $2205       ; to $2223&lt;br /&gt;
&lt;br /&gt;
ObjectWiggleAnimation = $220E  ; only used for egg wiggle animation&lt;br /&gt;
                               ; $220E : P0&lt;br /&gt;
                               ; $220F : P1&lt;br /&gt;
                               ; $2210 - $2217 : EnemyBird(8)&lt;br /&gt;
                               ; $2218 - $221A : Pterry(3)&lt;br /&gt;
                               ; $221B - $2226 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectXCoordLo = $2227  ; sub-pixel X&lt;br /&gt;
                            ; $2227 : P0&lt;br /&gt;
                            ; $2228 : P1&lt;br /&gt;
                            ; $2229 - $2230 : EnemyBird(8)&lt;br /&gt;
                            ; $2231 - $2233 : Pterry(3)&lt;br /&gt;
                            ; $2234 - $223F : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectYCoordLo = $2240  ; sub-pixel Y&lt;br /&gt;
                            ; $2240 : P0&lt;br /&gt;
                            ; $2241 : P1&lt;br /&gt;
                            ; $2242 - $2249 : EnemyBird(8)&lt;br /&gt;
                            ; $224A - $224C : Pterry(3)&lt;br /&gt;
                            ; $224D - $2258 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
TitleCopyrightCharBuffer  = $2244 ; to $225F&lt;br /&gt;
TitleScreenLogoCharBuffer = $2260 ; to $2347&lt;br /&gt;
&lt;br /&gt;
ObjectBirdLevelAndType = $2259&lt;br /&gt;
  ; 0:red-bounder, 1:gray-hunter, 2:blue-shadowlord, 3:??, 4:pterry&lt;br /&gt;
  ; $2259 : P0&lt;br /&gt;
  ; $225A : P1&lt;br /&gt;
  ; $225B - $2262 : EnemyBird(8)&lt;br /&gt;
  ; $2263 - $2265 : Pterry(3)&lt;br /&gt;
  ; $2266 - $2271 : Egg(12)&lt;br /&gt;
EggLevelAndType = $2266&lt;br /&gt;
&lt;br /&gt;
GameObjectInAir = $2272  ; ... i.e. not standing on a platform.&lt;br /&gt;
  ; $2272 : P0&lt;br /&gt;
  ; $2273 : P1&lt;br /&gt;
  ; $2274 - $227B : EnemyBird(8)&lt;br /&gt;
  ; $227C - $227E : Pterry(3)&lt;br /&gt;
  ; $227F - $228A : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectYVelocityLo = $228B&lt;br /&gt;
  ; $228B : P0&lt;br /&gt;
  ; $228C : P1&lt;br /&gt;
  ; $228D - $2294 : EnemyBird(8)&lt;br /&gt;
  ; $2295 - $2297 : Pterry(3)&lt;br /&gt;
  ; $2298 - $22A3 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectYVelocityHi = $22A4&lt;br /&gt;
  ; $22A4 : P0&lt;br /&gt;
  ; $22A5 : P1&lt;br /&gt;
  ; $22A6 - $22AD : EnemyBird(8)&lt;br /&gt;
  ; $22AE - $22B0 : Pterry(3)&lt;br /&gt;
  ; $22B1 - $22BC : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectXVelocity = $22BD&lt;br /&gt;
  ; $22BD : P0&lt;br /&gt;
  ; $22BE : P1&lt;br /&gt;
  ; $22BF - $22C6 : EnemyBird(8)&lt;br /&gt;
  ; $22C7 - $22C9 : Pterry(3)&lt;br /&gt;
  ; $22CA - $22D5 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectHunterIndex = $22D6&lt;br /&gt;
  ; When one game object tagets another, the index of the hunter is &lt;br /&gt;
  ; stored here. E.g. the index of a riderless bird targetting a reborn rider&lt;br /&gt;
  ; There's a corresponding GameObjectPreyIndex that would store the index&lt;br /&gt;
  ; of the reborn rider.&lt;br /&gt;
  ; $22D6 : P0 &lt;br /&gt;
  ; $22D7 : P1&lt;br /&gt;
  ; $22D8 - $22DF : EnemyBird(8)&lt;br /&gt;
  ; $22E0 - $22E2 : Pterry(3)&lt;br /&gt;
  ; $22E3 - $22EE : Egg(12)&lt;br /&gt;
&lt;br /&gt;
UnusedGameObjectArray2 = $22EF&lt;br /&gt;
  ; A game object sized array that gets cleared with others&lt;br /&gt;
  ; but it's never actually used after that.&lt;br /&gt;
  ; $22EF : P0&lt;br /&gt;
  ; $22F0 : P1&lt;br /&gt;
  ; $22F1 - $22F8 : EnemyBird(8)&lt;br /&gt;
  ; $22F9 - $22FB : Pterry(3)&lt;br /&gt;
  ; $22FC - $2307 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectCountdownHi = $2308&lt;br /&gt;
  ; $2308 : P0&lt;br /&gt;
  ; $2309 : P1&lt;br /&gt;
  ; $230A - $2311 : EnemyBird(8)&lt;br /&gt;
  ; $2312 - $2314 : Pterry(3)&lt;br /&gt;
  ; $2315 - $2320 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectCountdownLo = $2321&lt;br /&gt;
  ; $2321 : P0&lt;br /&gt;
  ; $2322 : P1&lt;br /&gt;
  ; $2323 - $232A : EnemyBird(8)&lt;br /&gt;
  ; $232B - $232D : Pterry(3)&lt;br /&gt;
  ; $232E - $2339 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectDirection = $233A&lt;br /&gt;
  ; $233A : P0&lt;br /&gt;
  ; $233B : P1&lt;br /&gt;
  ; $233C - $2343 : EnemyBird(8)&lt;br /&gt;
  ; $2344 - $2346 : Pterry(3)&lt;br /&gt;
  ; $2347 - $2352 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
GameObjectAnimationFrame = $2360&lt;br /&gt;
  ; $2360 : P0&lt;br /&gt;
  ; $2361 : P1&lt;br /&gt;
  ; $2362 - $2369 : EnemyBird(8)&lt;br /&gt;
  ; $236A - $236C : Pterry(3)&lt;br /&gt;
  ; $236D - $2378 : Egg(12)&lt;br /&gt;
&lt;br /&gt;
; ??? = $2379 ; unused?&lt;br /&gt;
&lt;br /&gt;
GameObjectPreyIndex = $237A&lt;br /&gt;
  ; $237A : P0&lt;br /&gt;
  ; $237B : P1&lt;br /&gt;
  ; $237C - $2383 : EnemyBird(8)&lt;br /&gt;
  ; $2384 - $2385 : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
GameObjectTimerResetValue = $2387&lt;br /&gt;
  ; $2387 : P0&lt;br /&gt;
  ; $2388 : P1&lt;br /&gt;
  ; $2389 - $2390 : EnemyBird(8)&lt;br /&gt;
  ; $2391 - $2393 : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
GameObjectEventTimer1 = $2394&lt;br /&gt;
  ; $2394 : P0&lt;br /&gt;
  ; $2395 : P1&lt;br /&gt;
  ; $2396 - $239D : EnemyBird(8)&lt;br /&gt;
  ; $239E - $23A0 : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
GameObjectAnimationCounter = $23A1  ; Seems to only be used by pterry.&lt;br /&gt;
  ; A animation countdown that's used to derive the flap frame used.&lt;br /&gt;
  ; $23A1 : P0&lt;br /&gt;
  ; $23A2 : P1&lt;br /&gt;
  ; $23A3 - $23AA : EnemyBird(8)&lt;br /&gt;
  ; $23AB - $23AD : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
GameObjectAnimationDelay = $23AE  ; Also only used by pterry.&lt;br /&gt;
  ; Used to add delay between the pterry flap frames.&lt;br /&gt;
  ; $23AE : P0&lt;br /&gt;
  ; $23AF : P1&lt;br /&gt;
  ; $23B0 - $23B7 : EnemyBird(8)&lt;br /&gt;
  ; $23B8 - $23BA : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
GameObjectChargingTimer = $23BB&lt;br /&gt;
  ; Used for timing of pterry charging at the player, &lt;br /&gt;
  ; and riderless birds sliding at riders.&lt;br /&gt;
  ; $23BB : P0&lt;br /&gt;
  ; $23BC : P1&lt;br /&gt;
  ; $23BD - $23C4 : EnemyBird(8)&lt;br /&gt;
  ; $23C5 - $23C7 : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
PterryDefeatedFlag = $23C8 ; to $23CA (Pterry objects only)&lt;br /&gt;
  ; $23C8 - $23C4 : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
; Note this is an alias for the same underlying memory as PterryDefeatedFlag.&lt;br /&gt;
EnemyBirdTypesForLevel = $23C8 ; to ????&lt;br /&gt;
&lt;br /&gt;
PterryAgressionFlag = $23D2 ; to $23D4&lt;br /&gt;
; forces faster respawn on higher levels&lt;br /&gt;
&lt;br /&gt;
; $23D5 - $23D9 don't seem to be used, other than getting cleared &lt;br /&gt;
; with other game objects at the game start/end.&lt;br /&gt;
&lt;br /&gt;
GameObjectTurnCheckTimerLo = $23DA  &lt;br /&gt;
; seems to get read when the dead bird flys off-screen&lt;br /&gt;
  ; $23DA : P0&lt;br /&gt;
  ; $23DB : P1&lt;br /&gt;
  ; $23DC - $23E3 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
GameObjectTurnCheckTimerHi = $23E4&lt;br /&gt;
  ; $23E4 : P0&lt;br /&gt;
  ; $23E5 : P1&lt;br /&gt;
  ; $23E6 - $23ED : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
  ; Index into tables that load turn timer values.&lt;br /&gt;
GameObjectTurnTimerIndex = $23EE&lt;br /&gt;
  ; $23EE : P0&lt;br /&gt;
  ; $23EF : P1&lt;br /&gt;
  ; $23F0 - $23F7 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
  ; A Hi timer controlling the frequency of AI decision-making for birds.&lt;br /&gt;
  ; For details see the comments below for it's Lo timer counterpart.&lt;br /&gt;
GameObjectAITimerHi = $23F8&lt;br /&gt;
  ; $23F8 : P0&lt;br /&gt;
  ; $23F9 : P1&lt;br /&gt;
  ; $23FA - $2401 : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
; A Lo timer controlling the frequency of AI decision-making for birds&lt;br /&gt;
; and pterodactyls. Birds use this lo timer and it's hi counterpart to,&lt;br /&gt;
; for example, randomly turn around. Pterrys use it, for example, to home&lt;br /&gt;
; in on prey.&lt;br /&gt;
GameObjectAITimerLo = $2402&lt;br /&gt;
  ; $2402 : P0&lt;br /&gt;
  ; $2403 : P1&lt;br /&gt;
  ; $2404 - $240B : EnemyBird(8)&lt;br /&gt;
  ; $240C - $240E : Pterry(3)&lt;br /&gt;
&lt;br /&gt;
; Flags for platform dissolving sprite animation&lt;br /&gt;
PlatformDissolveAnimationFlag0 = $240F&lt;br /&gt;
PlatformDissolveAnimationFlag1 = $2410&lt;br /&gt;
PlatformDissolveAnimationFlag2 = $2411&lt;br /&gt;
PlatformDissolveAnimationFlag3 = $2412&lt;br /&gt;
PlatformDissolveAnimationFlag4 = $2413&lt;br /&gt;
PlatformDissolveAnimationFlag5 = $2414&lt;br /&gt;
&lt;br /&gt;
PlatformDissolveAnimationXCoord0 = $2415&lt;br /&gt;
PlatformDissolveAnimationXCoord1 = $2416&lt;br /&gt;
PlatformDissolveAnimationXCoord2 = $2417&lt;br /&gt;
PlatformDissolveAnimationXCoord3 = $2418&lt;br /&gt;
PlatformDissolveAnimationXCoord4 = $2419&lt;br /&gt;
PlatformDissolveAnimationXCoord5 = $241A&lt;br /&gt;
&lt;br /&gt;
PlatformDissolveAnimationYCoord0 = $241B&lt;br /&gt;
PlatformDissolveAnimationYCoord1 = $241C&lt;br /&gt;
PlatformDissolveAnimationYCoord2 = $241D&lt;br /&gt;
PlatformDissolveAnimationYCoord3 = $241E&lt;br /&gt;
PlatformDissolveAnimationYCoord4 = $241F&lt;br /&gt;
PlatformDissolveAnimationYCoord5 = $2420&lt;br /&gt;
&lt;br /&gt;
RiderObjectPaletteAndWidth = $2421&lt;br /&gt;
  ; $2421 : P0&lt;br /&gt;
  ; $2422 : P1&lt;br /&gt;
  ; $2423 - $242A : EnemyBird(8)&lt;br /&gt;
&lt;br /&gt;
; RAM structures containing DL addresses&lt;br /&gt;
DisplayListLo = $242B  ; to $2442&lt;br /&gt;
DisplayListHi = $2443  ; to $245A&lt;br /&gt;
&lt;br /&gt;
; Game logic writes sprite data to a render list, and then the render list is &lt;br /&gt;
; used to update the DLs in one shot. &lt;br /&gt;
RenderListDLLo            = $245B  ; to $24AF&lt;br /&gt;
RenderListDLHi            = $24B0  ; to $2504&lt;br /&gt;
RenderListGfxDataLo       = $2505  ; to $2559&lt;br /&gt;
RenderListGfxDataHi       = $255A  ; to $25AE&lt;br /&gt;
RenderListPaletteAndWidth = $25AF  ; to $2603&lt;br /&gt;
RenderListXCoord          = $2604  ; to $2658&lt;br /&gt;
&lt;br /&gt;
HudDisplayStringBuffer    = $2659  ; to ???&lt;br /&gt;
&lt;br /&gt;
HudWaveNumberDigit1 = $267C&lt;br /&gt;
HudWaveNumberDigit2 = $267D&lt;br /&gt;
&lt;br /&gt;
MenuLine1CharBuffer = $2685 ; &amp;quot;TWO PLAYER&amp;quot; text&lt;br /&gt;
MenuLine2CharBuffer = $2699 ; &amp;quot;ONE PLAYER&amp;quot; text&lt;br /&gt;
&lt;br /&gt;
DifficultyLevelCharBuffer = $26AD&lt;br /&gt;
&lt;br /&gt;
SurvivalWaveFlag  = $26C1&lt;br /&gt;
TeamWaveFlag      = $26C2&lt;br /&gt;
GladiatorWaveFlag = $26C3&lt;br /&gt;
&lt;br /&gt;
ScorePopup_ActiveTimerBase = $26C4  ; Base for active timers for score popups (12 bytes)&lt;br /&gt;
ScorePopup_ZoneIndexBase   = $26DC  ; Base for zone index for score popups (12 bytes)&lt;br /&gt;
ScorePopup_CharDataLoBase  = $26E8  ; Base for character data (lo byte) for score popups (12 bytes)&lt;br /&gt;
ScorePopup_XCoordBase      = $26D0  ; Base for X coordinate for score popups (12 bytes)&lt;br /&gt;
&lt;br /&gt;
FinalDLL_PointerStorage_Hi = $275E&lt;br /&gt;
FinalDLL_PointerStorage_Lo = $275F&lt;br /&gt;
&lt;br /&gt;
CurrentPlayer = $27AE&lt;br /&gt;
&lt;br /&gt;
DisplayEasterEggFlag = $27CE&lt;br /&gt;
&lt;br /&gt;
; ****************** CONSTANTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Difficulty Level Constants&lt;br /&gt;
; Used with the 'Difficulty' variable ($4C) and for text display.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
Difficulty_Beginner     = $00&lt;br /&gt;
Difficulty_Intermediate = $01&lt;br /&gt;
Difficulty_Advanced     = $02&lt;br /&gt;
Difficulty_Expert       = $03&lt;br /&gt;
&lt;br /&gt;
PLAYER1_OBJECT_INDEX             = $01&lt;br /&gt;
PLAYER1_COLLISION_HEIGHT_SPECIAL = $0B  ; Specific height check value for Player 1&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; GameObjectState Constants&lt;br /&gt;
; Defines the various states a game object can be in.&lt;br /&gt;
;&lt;br /&gt;
; Player and Enemy Bird States ($D0 - $D9):&lt;br /&gt;
; Shared states for player-controlled birds and enemy AI birds.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
State_Dead         = $00  ; Object is inactive, dead, or not present.&lt;br /&gt;
State_Born1        = $03  ; First phase of spawning/birth animation.&lt;br /&gt;
State_Normal       = $04  ; Normal gameplay state (player controllable, AI active).&lt;br /&gt;
State_Hit          = $05  ; Object has been hit (e.g., by a lance, preparing to die/drop egg).&lt;br /&gt;
State_Invincible   = $06  ; Object is temporarily invincible (e.g., during spawn).&lt;br /&gt;
State_Born2        = $07  ; Second phase of spawning/birth animation.&lt;br /&gt;
State_TrollHasBird = $08  ; Object (bird) is currently held by the troll.&lt;br /&gt;
&lt;br /&gt;
                              ; EnemyBird Specific State ($D2 - $D9):&lt;br /&gt;
State_BirdSeekingRider = $14  ; Enemy bird is actively seeking a rider (that hatched from an egg).&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Pterodactyl (Pterry) States ($DA - $DC):&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
                                  ; State_Dead is $00, shared with above.&lt;br /&gt;
PterryState_Normal         = $0A  ; Pterry is flying normally.&lt;br /&gt;
PterryState_Charging       = $0B  ; Pterry is actively charging/attacking a player.&lt;br /&gt;
PterryState_Leaving        = $0C  ; Pterry is leaving the screen (e.g., after being hit or timer expiry).&lt;br /&gt;
PterryState_DefeatedVisual = $0D  ; Pterry being visually defeated on screen&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Egg States ($DD - $E8):&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
EggState_None          = $00  ; Egg slot is empty, no egg present.&lt;br /&gt;
EggState_Egg           = $01  ; A laid egg, waiting to hatch.&lt;br /&gt;
EggState_Hatching      = $02  ; Egg is actively wiggling/hatching.&lt;br /&gt;
EggState_RiderOnShell  = $03  ; Rider has hatched and is standing on the broken egg shell.&lt;br /&gt;
EggState_StandingRider = $04  ; Rider is standing alone, shell is gone (will attract a hunter bird).&lt;br /&gt;
                              ; Note: This value is the same as State_Normal for birds.&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Egg Physics Parameter Constants&lt;br /&gt;
; These define the specific physics characteristics for an airborne egg.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
EGG_WEIGHT_FACTOR               = $04  ; Gravity effect on egg (lower is lighter)&lt;br /&gt;
EGG_MAX_RISE_SPEED_NEG          = $FF  ; Max upward Y-velocity (effectively -1, very slow rise)&lt;br /&gt;
EGG_MAX_FALL_SPEED              = $01  ; Max downward Y-velocity (slow fall)&lt;br /&gt;
EGG_X_SPEED_LUT_MAX_CLAMP_INDEX = $02  ; Smallest numerical index for X-speed LUT (fastest left drift)&lt;br /&gt;
                                       ; Note: &amp;quot;Max&amp;quot; in Temp61MaxPhysicsXSpeedIndex refers to its role in clamping logic,&lt;br /&gt;
                                       ; not necessarily the numerically largest index value.&lt;br /&gt;
EGG_X_SPEED_LUT_MIN_CLAMP_INDEX = $08  ; Largest numerical index for X-speed LUT (fastest right drift)&lt;br /&gt;
                                       ; Note: &amp;quot;Min&amp;quot; in MinPhysicsXSpeedLUTIndex refers to its role in clamping logic.&lt;br /&gt;
                                       ; For eggs, this value is numerically larger than EGG_X_SPEED_LUT_MAX_CLAMP_INDEX,&lt;br /&gt;
                                       ; defining the allowed index range [$02..$08] for X-movement.&lt;br /&gt;
&lt;br /&gt;
PTERRY_SPAWN_Y_COORD_MASK = %00000011  ; Mask for selecting Y coordinate from PterrySpawnYCoordLUT&lt;br /&gt;
PTERRY_SPAWN_XDIRVEL_MASK = %00000001  ; Mask for selecting from X/Dir/XVel LUTs&lt;br /&gt;
PTERRY_MIN_SPAWN_DIST_X = $30          ; Minimum X distance from player for Pterry spawn&lt;br /&gt;
PTERRY_MIN_SPAWN_DIST_Y = $20          ; Minimum Y distance from player for Pterry spawn&lt;br /&gt;
&lt;br /&gt;
MinEnemyBirdObjectIndex = $02         ; Smallest index for an enemy bird object&lt;br /&gt;
MaxEnemyBirdSlots       = $0A         ; Number of enemy bird slots to check (index 02 to 09)&lt;br /&gt;
&lt;br /&gt;
InitialTimerHiByteValue   = $00       ; Initial value for the high byte of the timer.&lt;br /&gt;
DifficultyLoopCounterBase = $03       ; Base value for calculating difficulty-dependent loop iterations.&lt;br /&gt;
                                      ; Max Difficulty is 3. Loop runs (Base - Difficulty + 1) times.&lt;br /&gt;
TimerLevelCalcBaseValue = $27         ; Baseline value for calculating level-dependent part of timer.&lt;br /&gt;
RandomTimerLoopAddend   = $40         ; Value added to timer in each difficulty-scaled loop iteration.&lt;br /&gt;
&lt;br /&gt;
; AI Action Categories (values from BirdAIActionCategoryByProximityLUT lookup)&lt;br /&gt;
AIActionCat_CloseDefensive = $00&lt;br /&gt;
AIActionCat_OptimalAttack  = $01&lt;br /&gt;
AIActionCat_ModerateEngage = $02&lt;br /&gt;
AIActionCat_FarApproach    = $03&lt;br /&gt;
&lt;br /&gt;
                                 ; Constants for Score Popup Display List Object&lt;br /&gt;
ScorePopup_DLModeByte EQU $60    ; Indirect Character Mode for DL&lt;br /&gt;
ScorePopup_DLCharHiByte EQU $27  ; High byte of character data address for HSC font&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Sound Effect (SFX) Index Constants&lt;br /&gt;
; Used as arguments to ScheduleSFX and for identifying sounds.&lt;br /&gt;
; The actual sound data is pointed to by SFX_FreqAndControlDataPtrLoLUT/Hi tables.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SFX_CoinDrop              = $00  ; Sound for coin drop (attract mode?)&lt;br /&gt;
SFX_FreeBird              = $01  ; Sound when a player earns an extra life.&lt;br /&gt;
SFX_PickupEgg             = $02  ; Sound when a player picks up an egg.&lt;br /&gt;
SFX_GameStart             = $03  ; Sound played at the beginning of a new game.&lt;br /&gt;
SFX_BirdPlatformBounce    = $04  ; Sound when a bird bounces off a platform edge.&lt;br /&gt;
SFX_BirdBirdBounce        = $05  ; Sound when two birds collide and bounce off each other.&lt;br /&gt;
SFX_PlayerFootstep        = $06  ; Sound of a player's bird walking on a platform.&lt;br /&gt;
SFX_PterryDefeated        = $07  ; Sound when a Pterodactyl is defeated.&lt;br /&gt;
SFX_PterryCharging        = $08  ; Sound when a Pterodactyl starts its charging attack.&lt;br /&gt;
SFX_PlayerBorn            = $09  ; Sound when a player's bird spawns/re-spawns.&lt;br /&gt;
SFX_Invulnerable          = $0A  ; Sound indicating player invulnerability (e.g., during spawn).&lt;br /&gt;
SFX_EggWigglingHatching   = $0B  ; Sound of an egg wiggling before hatching.&lt;br /&gt;
SFX_EnemyBirdBorn         = $0C  ; Sound when an enemy bird spawns.&lt;br /&gt;
SFX_TrollJumping          = $0D  ; Sound of the troll jumping out of the lava.&lt;br /&gt;
SFX_PlatformDissolve      = $0E  ; Sound when a platform starts to dissolve.&lt;br /&gt;
SFX_Skid                  = $0F  ; Sound of a bird skidding to a stop on a platform.&lt;br /&gt;
SFX_BirdExplosion         = $10  ; Sound when a bird (player or enemy) dies in an explosion.&lt;br /&gt;
SFX_CheepCheep            = $11  ; A &amp;quot;cheep cheep&amp;quot; sound, possibly unused or for a minor event.&lt;br /&gt;
SFX_PlayerBirdFlap        = $12  ; Sound of a player's bird flapping its wings.&lt;br /&gt;
SFX_ChannelAvailable      = $FF&lt;br /&gt;
&lt;br /&gt;
HunterBirdXVel_Right        = $02  ; X-velocity for hunter bird moving right&lt;br /&gt;
HunterBirdXVel_Left         = $FD  ; X-velocity for hunter bird moving left (-3)&lt;br /&gt;
HunterBirdX_OffscreenLeft   = $1A  ; Spawn X-coordinate for hunter bird appearing from left&lt;br /&gt;
HunterBirdX_OffscreenRight  = $BE  ; Spawn X-coordinate for hunter bird appearing from right&lt;br /&gt;
HunterBirdYOffsetAboveRider = $0F  ; Vertical offset (15 pixels) for hunter bird above rider&lt;br /&gt;
&lt;br /&gt;
X_VEL_TO_LUT_INDEX_OFFSET = $05   ; Offset to convert signed X-velocity to 0-based LUT index (e.g., index 5 = zero movement)&lt;br /&gt;
&lt;br /&gt;
Direction_Right = $01&lt;br /&gt;
Direction_Left  = $FF&lt;br /&gt;
&lt;br /&gt;
TOP_SCREEN_Y_BOUNDARY = $10         ; Y-coordinate of the top screen edge for bounce&lt;br /&gt;
&lt;br /&gt;
SKID_VELOCITY_THRESHOLD_RIGHT = $03  ; Min X-velocity (e.g. +3) to initiate a skid when turning left&lt;br /&gt;
SKID_VELOCITY_THRESHOLD_LEFT  = $FE  ; Max X-velocity (e.g. -2) to initiate a skid when turning right&lt;br /&gt;
                                     ; (Max left speed is -3, which is $FD)&lt;br /&gt;
SKID_ANIMATION_FRAME = $04           ; Footstep animation index when skidding&lt;br /&gt;
&lt;br /&gt;
                               ; NMIModeFlag Values&lt;br /&gt;
NMIMode_NormalGame      = $00  ; Normal in-game NMI processing&lt;br /&gt;
NMIMode_SplitScreen160A = $01  ; 160A portion of split screen NMI&lt;br /&gt;
NMIMode_SplitScreen320A = $FF  ; 320A portion of split screen NMI&lt;br /&gt;
&lt;br /&gt;
                               ; Console Switch Masks (from SWCHB - Active Low)&lt;br /&gt;
SWCHB_Reset_Mask = %00000001   ; Bit 0 for Reset&lt;br /&gt;
SWCHB_Select_Mask = %00000010  ; Bit 1 for Select&lt;br /&gt;
SWCHB_Pause_Mask = %00001000   ; Bit 3 for Pause&lt;br /&gt;
&lt;br /&gt;
                         ; Control Register Values&lt;br /&gt;
CTRL_DMA_ON_160AB = $40  ; single-width chars, 160A/B, border-off&lt;br /&gt;
CTRL_DMA_OFF      = $60&lt;br /&gt;
CTRL_DMA_ON_320AC = $4B  ; single-width chars, 320A/C, border-on&lt;br /&gt;
&lt;br /&gt;
                                    ; Input Register Bitmasks&lt;br /&gt;
Input_FireButtonMask EQU %10000000  ; Bit 7 for fire button&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; ****************** MACROS&lt;br /&gt;
&lt;br /&gt;
; ASCII to HSC text encoding...&lt;br /&gt;
 mac WATKINS&lt;br /&gt;
 dc.b {1}-&amp;quot;A&amp;quot;&lt;br /&gt;
 endm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; ****************** ROM &lt;br /&gt;
&lt;br /&gt;
  ORG $8000&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetBirdRandomTurnTimers&lt;br /&gt;
; Sets the 16-bit turn timer for an AI bird (index in X) to a new random value&lt;br /&gt;
; based on its TurnTimerIndex. Also toggles the bird's direction.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetBirdRandomTurnTimers&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
&lt;br /&gt;
  LDY GameObjectTurnTimerIndex,X&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
  AND #$0F&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC TurnCheckTimerValuesLoLUT,Y&lt;br /&gt;
  STA GameObjectTurnCheckTimerLo,X&lt;br /&gt;
  LDA TurnCheckTimerValuesHiLUT,Y&lt;br /&gt;
  STA GameObjectTurnCheckTimerHi,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; RunEggObjectProcessing&lt;br /&gt;
; Main routine to update the state and behavior of an egg object (index in X).&lt;br /&gt;
; This is a state machine that handles an egg's lifecycle:&lt;br /&gt;
; - State 1 (Egg): A stationary egg on a platform, counting down to hatch.&lt;br /&gt;
; - State 2 (Hatching): The egg is wiggling, counting down to reveal the rider.&lt;br /&gt;
; - State 3 (RiderOnShell): A rider stands on the broken shell for a short time.&lt;br /&gt;
; - State 4 (StandingRider): The rider stands alone, waiting for a hunter bird.&lt;br /&gt;
; It also handles the physics for an egg when it is airborne.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
RunEggObjectProcessing&lt;br /&gt;
  LDA GameObjectState,X               ; Get the current state of the egg&lt;br /&gt;
  BEQ ExitEggProcessing_A             ; If state is 0 (EggState_None), skip processing&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectInAir,X                       ; Is the egg currently airborne?&lt;br /&gt;
  BEQ ProcessEggOnPlatform                    ; If not (on a platform), handle platform logic.&lt;br /&gt;
  JSR EggIsAirborne                           ; If airborne, set up egg-specific physics parameters...&lt;br /&gt;
  JMP UpdateEggPhysicsAndPlatformInteraction  ; ...and jump to the physics/platform interaction handler.&lt;br /&gt;
&lt;br /&gt;
ProcessEggOnPlatform&lt;br /&gt;
  LDA LevelBCD                       ; Get current level in BCD format&lt;br /&gt;
  CMP #$03                           ; Is it Level 3 or higher? (BCD comparison)&lt;br /&gt;
  BNE ProcessEgg_StandardBehavior    ; If not, eggs behave normally.&lt;br /&gt;
  JSR CheckIfEggSlippingOffPlatform  ; On Level 3+, platforms are slippery. Check if egg is near an edge.&lt;br /&gt;
  LDA Temp60                         ; Check result from the slip check.&lt;br /&gt;
  BNE ProcessEgg_StandardBehavior    ; If not slipping, proceed with standard behavior.&lt;br /&gt;
&lt;br /&gt;
; Egg is on Level 3+ AND is slipping off the platform's edge.&lt;br /&gt;
  LDA #$01               ; Set InAir flag to true.&lt;br /&gt;
  STA GameObjectInAir,X  ; Make the egg airborne, causing it to fall.&lt;br /&gt;
                         ; Falls through to ExitEggProcessing_A (RTS).&lt;br /&gt;
ExitEggProcessing_A&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessEgg_StandardBehavior&lt;br /&gt;
; This is the main state machine for an egg that is resting on a platform.&lt;br /&gt;
  LDA GameObjectState,X         ; Get current state of the egg.&lt;br /&gt;
  CMP #EggState_StandingRider   ; State 4: Rider is standing alone. No further action needed here.&lt;br /&gt;
  BEQ ExitEggProcessing_A       ; Its fate is now tied to a hunter bird.&lt;br /&gt;
  CMP #EggState_Hatching        ; State 2: Egg is actively hatching.&lt;br /&gt;
  BEQ ProcessHatchingEggTimer   ; Process its hatching animation timer.&lt;br /&gt;
  CMP #EggState_RiderOnShell    ; State 3: Rider is on the shell.&lt;br /&gt;
  BEQ ProcessRiderOnShellTimer  ; Process its timer for shedding the shell.&lt;br /&gt;
&lt;br /&gt;
                               ; --- State 1: Egg is waiting to hatch ---&lt;br /&gt;
  DEC GameObjectCountdownLo,X  ; Decrement low byte of the 16-bit hatch timer.&lt;br /&gt;
  BEQ DecrementHatchTimerHi    ; If low byte wrapped, handle the high byte.&lt;br /&gt;
  RTS                          ; Timer still active, nothing more to do.&lt;br /&gt;
&lt;br /&gt;
DecrementHatchTimerHi&lt;br /&gt;
  DEC GameObjectCountdownHi,X  ; Decrement high byte of hatch timer.&lt;br /&gt;
  BEQ AttemptToHatchEgg        ; If timer expired, try to hatch.&lt;br /&gt;
  BMI AttemptToHatchEgg        ; Also handle underflow just in case.&lt;br /&gt;
ExitEggProcessing_B&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AttemptToHatchEgg&lt;br /&gt;
  LDA Difficulty           ; Get current game difficulty.&lt;br /&gt;
  BEQ ExitEggProcessing_B  ; On Beginner difficulty, eggs never hatch.&lt;br /&gt;
  LDA EnemyBirdCount       ; Get current number of active enemy birds.&lt;br /&gt;
  CMP MaxEnemyBirdCount    ; Compare with the maximum allowed on screen for this level.&lt;br /&gt;
  BCC ProceedWithHatching  ; If we are below the max, the egg can hatch.&lt;br /&gt;
&lt;br /&gt;
; Max enemy birds reached, cannot hatch now. Reset a short timer to try again soon.&lt;br /&gt;
  LDA #$0A  ; Reset countdown low byte.&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  LDA #$00  ; Reset countdown high byte.&lt;br /&gt;
  STA GameObjectCountdownHi,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProceedWithHatching&lt;br /&gt;
  INC EnemyBirdCount            ; One more enemy bird will be active (the rider).&lt;br /&gt;
  LDA #EggState_Hatching        ; Set egg state to 'hatching' (state 2).&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$05                      ; Set initial low byte for hatching animation timer.&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  LDA #$0A                      ; Set initial high byte for hatching animation timer.&lt;br /&gt;
  STA GameObjectCountdownHi,X&lt;br /&gt;
  LDA #SFX_EggWigglingHatching  ; Schedule the egg wiggling/hatching sound effect.&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessHatchingEggTimer         ; --- State 2: Egg is actively hatching ---&lt;br /&gt;
  DEC GameObjectCountdownLo,X   ; Decrement low byte of hatching animation timer.&lt;br /&gt;
  BEQ ContinueHatchingEggTimer  ; If low byte wrapped, process high byte and animation.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ContinueHatchingEggTimer&lt;br /&gt;
  LDA GameObjectCountdownHi,X&lt;br /&gt;
  AND #$07                      ; Check lower 3 bits of high byte timer.&lt;br /&gt;
  BEQ UpdateEggWiggleAnimation  ; If zero, it's time to update the wiggle animation frame.&lt;br /&gt;
                                ; Otherwise, play the sound effect (every time Lo wraps, unless Hi&amp;amp;7 is 0).&lt;br /&gt;
  LDA #SFX_EggWigglingHatching  ; Schedule egg wiggling/hatching sound effect.&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
&lt;br /&gt;
UpdateEggWiggleAnimation&lt;br /&gt;
  DEC GameObjectCountdownHi,X   ; Decrement high byte of hatching animation timer.&lt;br /&gt;
  BEQ TransitionToRiderOnShell  ; If timer fully expired, transition to the next state.&lt;br /&gt;
  LDA ObjectWiggleAnimation,X   ; Get current wiggle frame.&lt;br /&gt;
  EOR #$01                      ; Toggle wiggle frame (0 &amp;lt;-&amp;gt; 1).&lt;br /&gt;
  STA ObjectWiggleAnimation,X   ; Store new wiggle frame.&lt;br /&gt;
  LDA #$0A                      ; Reset low byte of hatching animation timer for the next wiggle cycle.&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TransitionToRiderOnShell&lt;br /&gt;
  LDA #EggState_RiderOnShell   ; Egg is now 'rider standing on shell' (state 3).&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$0F                     ; Set timer for how long rider stays on the shell.&lt;br /&gt;
  STA GameObjectCountdownLo,X  ; (High byte is implicitly 0 from the previous countdown).&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessRiderOnShellTimer       ; --- State 3: Rider standing on broken shell ---&lt;br /&gt;
  DEC GameObjectCountdownLo,X  ; Decrement timer for rider on shell.&lt;br /&gt;
  BEQ EggIsRiderNoShell        ; If timer expires, transition to rider without shell.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; EggIsRiderNoShell&lt;br /&gt;
; Called when an egg (object X) has progressed to the state of being just a &lt;br /&gt;
; rider (state 4), having shed its shell. This routine finds an available enemy&lt;br /&gt;
; bird slot and spawns a new &amp;quot;hunter&amp;quot; bird (object Y) to fly in and retrieve&lt;br /&gt;
; this rider. X contains the index of the egg object (now the rider).&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
EggIsRiderNoShell&lt;br /&gt;
  LDA #EggState_StandingRider    ; Set state to: rider standing without shell.&lt;br /&gt;
  STA GameObjectState,X          ; Update the former egg object's state.&lt;br /&gt;
&lt;br /&gt;
                                 ; Find an available (dead) enemy bird slot to spawn the hunter bird.&lt;br /&gt;
  LDY #MinEnemyBirdObjectIndex   ; Start from the first enemy bird slot (index 2).&lt;br /&gt;
FindDeadEnemyBirdSlotLoop&lt;br /&gt;
  LDA.w GameObjectState,Y        ; Get state of potential enemy bird Y.&lt;br /&gt;
  BEQ FoundDeadEnemyBirdSlot     ; If state is 0 (dead), the slot is available.&lt;br /&gt;
  INY                            ; Try next bird slot.&lt;br /&gt;
  CPY #MaxEnemyBirdSlots         ; Have we checked all enemy bird slots (up to 9)?&lt;br /&gt;
  BNE FindDeadEnemyBirdSlotLoop  ; If not, loop.&lt;br /&gt;
&lt;br /&gt;
FoundDeadEnemyBirdSlot&lt;br /&gt;
                                  ; Initialize the new hunter bird (object Y) based on the rider (object X).&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X    ; Get rider's original bird type/level (e.g., Bounder, Hunter, Shadow Lord).&lt;br /&gt;
  STA ObjectBirdLevelAndType,Y    ; Set the new hunter bird's type/level to match.&lt;br /&gt;
&lt;br /&gt;
  TYA                             ; Bird Y (the hunter) is now hunting Rider X (the prey).&lt;br /&gt;
  STA GameObjectHunterIndex,X     ; Link: Rider X is being hunted by Bird Y.&lt;br /&gt;
  TXA                             ;&lt;br /&gt;
  STA GameObjectPreyIndex,Y       ; Link: Bird Y is hunting Rider X.&lt;br /&gt;
&lt;br /&gt;
  STY TempSavedYForHunterBirdSpawn         ; Save Y (hunter bird index) as it will be clobbered by the JSR.&lt;br /&gt;
  JSR DetermineInitialHunterBirdDirection  ; Determine which side of the screen the bird should spawn from.&lt;br /&gt;
  LDY TempSavedYForHunterBirdSpawn         ; Restore Y.&lt;br /&gt;
&lt;br /&gt;
  STA GameObjectDirection,Y                ; Set hunter bird's initial direction.&lt;br /&gt;
  LDA GameObjectDirection,Y                ; Load direction again to check sign.&lt;br /&gt;
  BMI SpawnHunterBirdFacingLeft&lt;br /&gt;
&lt;br /&gt;
SpawnHunterBirdFacingRight&lt;br /&gt;
  LDA #HunterBirdXVel_Right       ; Set X velocity for right-facing bird.&lt;br /&gt;
  STA GameObjectXVelocity,Y&lt;br /&gt;
  LDA #HunterBirdX_OffscreenLeft  ; Spawn off-screen to the left.&lt;br /&gt;
  JMP SetHunterBirdInitialXPosition&lt;br /&gt;
&lt;br /&gt;
SpawnHunterBirdFacingLeft&lt;br /&gt;
  LDA #HunterBirdXVel_Left         ; Set X velocity for left-facing bird.&lt;br /&gt;
  STA GameObjectXVelocity,Y&lt;br /&gt;
  LDA #HunterBirdX_OffscreenRight  ; Spawn off-screen to the right.&lt;br /&gt;
&lt;br /&gt;
SetHunterBirdInitialXPosition&lt;br /&gt;
  STA GameObjectXCoordHi,Y  ; Set hunter bird's initial X coordinate (high byte).&lt;br /&gt;
&lt;br /&gt;
; Set hunter bird's initial Y coordinate to be slightly above the rider.&lt;br /&gt;
  LDA GameObjectYCoordHi,X          ; Get rider's Y coordinate.&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #HunterBirdYOffsetAboveRider  ; Spawn 15 pixels above the rider.&lt;br /&gt;
  STA GameObjectYCoordHi,Y          ; Set hunter bird's Y coordinate.&lt;br /&gt;
&lt;br /&gt;
; Initialize various properties for the newly spawned hunter bird.&lt;br /&gt;
  LDA #$01                            ; True for boolean flags.&lt;br /&gt;
  STA GameObjectInAir,Y               ; Hunter bird starts in the air.&lt;br /&gt;
  STA.w GameObjectAIMode,Y            ; Set hunter bird's AI mode to seeking.&lt;br /&gt;
  LDA #$00                            ; Zero for timers and some physics components.&lt;br /&gt;
  STA GameObjectChargingTimer,Y       ; Clear charging timer.&lt;br /&gt;
  STA GameObjectFootstepAnimTimer,Y   ; Clear footstep animation timer.&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,Y   ; Reset footstep animation frame.&lt;br /&gt;
  STA GameObjectYVelocityLo,Y         ; Clear Y velocity (low byte).&lt;br /&gt;
  STA GameObjectYVelocityHi,Y         ; Clear Y velocity (high byte).&lt;br /&gt;
  STA GameObjectPlatformSkipState,Y   ; Not skipping on a platform.&lt;br /&gt;
  STA GameObjectSkidDirection,Y       ; Not skidding.&lt;br /&gt;
  STA GameObjectAnimationFrame,Y      ; Reset animation frame.&lt;br /&gt;
  STA.w GameObjectAlive,Y             ; Mark as alive (though its state defines behavior).&lt;br /&gt;
  STA GameObjectAITargetDelayTimer,X  ; Reset AI target delay for the rider it was targeting.&lt;br /&gt;
&lt;br /&gt;
  LDA #$01                           ; Default timer reset value.&lt;br /&gt;
  STA GameObjectTimerResetValue,Y    ; Set timer reset value for hunter bird.&lt;br /&gt;
  STA GameObjectEventTimer1,Y        ; Set event timer 1 for hunter bird.&lt;br /&gt;
&lt;br /&gt;
  LDA #State_BirdSeekingRider        ; Set state to: bird is actively seeking its rider.&lt;br /&gt;
  STA GameObjectState,Y              ; Update hunter bird's state.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DetermineInitialHunterBirdDirection&lt;br /&gt;
; Determines the initial direction for a newly spawned hunter bird. The hunter&lt;br /&gt;
; pursues the rider (object index in X). The routine checks which platform the&lt;br /&gt;
; rider is on to decide if the hunter should enter from the left or right.&lt;br /&gt;
; Returns:&lt;br /&gt;
; A = Direction_Right ($01) if rider is on a known platform.&lt;br /&gt;
; A = Direction_Left ($FF) if rider is not found on a known platform.&lt;br /&gt;
; Preserves: X / Modifies: Y, A&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DetermineInitialHunterBirdDirection&lt;br /&gt;
  LDY #$06                     ; Start with the last platform index (Platform 6).&lt;br /&gt;
  LDA GameObjectYCoordHi,X     ; Get rider's Y coordinate (high byte).&lt;br /&gt;
FindRiderPlatformLoop&lt;br /&gt;
  CMP PlatformTopCoordinate,Y  ; Is rider at the Y level of this platform's top?&lt;br /&gt;
  BNE RiderNotOnThisPlatform   ; If not, check the next platform.&lt;br /&gt;
&lt;br /&gt;
; Rider is at the correct Y level, now check X bounds.&lt;br /&gt;
  LDA GameObjectXCoordHi,X           ; Get rider's X coordinate (high byte).&lt;br /&gt;
  CMP PlatformLeftsideCoordinate,Y   ; Is rider to the right of the platform's left edge?&lt;br /&gt;
  BCC RiderNotOnThisPlatform         ; If rider is left of the left edge, not on this platform.&lt;br /&gt;
  CMP PlatformRightsideCoordinate,Y  ; Is rider to the left of the platform's right edge?&lt;br /&gt;
  BCS RiderNotOnThisPlatform         ; If rider is right of the right edge, not on this platform.&lt;br /&gt;
&lt;br /&gt;
; Rider is on this platform.&lt;br /&gt;
  LDA #Direction_Right  ; Return direction: RIGHT.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
RiderNotOnThisPlatform&lt;br /&gt;
  DEY                        ; Next platform index.&lt;br /&gt;
  BPL FindRiderPlatformLoop  ; If platform index is still valid, loop.&lt;br /&gt;
&lt;br /&gt;
; Rider was not found on any of the checked platforms.&lt;br /&gt;
  LDA #Direction_Left  ; Return direction: LEFT.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; EggIsAirborne&lt;br /&gt;
; Sets up the physics parameters in Zero Page specifically for an airborne egg&lt;br /&gt;
; object. Eggs have unique, floaty physics compared to birds. After setting&lt;br /&gt;
; the parameters, it jumps to the common airborne physics update routine.&lt;br /&gt;
; X = index of the egg GameObject&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
EggIsAirborne&lt;br /&gt;
; Set egg's gravity (WeightFactor). A lower value means less gravity.&lt;br /&gt;
  LDA #EGG_WEIGHT_FACTOR&lt;br /&gt;
  STA Temp64WeightFactor&lt;br /&gt;
&lt;br /&gt;
; Set egg's maximum upward speed (a small negative value for a slow rise).&lt;br /&gt;
  LDA #EGG_MAX_RISE_SPEED_NEG&lt;br /&gt;
  STA Temp63MaxRiseSpeedNeg&lt;br /&gt;
&lt;br /&gt;
; Set egg's maximum downward speed (a small positive value for a slow fall).&lt;br /&gt;
  LDA #EGG_MAX_FALL_SPEED&lt;br /&gt;
  STA Temp62MaxFallSpeed&lt;br /&gt;
&lt;br /&gt;
; Set egg's X-axis speed Look-Up Table index range. This controls its&lt;br /&gt;
; horizontal drift. For eggs, this range is narrow, resulting in slow drift.&lt;br /&gt;
  LDA #EGG_X_SPEED_LUT_MAX_CLAMP_INDEX&lt;br /&gt;
  STA Temp61MaxPhysicsXSpeedIndex         ; Smallest X-speed LUT index egg can use.&lt;br /&gt;
  LDA #EGG_X_SPEED_LUT_MIN_CLAMP_INDEX&lt;br /&gt;
  STA Temp60MinPhysicsXSpeedIndex         ; Largest X-speed LUT index egg can use.&lt;br /&gt;
&lt;br /&gt;
  JMP UpdateAirborneXPositionAndVelocity  ; Proceed to common X-axis physics update.&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdateAirborneObjectPhysics&lt;br /&gt;
; Main physics routine for airborne birds and pterodactyls. It loads the&lt;br /&gt;
; appropriate physics parameters for the object type and then jumps to the&lt;br /&gt;
; common X and Y position update logic.&lt;br /&gt;
; Input: X = GameObject index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdateAirborneObjectPhysics&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$08             ; check if state=troll holding the bird&lt;br /&gt;
  BNE ObjectIsAirborne&lt;br /&gt;
  JMP TrollHoldingTheBird&lt;br /&gt;
ObjectIsAirborne&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X ; Get bird type for index with physics LUTs&lt;br /&gt;
  LDA.w BirdPhysicsIndexMinByType,Y&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA.w BirdPhysicsIndexMaxByType,Y&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA BirdWeightByTypeLUT,Y&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA BirdMaxDownVelocityByTypeLUT,Y&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA BirdMaxUpVelocityByTypeLUT,Y&lt;br /&gt;
  STA Temp63&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdateAirborneXPositionAndVelocity&lt;br /&gt;
; This is the core 16-bit physics update routine for all airborne objects.&lt;br /&gt;
; It's jumped to after physics parameters have been loaded into ZP temps.&lt;br /&gt;
; It handles:&lt;br /&gt;
; 1. X-velocity to LUT index conversion and clamping.&lt;br /&gt;
; 2. 16-bit X-position update from LUT.&lt;br /&gt;
; 3. Horizontal screen wrapping.&lt;br /&gt;
; 4. 16-bit Y-velocity update (applying gravity).&lt;br /&gt;
; 5. 16-bit Y-position update from velocity.&lt;br /&gt;
; Input: X = GameObject index. ZP temps $60-$64 must be pre-loaded.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdateAirborneXPositionAndVelocity&lt;br /&gt;
  LDA GameObjectXVelocity,X                 ; Load current X velocity component&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #X_VEL_TO_LUT_INDEX_OFFSET            ; Convert signed X velocity to an unsigned LUT index base.&lt;br /&gt;
                                            ; E.g., if XVel is -5 to +5, and OFFSET is 5, result is 0 to 10.&lt;br /&gt;
                                            ; This resulting index (in Y) is then adjusted by specific min/max allowed indices.&lt;br /&gt;
  TAY                                       ; Y = initial candidate X speed LUT index&lt;br /&gt;
&lt;br /&gt;
  BMI XSpeedIndexIsNegative_SetToMaxAllowed       ; If Y &amp;lt; 0 (unlikely for typical Xvel range), use MaxAllowedIndex.&lt;br /&gt;
                                                  ; else (Y &amp;gt;= 0)&lt;br /&gt;
XSpeedIndex_CheckAgainstMaxAllowed&lt;br /&gt;
  CPY Temp61MaxPhysicsXSpeedIndex                 ; Compare Y with Temp61MaxPhysicsXSpeedIndex&lt;br /&gt;
  BCS XSpeedIndex_AtOrExceedsMax_CheckMinAllowed  ; If Y &amp;gt;= Temp61MaxPhysicsXSpeedIndex, Y is used as is for min check.&lt;br /&gt;
                                                  ; else (Y &amp;lt; Temp61MaxPhysicsXSpeedIndex)&lt;br /&gt;
XSpeedIndexIsNegative_SetToMaxAllowed             ; also reached if Y &amp;lt; MaxAllowedIndex&lt;br /&gt;
  LDY Temp61MaxPhysicsXSpeedIndex                 ; Y = Temp61MaxPhysicsXSpeedIndex. If Y was &amp;lt; Max, it's forced to Max.&lt;br /&gt;
&lt;br /&gt;
XSpeedIndex_AtOrExceedsMax_CheckMinAllowed&lt;br /&gt;
  CPY Temp60MinPhysicsXSpeedIndex ; Compare Y (now possibly MaxAllowedIndex) with Temp60MinPhysicsXSpeedIndex&lt;br /&gt;
  BEQ XSpeedIndex_IsFinalized     ; If Y == MinAllowedIndex, the index is finalized.&lt;br /&gt;
  BCC XSpeedIndex_IsFinalized     ; If Y &amp;lt; MinAllowedIndex, the index is also finalized.&lt;br /&gt;
                                  ; (This implies that values &amp;lt; MinAllowedIndex are treated as MinAllowedIndex by table structure or subsequent logic)&lt;br /&gt;
                                  ; else (Y &amp;gt; MinAllowedIndex)&lt;br /&gt;
  LDY Temp60MinPhysicsXSpeedIndex ; Y = Temp60MinPhysicsXSpeedIndex. If Y was &amp;gt; Min, it's forced to Min.&lt;br /&gt;
&lt;br /&gt;
XSpeedIndex_IsFinalized&lt;br /&gt;
  TYA                             ; A = final Y (the determined LUT index)&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #X_VEL_TO_LUT_INDEX_OFFSET  ; Convert the LUT index back to a signed X velocity value&lt;br /&gt;
  STA GameObjectXVelocity,X       ; Store the (potentially modified by LUT index logic) X velocity&lt;br /&gt;
&lt;br /&gt;
UpdateXPositionFromLUT&lt;br /&gt;
  CLC&lt;br /&gt;
  LDA GameObjectXCoordLo,X            ; Load current X sub-pixel coordinate&lt;br /&gt;
  ADC XPositionIncrementTableLoLUT,Y  ; Add X sub-pixel increment from LUT using final index Y&lt;br /&gt;
  STA GameObjectXCoordLo,X&lt;br /&gt;
  LDA GameObjectXCoordHi,X            ; Load current X pixel coordinate&lt;br /&gt;
  ADC XPositionIncrementTableHiLUT,Y  ; Add X pixel increment from LUT (with carry from Lo)&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
&lt;br /&gt;
HandleXScreenWrap&lt;br /&gt;
  CMP ObjectScreenWrapXRightEdgeLUT,X  ; Compare X with right edge for wrapping&lt;br /&gt;
  BCC CheckLeftEdgeWrap                ; If X &amp;lt; RightEdge, no right-to-left wrap.&lt;br /&gt;
  BEQ CheckLeftEdgeWrap                ; If X == RightEdge, also no right-to-left wrap.&lt;br /&gt;
                                       ; else (X &amp;gt; RightEdge) -&amp;gt; wrap from right to left&lt;br /&gt;
  LDA ObjectScreenWrapXLeftEdgeLUT,X   ; Load left edge X coordinate&lt;br /&gt;
  JMP StoreWrappedXAndCheckObjectRemoval&lt;br /&gt;
&lt;br /&gt;
CheckLeftEdgeWrap&lt;br /&gt;
  CMP ObjectScreenWrapXLeftEdgeLUT,X   ; Compare X with left edge for wrapping&lt;br /&gt;
  BCS XWrapHandled_ProceedToYPhysics   ; If X &amp;gt;= LeftEdge, no left-to-right wrap.&lt;br /&gt;
                                       ; else (X &amp;lt; LeftEdge) -&amp;gt; wrap from left to right&lt;br /&gt;
  LDA ObjectScreenWrapXRightEdgeLUT,X  ; Load right edge X coordinate&lt;br /&gt;
&lt;br /&gt;
StoreWrappedXAndCheckObjectRemoval&lt;br /&gt;
  STA GameObjectXCoordHi,X  ; Store wrapped X pixel coordinate&lt;br /&gt;
&lt;br /&gt;
  CPX #$0D                            ; Check if object index is Pterry or Egg (Indices $0A-$0C for Pterry, $0D-$18 for Egg)&lt;br /&gt;
                                      ; Player/Enemy birds are $00-$09.&lt;br /&gt;
  BCS XWrapHandled_ProceedToYPhysics  ; If Pterry or Egg, skip removal check.&lt;br /&gt;
                                      ; Object is a Player or Enemy Bird that wrapped&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #State_Hit                      ; is state=bird hit? ($05)&lt;br /&gt;
  BEQ KillBird                        ; If hit bird wrapped, remove it.&lt;br /&gt;
  CMP #PterryState_Leaving            ; is state=pterry leaving? ($0C) - This check is for birds, but PterryState is used.&lt;br /&gt;
                                      ; This implies a bird object could be in a &amp;quot;leaving&amp;quot; state, perhaps an unridden enemy bird.&lt;br /&gt;
  BEQ RemovePterry                    ; If &amp;quot;leaving&amp;quot; bird wrapped, remove it.&lt;br /&gt;
&lt;br /&gt;
XWrapHandled_ProceedToYPhysics&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X         ; Get object's type (0-2 Enemy, 3 Player, 4 Pterry)&lt;br /&gt;
  CMP #$04                             ; Is it Pterry? (Type 4)&lt;br /&gt;
  BEQ ApplyGravityAndYVelocity         ; If Pterry, always apply Y-velocity updates.&lt;br /&gt;
                                       ; Not Pterry (Player or Enemy Bird)&lt;br /&gt;
  LDA GameObjectInAir,X                ; Check if the bird is airborne (not on a platform)&lt;br /&gt;
  BEQ UpdateYPositionFromVelocityOnly  ; If on a platform (InAir == 0), skip Y-velocity changes due to gravity.&lt;br /&gt;
                                       ; Only update Y position based on its current (likely zeroed on landing) Y velocity.&lt;br /&gt;
ApplyGravityAndYVelocity&lt;br /&gt;
; Apply Y-velocity changes (gravity and clamping)&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp64WeightFactor&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA #$00                             ; Prepare to add carry to Hi byte&lt;br /&gt;
  ADC GameObjectYVelocityHi,X          ; A = Y_Vel_Hi + Carry&lt;br /&gt;
  BMI YVelocityIsUpward_CheckMaxRise   ; If Y-velocity is negative (moving up).&lt;br /&gt;
&lt;br /&gt;
; Y-velocity is positive (moving downward) or zero&lt;br /&gt;
  CMP Temp62MaxFallSpeed&lt;br /&gt;
  BEQ StoreYVelocityHi   ; If Y_Vel_Hi == Temp62MaxFallSpeed, store it.&lt;br /&gt;
  BCC StoreYVelocityHi   ; If Y_Vel_Hi &amp;lt; Temp62MaxFallSpeed, store it (falling slower than max is fine).&lt;br /&gt;
                         ; Else (Y_Vel_Hi &amp;gt; Temp62MaxFallSpeed - falling too fast)&lt;br /&gt;
  LDA #$00               ; Reset Lo byte of Y-velocity as Hi is being clamped&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA Temp62MaxFallSpeed ; Load Temp62MaxFallSpeed to clamp&lt;br /&gt;
  JMP StoreYVelocityHi&lt;br /&gt;
&lt;br /&gt;
YVelocityIsUpward_CheckMaxRise&lt;br /&gt;
  CMP Temp63MaxRiseSpeedNeg&lt;br /&gt;
                            ; e.g. Y_Vel_Hi=$FE(-2), Temp63MaxRiseSpeedNeg=$FC(-4). $FE &amp;gt;= $FC (less negative), so BCS is taken.&lt;br /&gt;
  BCS StoreYVelocityHi      ; If Y_Vel_Hi &amp;gt;= Temp63MaxRiseSpeedNeg (rising slower or at max rise), store it.&lt;br /&gt;
                            ; Else (Y_Vel_Hi &amp;lt; Temp63MaxRiseSpeedNeg - rising too fast, i.e., more negative)&lt;br /&gt;
  LDA #$00                  ; Reset Lo byte of Y-velocity&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA Temp63MaxRiseSpeedNeg ; Load Temp63MaxRiseSpeedNeg to clamp&lt;br /&gt;
&lt;br /&gt;
StoreYVelocityHi&lt;br /&gt;
  STA GameObjectYVelocityHi,X  ; Store the (clamped) Hi byte of Y-velocity&lt;br /&gt;
&lt;br /&gt;
UpdateYPositionFromVelocityOnly&lt;br /&gt;
; Update Y-coordinates from Y-velocity&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC GameObjectYCoordLo,X            ; Add Y_Vel_Lo to Y_Coord_Lo&lt;br /&gt;
  STA GameObjectYCoordLo,X&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  ADC GameObjectYVelocityHi,X         ; Add Y_Vel_Hi to Y_Coord_Hi (with carry)&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  JMP HandleObjectTopScreenCollision  ; Jump to process Y boundary conditions (top of screen bounce, troll grab)&lt;br /&gt;
&lt;br /&gt;
RemovePterry&lt;br /&gt;
  LDA #$00               ; Pterry is dead and gone&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA PterryAliveCount&lt;br /&gt;
  BEQ SkipPterryDecrement&lt;br /&gt;
  DEC PterryAliveCount&lt;br /&gt;
SkipPterryDecrement&lt;br /&gt;
  JSR UpdatePterryRespawnTimer&lt;br /&gt;
  LSR PterryCountdownHi  ; divide pterry &lt;br /&gt;
  ROR PterryCountdownLo  ; counter by two&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
KillBird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  CPX #$02  ; players are X=0,1&lt;br /&gt;
  BCC KillPlayerBird&lt;br /&gt;
  DEC EnemyBirdCount&lt;br /&gt;
  BNE MoreEnemyBirdsLeft&lt;br /&gt;
  LDA EggsPresentCount&lt;br /&gt;
  BNE MoreEnemyBirdsLeft&lt;br /&gt;
  JMP SetupNextLevel&lt;br /&gt;
MoreEnemyBirdsLeft&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
KillPlayerBird&lt;br /&gt;
  LDA P0Lives,X&lt;br /&gt;
  BPL SetupNewPlayerBird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetupNewPlayerBird&lt;br /&gt;
  JMP SpawnNewBird&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; HandleObjectTopScreenCollision&lt;br /&gt;
; Checks if an object has moved above the top screen boundary. If so, it reverses&lt;br /&gt;
; and dampens its Y velocity for a bounce effect and clamps its Y position.&lt;br /&gt;
; Input: X = GameObject index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandleObjectTopScreenCollision&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectYCoordHi,X                ; Get object's current Y position (high byte)&lt;br /&gt;
  CMP #TOP_SCREEN_Y_BOUNDARY              ; Compare with the top screen boundary&lt;br /&gt;
  BCS ProcessTrollGrab_Or_FurtherYChecks  ; If Y &amp;gt;= TOP_BOUNDARY (i.e., below or at safe margin),&lt;br /&gt;
                                          ; object is not at/above top, skip bounce logic.&lt;br /&gt;
                                          ; Branch to ProcessTrollGrab_Or_FurtherYChecks&lt;br /&gt;
&lt;br /&gt;
                                  ; Object is at or above the top screen boundary (Y &amp;lt; TOP_SCREEN_Y_BOUNDARY)&lt;br /&gt;
  LDA GameObjectYVelocityHi,X     ; Get Y velocity (high byte)&lt;br /&gt;
  BPL ClampYAtTopBoundaryAndExit  ; If velocity is positive or zero (moving down/still),&lt;br /&gt;
                                  ; no upward bounce needed, just clamp position.&lt;br /&gt;
&lt;br /&gt;
            ; Object is moving upwards into the top boundary (Y velocity is negative)&lt;br /&gt;
            ; Reverse and dampen Y velocity for bounce effect.&lt;br /&gt;
  EOR #$FF  ; Negate Y-velocity (High Byte), part 1&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01  ; Negate Y-velocity (High Byte), part 2 (Two's complement)&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectYVelocityLo,X  ; Get Y velocity (low byte)&lt;br /&gt;
  EOR #$FF                     ; Negate Y-velocity (Low Byte), part 1&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                     ; Negate Y-velocity (Low Byte), part 2&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
&lt;br /&gt;
                               ; Dampen the bounce velocity: Divide Y-velocity by 4&lt;br /&gt;
  CLC&lt;br /&gt;
  ROR GameObjectYVelocityHi,X  ; Shift combined 16-bit velocity right (effectively VelY / 2)&lt;br /&gt;
  ROR GameObjectYVelocityLo,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ROR GameObjectYVelocityHi,X  ; Shift again (effectively VelY / 4 total)&lt;br /&gt;
  ROR GameObjectYVelocityLo,X&lt;br /&gt;
&lt;br /&gt;
ClampYAtTopBoundaryAndExit&lt;br /&gt;
  LDA #TOP_SCREEN_Y_BOUNDARY   ; Load the top boundary Y coordinate&lt;br /&gt;
  STA GameObjectYCoordHi,X     ; Clamp object's Y position to the top boundary&lt;br /&gt;
  RTS                          ; Return from NMI or subroutine&lt;br /&gt;
&lt;br /&gt;
ProcessTrollGrab_Or_FurtherYChecks&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$08&lt;br /&gt;
  BEQ TrollHoldingTheBird&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP TrollGrabHeight,X&lt;br /&gt;
  BCS TrollJustGrabbedTheBird&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TrollJustGrabbedTheBird&lt;br /&gt;
  CPX #$0D  ; Eggs can't be grabbed (but Pterry can?!?)&lt;br /&gt;
  BCS TrollKilledEnemyBird&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TrollHoldingTheBird&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$BB                  ; See if the bird pulled down far enough to die&lt;br /&gt;
  BCS TrollKilledThBird&lt;br /&gt;
  INC GameObjectYCoordHi,X  ; Pull the bird down some more&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TrollKilledThBird&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS GotoKillBird  ; branch if non-player enemy bird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  JMP StartPlayerDeath&lt;br /&gt;
GotoKillBird&lt;br /&gt;
  JMP KillBird&lt;br /&gt;
&lt;br /&gt;
TrollKilledEnemyBird&lt;br /&gt;
; a shortened version of the KillBird routine&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  DEC EggsPresentCount&lt;br /&gt;
  BNE ExitTrollKillRoutine&lt;br /&gt;
  LDA EnemyBirdCount&lt;br /&gt;
  BNE ExitTrollKillRoutine&lt;br /&gt;
  JMP SetupNextLevel&lt;br /&gt;
&lt;br /&gt;
ExitTrollKillRoutine&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; ProcessBirdToBirdCollisionLoop&lt;br /&gt;
; Checks for collisions between the bird object in X and all other birds with a&lt;br /&gt;
; lower index. Handles simple horizontal bounces for non-player birds.&lt;br /&gt;
; Input: X = Index of the primary bird for collision check&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ProcessBirdToBirdCollisionLoop&lt;br /&gt;
  TXA                           ; A = ObjX_idx&lt;br /&gt;
  TAY                           ; Y_reg = ObjX_idx (used as the initial counter for ObjY loop)&lt;br /&gt;
  PHA                           ; Push ObjX_idx onto stack (will be retrieved by PLA in Bird2BirdIterateAndCheckObjY)&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY  ; Jump to the main loop logic for iterating through ObjY&lt;br /&gt;
&lt;br /&gt;
; Start of the logic for a specific ObjX vs ObjY pair&lt;br /&gt;
Bird2BirdFilterObjYAndDetectCollision&lt;br /&gt;
  LDA.w GameObjectState,Y           ; Get state of ObjY (current object in inner loop, index in Y_REG)&lt;br /&gt;
  BNE Bird2BirdCheckIfObjYBorn1     ; If not State_Dead ($00), check further&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY  ; ObjY is dead, skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
Bird2BirdCheckIfObjYBorn1&lt;br /&gt;
  CMP #State_Born1                    ; Is ObjY in State_Born1 ($03)?&lt;br /&gt;
  BNE Bird2BirdCheckIfObjYInvincible  ; If not, check next state&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY    ; ObjY is in Born1 state, skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
Bird2BirdCheckIfObjYInvincible&lt;br /&gt;
  CMP #State_Invincible             ; Is ObjY in State_Invincible ($06)?&lt;br /&gt;
  BNE Bird2BirdCheckIfObjYBorn2     ; If not, check next state&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY  ; ObjY is invincible, skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
Bird2BirdCheckIfObjYBorn2&lt;br /&gt;
  CMP #State_Born2                  ; Is ObjY in State_Born2 ($07)?&lt;br /&gt;
  BNE Bird2BirdCheckIfObjYAlive     ; If not, check if alive&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY  ; ObjY is in Born2 state, skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
Bird2BirdCheckIfObjYAlive&lt;br /&gt;
  LDA.w GameObjectAlive,Y                 ; Is ObjY alive?&lt;br /&gt;
  BNE Bird2BirdPerformCollisionDetection  ; If alive flag is non-zero, proceed to collision detection&lt;br /&gt;
  JMP Bird2BirdIterateAndCheckObjY        ; ObjY is not alive (e.g. riderless bird leaving), skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
Bird2BirdPerformCollisionDetection&lt;br /&gt;
  JSR GameObjCollisionDetection      ; Check collision between ObjX (in X_REG) and ObjY (in Y_REG)&lt;br /&gt;
                                     ; Carry will be CLEAR if collision, SET if no collision.&lt;br /&gt;
  BCS Bird2BirdIterateAndCheckObjY   ; If Carry SET (no collision), skip to next ObjY&lt;br /&gt;
&lt;br /&gt;
; Collision detected between ObjX and ObjY (Carry is CLEAR)&lt;br /&gt;
  CPX #MinEnemyBirdObjectIndex  ; Is ObjX a player (index &amp;lt; 2)?&lt;br /&gt;
  BCS GameObject1NotAPlayer     ; If ObjX_idx &amp;gt;= 2 (enemy bird), check ObjY&lt;br /&gt;
  JMP CheckPlayerAndBirdY       ; ObjX is a player, jump to player-involved collision logic&lt;br /&gt;
&lt;br /&gt;
GameObject1NotAPlayer&lt;br /&gt;
  CPY #MinEnemyBirdObjectIndex  ; Is ObjY a player (index &amp;lt; 2)?&lt;br /&gt;
  BCS GameObject2NotAPlayer     ; If ObjY_idx &amp;gt;= 2 (enemy bird), both are non-players&lt;br /&gt;
  JMP CheckPlayerAndBirdY       ; ObjY is a player, ObjX is enemy, jump to player-involved logic&lt;br /&gt;
&lt;br /&gt;
GameObject2NotAPlayer           ; Both ObjX and ObjY are non-player birds (indices &amp;gt;= 2)&lt;br /&gt;
BirdsAtTheSameHeight&lt;br /&gt;
  LDA #SFX_BirdBirdBounce       ; Sound effect for bird-to-bird bounce&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
&lt;br /&gt;
BirdsHaveBounced   ; Collision response for two non-player birds&lt;br /&gt;
  PLA              ; A = Pop ObjY_idx from stack (pushed at Bird2BirdIterateAndCheckObjY)&lt;br /&gt;
  TAY              ; Y_REG = ObjY_idx (the object ObjX collided with)&lt;br /&gt;
                   ; X_REG still holds ObjX_idx&lt;br /&gt;
&lt;br /&gt;
  LDA TempCollisionOverlap  ; Load Y-axis overlap magnitude (from GameObjCollisionDetection)&lt;br /&gt;
  CMP #$07                  ; Collision_MinYOverlapForHorizBounce (value from original code)&lt;br /&gt;
  BCS HandleVerticalBounceCollision      ; If Y_overlap &amp;gt;= 7, jump to vertical bounce logic&lt;br /&gt;
&lt;br /&gt;
                                         ; Y_overlap &amp;lt; 7: Handle as a primarily horizontal collision (glancing blow)&lt;br /&gt;
                                         ; Nudge objects apart based on their relative X positions.&lt;br /&gt;
  LDA GameObjectXCoordHi,X               ; ObjX's X coordinate&lt;br /&gt;
  CMP GameObjectXCoordHi,Y               ; Compare with ObjY's X coordinate&lt;br /&gt;
  BCC Bird2BirdBounceObjXLeft_ObjYRight  ; If ObjX is to the left of ObjY&lt;br /&gt;
&lt;br /&gt;
                                         ; ObjX is to the right of (or at same X as) ObjY.&lt;br /&gt;
                                         ; Nudge ObjY left, ObjX right.&lt;br /&gt;
  LDA #Direction_Left                    ; Set ObjY direction to Left&lt;br /&gt;
  STA GameObjectDirection,Y&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$01                                      ; ObjY_X--&lt;br /&gt;
  STA GameObjectXCoordHi,Y&lt;br /&gt;
  LDA #Direction_Right                          ; Set ObjX direction to Right&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  INC GameObjectXCoordHi,X                      ; ObjX_X++&lt;br /&gt;
  JMP Bird2BirdApplyHorizontalBounceVelocities  ; Proceed to adjust velocities&lt;br /&gt;
&lt;br /&gt;
Bird2BirdBounceObjXLeft_ObjYRight&lt;br /&gt;
                                                ; Nudge ObjY right, ObjX left.&lt;br /&gt;
  LDA #Direction_Right                          ; Set ObjY direction to Right&lt;br /&gt;
  STA GameObjectDirection,Y&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                                      ; ObjY_X++&lt;br /&gt;
  STA GameObjectXCoordHi,Y&lt;br /&gt;
  LDA #Direction_Left                           ; Set ObjX direction to Left&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  DEC GameObjectXCoordHi,X                      ; ObjX_X--&lt;br /&gt;
                                                ; Fall through to Bird2BirdApplyHorizontalBounceVelocities&lt;br /&gt;
&lt;br /&gt;
Bird2BirdApplyHorizontalBounceVelocities&lt;br /&gt;
                                       ; Adjust X-velocities for both collided objects.&lt;br /&gt;
                                       ; The logic effectively reverses direction and slightly dampens.&lt;br /&gt;
                                       ; e.g., Vel +2 becomes -1; Vel -2 becomes +1. Stops if Vel was +/-1.&lt;br /&gt;
Bird2BirdAdjustObjX_Vel&lt;br /&gt;
  LDA GameObjectXVelocity,X            ; Get ObjX's current X-velocity&lt;br /&gt;
  BEQ Bird2BirdStoreAdjustedObjX_Vel   ; If velocity is zero, no change needed&lt;br /&gt;
  EOR #$FF                             ; Invert all bits (NOT operation)&lt;br /&gt;
  BPL Bird2BirdStoreAdjustedObjX_Vel   ; If result is positive (original was negative or zero), use this value&lt;br /&gt;
                                       ; (e.g., if original was -1 ($FF), result is $00)&lt;br /&gt;
                                       ; (e.g., if original was -2 ($FE), result is $01)&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02                             ; If result was negative (original was positive), add 2 to complete pseudo-negation&lt;br /&gt;
                                       ; (e.g., if original was +1 ($01), NOT is $FE. $FE + 2 = $00)&lt;br /&gt;
                                       ; (e.g., if original was +2 ($02), NOT is $FD. $FD + 2 = $FF (-1))&lt;br /&gt;
Bird2BirdStoreAdjustedObjX_Vel&lt;br /&gt;
  STA GameObjectXVelocity,X            ; Store new X-velocity for ObjX&lt;br /&gt;
&lt;br /&gt;
Bird2BirdAdjustObjY_Vel&lt;br /&gt;
  LDA GameObjectXVelocity,Y                    ; Get ObjY's current X-velocity&lt;br /&gt;
  BEQ Bird2BirdStoreAdjustedObjY_Vel           ; If velocity is zero, no change&lt;br /&gt;
  EOR #$FF                                     ; Invert all bits&lt;br /&gt;
  BPL Bird2BirdStoreAdjustedObjY_Vel           ; If result positive, use it&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02                                     ; Else, add 2&lt;br /&gt;
Bird2BirdStoreAdjustedObjY_Vel&lt;br /&gt;
  STA GameObjectXVelocity,Y                    ; Store new X-velocity for ObjY&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectInAir,Y                        ; Check if ObjY is in the air&lt;br /&gt;
  BEQ Bird2BirdFinishHorizontalBounceResponse  ; If ObjY is on a platform, this horizontal bounce is sufficient.&lt;br /&gt;
&lt;br /&gt;
  LDA TempCollisionOverlap                ; ObjY is airborne, check Y-overlap again&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BCS HandleVerticalBounceCollision       ; If Y_overlap &amp;gt;= 3, might need vertical bounce (external logic)&lt;br /&gt;
                                          ; Fall through to Bird2BirdFinishHorizontalBounceResponse if Y_overlap &amp;lt; 3 and ObjY airborne&lt;br /&gt;
&lt;br /&gt;
Bird2BirdFinishHorizontalBounceResponse&lt;br /&gt;
  RTS  ; Return from ProcessBirdToBirdCollisionLoop&lt;br /&gt;
&lt;br /&gt;
Bird2BirdIterateAndCheckObjY&lt;br /&gt;
  PLA&lt;br /&gt;
  DEY&lt;br /&gt;
  TYA&lt;br /&gt;
  BMI Bird2BirdFinishHorizontalBounceResponse&lt;br /&gt;
  PHA&lt;br /&gt;
  JMP Bird2BirdFilterObjYAndDetectCollision&lt;br /&gt;
HandleVerticalBounceCollision&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA GameObjectYVelocityLo,Y&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectYVelocityLo,Y&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  LDA GameObjectYVelocityHi,Y&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectYVelocityHi,Y&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  ROL&lt;br /&gt;
  ROR GameObjectYVelocityHi,X&lt;br /&gt;
  ROR GameObjectYVelocityLo,X&lt;br /&gt;
  LDA GameObjectYVelocityHi,Y&lt;br /&gt;
  ROL&lt;br /&gt;
  LDA GameObjectYVelocityHi,Y&lt;br /&gt;
  ROR&lt;br /&gt;
  STA GameObjectYVelocityHi,Y&lt;br /&gt;
  LDA GameObjectYVelocityLo,Y&lt;br /&gt;
  ROR&lt;br /&gt;
  STA GameObjectYVelocityLo,Y&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCC HandleBouncePhysicsForUpperObject&lt;br /&gt;
  LDA GameObjectYVelocityHi,Y&lt;br /&gt;
  BPL ClampWinnerVelocityOnBounce&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BCS ClampWinnerVelocityOnBounce&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ClampWinnerVelocityOnBounce&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameObjectYVelocityHi,Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HandleBouncePhysicsForUpperObject&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  BPL ClampBouncedObjectVelocityHi&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BCS ClampBouncedObjectVelocityHi&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ClampBouncedObjectVelocityHi&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; CheckPlayerAndBirdY&lt;br /&gt;
; Handles the complex logic for when a player collides with another bird&lt;br /&gt;
; (either another player or an enemy). Determines who wins the joust based on&lt;br /&gt;
; vertical position, awards points, and initiates death sequences.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
CheckPlayerAndBirdY&lt;br /&gt;
; A player and enemy bird -or- player and player have collided&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BNE DetermineJoustWinner&lt;br /&gt;
  JMP BirdsAtTheSameHeight&lt;br /&gt;
DetermineJoustWinner&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDA #SFX_BirdExplosion&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  CPY #$02&lt;br /&gt;
  BCS WhichBirdWasHigher ; branch if non-player enemy bird&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS WhichBirdWasHigher ; branch if non-player enemy bird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlayersWereATeam&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  LDA PlayerWasGladiator&lt;br /&gt;
  BEQ CalculateStandardPlayerJoustScore&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
CalculateStandardPlayerJoustScore&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCS PlayerXLosesJoustToPlayerY&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDA PlayerWasGladiator&lt;br /&gt;
  BEQ WhichBirdWasHigher&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlayerWasGladiator&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$04&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0E&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA Temp60ScoreAdd&lt;br /&gt;
  JSR CreateScorePopupAtObjectLocation&lt;br /&gt;
  JMP WhichBirdWasHigher&lt;br /&gt;
&lt;br /&gt;
PlayerXLosesJoustToPlayerY&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  TAX&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDA PlayerWasGladiator&lt;br /&gt;
  BEQ PlayerYWinsJoustVsPlayerX&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlayerWasGladiator&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$04&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0E&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  JSR CreateScorePopupAtObjectLocation&lt;br /&gt;
PlayerYWinsJoustVsPlayerX&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
WhichBirdWasHigher&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCS JoustLoserIdentified&lt;br /&gt;
  TYA&lt;br /&gt;
  TAX&lt;br /&gt;
JoustLoserIdentified&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS PlayerKilledEnemyBird&lt;br /&gt;
  JSR StartPlayerDeath&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JMP BirdsHaveBounced&lt;br /&gt;
PlayerKilledEnemyBird&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  JSR ConvertKilledBirdToEgg&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X&lt;br /&gt;
  BNE CheckIfKilledBirdIsHunter&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$50&lt;br /&gt;
  JMP StoreCalculatedScoreValue&lt;br /&gt;
CheckIfKilledBirdIsHunter&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE CalculateShadowLordKillScore&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  JMP StoreCalculatedScoreValue&lt;br /&gt;
SetDefaultKillScore&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  JMP StoreCalculatedScoreValue&lt;br /&gt;
CalculateShadowLordKillScore&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE SetDefaultKillScore&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$50&lt;br /&gt;
StoreCalculatedScoreValue&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JMP BirdsHaveBounced&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; CheckPlayerEggCollision&lt;br /&gt;
; Iterates through all egg objects and checks for collision with a player bird.&lt;br /&gt;
; Handles egg pickup, scoring, and sound effects.&lt;br /&gt;
; Input: X = Player object index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
CheckPlayerEggCollision&lt;br /&gt;
  LDY #$0D&lt;br /&gt;
CheckPlayerEggCollisionLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ SkipThisEggCheck&lt;br /&gt;
  JSR GameObjCollisionDetection  ; carry is clear on collision&lt;br /&gt;
  BCC PlayerPickedUpAnEgg&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BNE CheckAirbornePlayerEggCollision&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$05&lt;br /&gt;
  STA GameObjectYCoordHi,Y&lt;br /&gt;
  JSR GameObjCollisionDetection  ; carry is clear on collision&lt;br /&gt;
  BCC PlayerPickedUpAnEgg&lt;br /&gt;
  LDA Temp63&lt;br /&gt;
  STA GameObjectYCoordHi,Y&lt;br /&gt;
  JMP SkipThisEggCheck&lt;br /&gt;
CheckAirbornePlayerEggCollision&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BNE SkipThisEggCheck&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  STA GameObjectYCoordHi,Y&lt;br /&gt;
  JSR GameObjCollisionDetection  ; carry is clear on collision&lt;br /&gt;
  BCC PlayerPickedUpAnEgg&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$04&lt;br /&gt;
  STA GameObjectXCoordHi,Y&lt;br /&gt;
  JSR GameObjCollisionDetection  ; carry is clear on collision&lt;br /&gt;
  BCC PlayerPickedUpAnEgg&lt;br /&gt;
  LDA Temp63&lt;br /&gt;
  STA GameObjectYCoordHi,Y&lt;br /&gt;
  JSR GameObjCollisionDetection  ; carry is clear on collision&lt;br /&gt;
  BCC PlayerPickedUpAnEgg&lt;br /&gt;
  LDA Temp64&lt;br /&gt;
  STA GameObjectXCoordHi,Y&lt;br /&gt;
SkipThisEggCheck&lt;br /&gt;
  INY&lt;br /&gt;
  CPY #$19&lt;br /&gt;
  BEQ AllEggsChecked&lt;br /&gt;
  JMP CheckPlayerEggCollisionLoop&lt;br /&gt;
AllEggsChecked&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlayerPickedUpAnEgg&lt;br /&gt;
  LDA #SFX_PickupEgg&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BEQ DecrementEnemyCountForHatchingEggPickup&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE HandleEggPickupState&lt;br /&gt;
DecrementEnemyCountForHatchingEggPickup&lt;br /&gt;
  DEC EnemyBirdCount&lt;br /&gt;
HandleEggPickupState&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BNE ClearPickedUpEggState&lt;br /&gt;
  STX Temp65&lt;br /&gt;
  LDX GameObjectHunterIndex,Y&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  LDX Temp65&lt;br /&gt;
ClearPickedUpEggState&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
  DEC EggsPresentCount&lt;br /&gt;
  BNE CalculateEggPickupScore&lt;br /&gt;
  LDA EnemyBirdCount&lt;br /&gt;
  BNE CalculateEggPickupScore&lt;br /&gt;
  JSR SetupNextLevel&lt;br /&gt;
CalculateEggPickupScore&lt;br /&gt;
  LDA GameObjectDirection,Y&lt;br /&gt;
  BEQ CalculateScoreForEggPickup&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$08&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA Temp60ScoreAdd&lt;br /&gt;
  JSR CreateScorePopupAtObjectLocation&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$50&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
CalculateScoreForEggPickup&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA P0EggPointLevel,X&lt;br /&gt;
  STA Temp60ScoreAdd&lt;br /&gt;
  JSR CreateScorePopupAtObjectLocation&lt;br /&gt;
  LDA P0EggPointLevel,X&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA NextEggPointLevelLUT,Y&lt;br /&gt;
  STA P0EggPointLevel,X&lt;br /&gt;
  LDA EggPointLevelScoreHiLUT,Y&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA EggPointLevelScoreLoLUT,Y&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  JMP UpdatePlayerScoreAndBonus&lt;br /&gt;
&lt;br /&gt;
NextEggPointLevelLUT&lt;br /&gt;
 .byte $01,$02,$03,$03&lt;br /&gt;
&lt;br /&gt;
; Consecutive egg pickups score 250,500,750,1000,1000,1000...&lt;br /&gt;
EggPointLevelScoreHiLUT&lt;br /&gt;
 .byte &amp;gt;$0025,&amp;gt;$0050,&amp;gt;$0075,&amp;gt;$0100&lt;br /&gt;
EggPointLevelScoreLoLUT&lt;br /&gt;
 .byte &amp;lt;$0025,&amp;lt;$0050,&amp;lt;$0075,&amp;lt;$0100&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; ProcessBirdPlatformInteraction&lt;br /&gt;
; Handles all physics and state changes for a bird object (index in X)&lt;br /&gt;
; related to its interaction with platforms.&lt;br /&gt;
;&lt;br /&gt;
; This routine has two main paths:&lt;br /&gt;
; 1. On-Platform Logic: If the bird is on a platform (InAir flag is false),&lt;br /&gt;
;    it checks for proximity to edges, handles skidding, and can initiate a fall.&lt;br /&gt;
; 2. Airborne Logic: If the bird is airborne (InAir flag is true), it checks&lt;br /&gt;
;    for collisions with platforms, which can result in landing, bouncing, or&lt;br /&gt;
;    a &amp;quot;skip&amp;quot; across the surface.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ProcessBirdPlatformInteraction&lt;br /&gt;
    LDA GameObjectInAir,X                 ; Is the bird currently airborne?&lt;br /&gt;
    BNE BirdIsAirborne_CheckForCollision  ; If yes, branch to airborne logic path.&lt;br /&gt;
&lt;br /&gt;
; --- On-Platform Logic ---&lt;br /&gt;
    JSR CheckIfBirdNearPlatformEdge                          ; Check for proximity to a platform edge.&lt;br /&gt;
    LDA Temp60                         ; Load the result of the edge check.&lt;br /&gt;
    BNE OnPlatform_EdgeOrSideDetected  ; If non-zero, an edge was detected.&lt;br /&gt;
&lt;br /&gt;
; Bird is on a platform but not near an edge.&lt;br /&gt;
    LDA GameObjectSkidDirection,X              ; Is the bird currently skidding?&lt;br /&gt;
    BEQ BirdNotSkidding1                       ; If not, proceed to check if it should fall.&lt;br /&gt;
    JSR ClearSkidStateAndSound                 ; If it is skidding (but not near an edge), clear the skid state.&lt;br /&gt;
BirdNotSkidding1&lt;br /&gt;
    JMP CheckIfBirdIsUnsupportedAndShouldFall  ; Check if bird is on a valid platform spot, otherwise fall.&lt;br /&gt;
&lt;br /&gt;
OnPlatform_EdgeOrSideDetected&lt;br /&gt;
    JSR SelectCollisionPointsAndCheckPlatform  ; Perform a more detailed platform collision check.&lt;br /&gt;
    CMP #$08                      ; Is the collision type a side impact?&lt;br /&gt;
    BEQ OnPlatform_BounceOffSide  ; If yes, handle bouncing off the side.&lt;br /&gt;
    RTS                           ; Otherwise, no action needed this frame.&lt;br /&gt;
&lt;br /&gt;
OnPlatform_BounceOffSide&lt;br /&gt;
    INC GameObjectXCoordHi,X         ; Nudge the bird slightly away from the platform.&lt;br /&gt;
    LDA #SFX_BirdPlatformBounce      ; Schedule the bounce sound effect.&lt;br /&gt;
    JSR ScheduleSFX&lt;br /&gt;
    LDA GameObjectXVelocity,X        ; Reverse X-velocity.&lt;br /&gt;
    EOR #$FF&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    STA GameObjectXVelocity,X&lt;br /&gt;
    LDA GameObjectDirection,X        ; Reverse facing direction.&lt;br /&gt;
    EOR #$FF&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
    LDA GameObjectSkidDirection,X    ; Reverse skid direction if skidding.&lt;br /&gt;
    EOR #$FF&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    STA GameObjectSkidDirection,X&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
; --- Airborne Logic ---&lt;br /&gt;
BirdIsAirborne_CheckForCollision&lt;br /&gt;
   JSR SelectCollisionPointsAndCheckPlatform   ; Check for collision with any platform.&lt;br /&gt;
    BEQ Airborne_NoCollision_ClearSkipState    ; If no collision, clear skip state and continue.&lt;br /&gt;
    BMI Airborne_HandleLanding                 ; If result is negative, it's a landing on top of a platform.&lt;br /&gt;
    CMP #$01&lt;br /&gt;
    BEQ Airborne_CheckForPlatformSkip          ; A result of 1 or 8 indicates a shallow landing or side hit.&lt;br /&gt;
    CMP #$08&lt;br /&gt;
    BEQ Airborne_CheckForPlatformSkip&lt;br /&gt;
    JMP CheckIfBirdIsUnsupportedAndShouldFall  ; For other collision types, check if it should fall.&lt;br /&gt;
&lt;br /&gt;
Airborne_HandleLanding&lt;br /&gt;
    LDA GameObjectPlatformSkipState,X          ; Is the bird in a &amp;quot;skip&amp;quot; state from a previous frame?&lt;br /&gt;
    BNE CheckIfBirdIsUnsupportedAndShouldFall  ; If yes, don't land yet, let it fall/continue skipping.&lt;br /&gt;
    LDA #$02                                   ; Set animation frame to standing/walking.&lt;br /&gt;
    STA GameObjectAnimationFrame,X&lt;br /&gt;
    LDA #$00                                   ; Bird is no longer in the air.&lt;br /&gt;
    STA GameObjectInAir,X&lt;br /&gt;
    STA GameObjectYVelocityHi,X                ; Zero out Y-velocity.&lt;br /&gt;
    STA GameObjectYVelocityLo,X&lt;br /&gt;
    LDA GameObjectXVelocity,X                  ; Check X-velocity to set facing direction.&lt;br /&gt;
    BEQ Airborne_Landing_Finalize              ; If stopped, branch to the JMP trampoline.&lt;br /&gt;
    BMI Airborne_Landing_FaceLeft&lt;br /&gt;
    LDA #Direction_Right                       ; Moving right, so face right.&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
    JMP Airborne_Landing_Finalize              ; Jump to the JMP trampoline.&lt;br /&gt;
Airborne_Landing_FaceLeft&lt;br /&gt;
    LDA #Direction_Left                        ; Moving left, so face left.&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
                                               ; Fall through to the JMP trampoline.&lt;br /&gt;
Airborne_Landing_Finalize&lt;br /&gt;
    JMP UpdateCoordsFromTempAndExit_B          ; This JMP acts as a trampoline for the short branches above.&lt;br /&gt;
&lt;br /&gt;
Airborne_CheckForPlatformSkip&lt;br /&gt;
    JSR CheckForShallowPlatformCollision       ; Another check, possibly to confirm the nature of the shallow landing.&lt;br /&gt;
    BNE Airborne_ProcessBounce                 ; If it's a bounce, process it.&lt;br /&gt;
    LDA GameObjectYCoordHi,X                   ; Check bird's Y coordinate.&lt;br /&gt;
    CMP #$92                                   ; Is it above a certain height?&lt;br /&gt;
    BCS CheckIfBirdIsUnsupportedAndShouldFall  ; If too low, treat as a fall.&lt;br /&gt;
    LDA #$01                                   ; Otherwise, initiate a &amp;quot;skip&amp;quot; across the platform surface.&lt;br /&gt;
    STA GameObjectPlatformSkipState,X&lt;br /&gt;
    BPL CheckIfBirdIsUnsupportedAndShouldFall  ; Always branches.&lt;br /&gt;
&lt;br /&gt;
Airborne_NoCollision_ClearSkipState&lt;br /&gt;
    LDA #$00                                   ; No collision, so clear any platform skip state.&lt;br /&gt;
    STA GameObjectPlatformSkipState,X&lt;br /&gt;
&lt;br /&gt;
CheckIfBirdIsUnsupportedAndShouldFall&lt;br /&gt;
    LDA #$01                                   ; Set InAir flag to TRUE, making the bird subject to gravity.&lt;br /&gt;
    STA GameObjectInAir,X&lt;br /&gt;
    LDA GameObjectYCoordHi,X&lt;br /&gt;
    CMP #TOP_SCREEN_Y_BOUNDARY                 ; Has the bird hit the top of the screen?&lt;br /&gt;
    BCC Airborne_BounceOffTopScreen            ; If Y &amp;lt; boundary, it has.&lt;br /&gt;
    JSR CheckForShallowPlatformCollision       ; Check for platform support again.&lt;br /&gt;
    BNE Airborne_ProcessBounce                 ; If a bounce condition is met, process it.&lt;br /&gt;
    JMP Exit_ProcessBirdPlatformInteraction    ; Otherwise, bird is airborne and falling, exit.&lt;br /&gt;
&lt;br /&gt;
Airborne_BounceOffTopScreen&lt;br /&gt;
    LDA GameObjectYVelocityHi,X                ; Get Y-velocity.&lt;br /&gt;
    BMI Airborne_ReverseYVelocityForBounce     ; If moving up (negative), reverse it for a bounce.&lt;br /&gt;
    RTS                                        ; If moving down, just let it fall away from the top.&lt;br /&gt;
&lt;br /&gt;
Airborne_ReverseYVelocityForBounce&lt;br /&gt;
    EOR #$FF                            ; Reverse Y-velocity to bounce down.&lt;br /&gt;
    STA GameObjectYVelocityHi,X&lt;br /&gt;
    LDA GameObjectYVelocityLo,X&lt;br /&gt;
    EOR #$FF&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    STA GameObjectYVelocityLo,X&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
Airborne_ProcessBounce&lt;br /&gt;
    TAY                                 ; A holds collision type, save in Y.&lt;br /&gt;
    BPL Airborne_Bounce_PositiveResult  ; Handle different bounce types based on sign.&lt;br /&gt;
                                        ; Negative result: Bounce off the bottom of a platform.&lt;br /&gt;
    LDA #SFX_BirdPlatformBounce&lt;br /&gt;
    JSR ScheduleSFX&lt;br /&gt;
    LDA #$80                            ; Set Y-velocity to a strong upward value.&lt;br /&gt;
    STA GameObjectYVelocityLo,X&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA GameObjectYVelocityHi,X&lt;br /&gt;
    JMP UpdateCoordsFromTempAndExit_B&lt;br /&gt;
&lt;br /&gt;
Airborne_Bounce_PositiveResult&lt;br /&gt;
    LDA #SFX_BirdPlatformBounce&lt;br /&gt;
    JSR ScheduleSFX&lt;br /&gt;
    TYA                                  ; Restore collision type from Y.&lt;br /&gt;
    LSR&lt;br /&gt;
    BCS Airborne_Bounce_SideImpactRight  ; Bit 0 set -&amp;gt; hit right side of platform&lt;br /&gt;
    LSR&lt;br /&gt;
    BCS Airborne_Bounce_GlancingBlow     ; Bit 1 set -&amp;gt; glancing blow, small bounce&lt;br /&gt;
    LSR&lt;br /&gt;
    BCS Airborne_Bounce_GlancingBlow     ; Bit 2 set -&amp;gt; also a glancing blow&lt;br /&gt;
                                         ; Fall-through for other bounce types&lt;br /&gt;
    LDA GameObjectXVelocity,X&lt;br /&gt;
    BPL UpdateCoordsFromTempAndExit_B    ; If moving right, no X-velocity change.&lt;br /&gt;
    EOR #$FF                             ; If moving left, dampen X-velocity (divide by 2).&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    ROR&lt;br /&gt;
    JMP Airborne_Bounce_StoreNewXVel&lt;br /&gt;
&lt;br /&gt;
Airborne_Bounce_SideImpactRight&lt;br /&gt;
    LDA GameObjectXVelocity,X&lt;br /&gt;
    BEQ UpdateCoordsFromTempAndExit_B   ; If stopped, no change.&lt;br /&gt;
    BMI UpdateCoordsFromTempAndExit_B   ; If moving left (away from impact), no change.&lt;br /&gt;
    EOR #$FF                            ; Moving right into platform, reverse and dampen velocity.&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$01&lt;br /&gt;
    SEC&lt;br /&gt;
    ROR&lt;br /&gt;
Airborne_Bounce_StoreNewXVel&lt;br /&gt;
    STA GameObjectXVelocity,X&lt;br /&gt;
    LDA GameObjectState,X&lt;br /&gt;
    CMP #State_Hit                                            ; Is the bird in the &amp;quot;hit&amp;quot; state?&lt;br /&gt;
    BNE UpdateCoordsFromTempAndExit_A                         ; If not, just update coords.&lt;br /&gt;
    LDY ObjectBirdLevelAndType,X                              ; If it is, reset its AI timer to make it&lt;br /&gt;
    LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y  ; react more quickly after the bounce.&lt;br /&gt;
    STA GameObjectTimerResetValue,X&lt;br /&gt;
    STA GameObjectEventTimer1,X&lt;br /&gt;
UpdateCoordsFromTempAndExit_A&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
Airborne_Bounce_GlancingBlow&lt;br /&gt;
    LDA #$50                         ; Set Y-velocity to a moderate upward value.&lt;br /&gt;
    STA GameObjectYVelocityLo,X&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA GameObjectYVelocityHi,X&lt;br /&gt;
&lt;br /&gt;
UpdateCoordsFromTempAndExit_B&lt;br /&gt;
    LDA Temp65                       ; Load new X coordinate calculated by collision routine.&lt;br /&gt;
    STA GameObjectXCoordHi,X&lt;br /&gt;
    LDA Temp66                       ; Load new Y coordinate.&lt;br /&gt;
    STA GameObjectYCoordHi,X&lt;br /&gt;
&lt;br /&gt;
Exit_ProcessBirdPlatformInteraction&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdateEggPhysicsAndPlatformInteraction&lt;br /&gt;
; Handles physics and platform interaction specifically for an egg object.&lt;br /&gt;
; Input: X = Egg object index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdateEggPhysicsAndPlatformInteraction&lt;br /&gt;
  JSR SelectEggCollisionPointAndCheck&lt;br /&gt;
  BEQ EggNoPlatformCollision&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  BMI HandlePlatformTopCollisionEgg&lt;br /&gt;
  LSR&lt;br /&gt;
  BCS EggBounceOffRightSideOfPlatform&lt;br /&gt;
  LSR&lt;br /&gt;
  BCS NegateEggYVelocityOnBounce&lt;br /&gt;
  LSR&lt;br /&gt;
  BCS NegateEggYVelocityOnBounce&lt;br /&gt;
  LSR&lt;br /&gt;
  BCS EggAirborne_BounceOffSideOfPlatform&lt;br /&gt;
EggNoPlatformCollision&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
EggAirborne_BounceOffSideOfPlatform&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BMI ReverseEggXVelocityOnBounce&lt;br /&gt;
  JMP UpdateEggCoordsAfterCollision&lt;br /&gt;
ReverseEggXVelocityOnBounce&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  JMP UpdateEggCoordsAfterCollision&lt;br /&gt;
EggBounceOffRightSideOfPlatform&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BPL ReverseEggXVelocityOnBounce&lt;br /&gt;
  JMP UpdateEggCoordsAfterCollision&lt;br /&gt;
NegateEggYVelocityOnBounce&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  BPL EggBounceYVelocityAlreadyDownward&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  SBC GameObjectYVelocityLo,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  SBC GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
EggBounceYVelocityAlreadyDownward&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
DecelerateBouncingEggXVelocity&lt;br /&gt;
  BMI DecelerateBouncingEggLeft&lt;br /&gt;
  DEC GameObjectXVelocity,X&lt;br /&gt;
  JMP UpdateEggCoordsAfterCollision&lt;br /&gt;
DecelerateBouncingEggLeft&lt;br /&gt;
  INC GameObjectXVelocity,X&lt;br /&gt;
  JMP UpdateEggCoordsAfterCollision&lt;br /&gt;
HandlePlatformTopCollisionEgg&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  BNE EggIsMovingBounce&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BNE EggIsMovingBounce&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  CMP #$28&lt;br /&gt;
  BCC EggLandedOnPlatform&lt;br /&gt;
EggIsMovingBounce&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  SBC GameObjectYVelocityLo,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  SBC GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  ROL&lt;br /&gt;
  ROR GameObjectYVelocityHi,X&lt;br /&gt;
  ROR GameObjectYVelocityLo,X&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BNE DecelerateBouncingEggXVelocity&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
EggLandedOnPlatform&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  STA ObjectWiggleAnimation,X&lt;br /&gt;
  STA GameObjectInAir,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  JSR CalculateLevelDifficultyRandomTimer&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA GameObjectCountdownHi,X&lt;br /&gt;
UpdateEggCoordsAfterCollision&lt;br /&gt;
  LDA Temp65&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  LDA Temp66&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SpawnPointSafetyCheck&lt;br /&gt;
; Checks if a spawn point is safe for a new bird to appear. It iterates through&lt;br /&gt;
; all other birds to see if any are too close to the target spawn point.&lt;br /&gt;
; Input: X = index of bird to be spawned.&lt;br /&gt;
; Output: Temp60 = 0 if safe, non-zero if unsafe.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SpawnPointSafetyCheck&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA                      ; save X&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCC SafetyCheckForPlayer&lt;br /&gt;
SafetyCheckForEnemy&lt;br /&gt;
  LDX #$03&lt;br /&gt;
  JMP SafetyCheckLoop&lt;br /&gt;
SafetyCheckForPlayer&lt;br /&gt;
  LDX #$00&lt;br /&gt;
SafetyCheckLoop&lt;br /&gt;
  LDA SpawnPlatformDissolved0,X&lt;br /&gt;
  BEQ HandleSpawnOnDissolvedPlatform&lt;br /&gt;
  LDY #$09&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA TempSpawnUnsafeCounter,X&lt;br /&gt;
CheckProximityToOtherObjectsLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ SpawnSafetyCheckDoNextObject&lt;br /&gt;
  CMP #$05&lt;br /&gt;
  BEQ SpawnSafetyCheckDoNextObject&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BEQ SpawnSafetyCheckDoNextObject&lt;br /&gt;
  CMP #$07&lt;br /&gt;
  BEQ SpawnSafetyCheckDoNextObject&lt;br /&gt;
  CMP #$06&lt;br /&gt;
  BNE ObjectStateIsValidForProximityCheck&lt;br /&gt;
  LDA GameObjectSpawnPlatformIndex,Y&lt;br /&gt;
  STX Temp5F&lt;br /&gt;
  CMP Temp5F&lt;br /&gt;
  BNE ObjectStateIsValidForProximityCheck&lt;br /&gt;
HandleSpawnOnDissolvedPlatform&lt;br /&gt;
  INC TempSpawnUnsafeCounter,X&lt;br /&gt;
  JMP MarkSpawnPointUnsafeAndContinueCheck&lt;br /&gt;
ObjectStateIsValidForProximityCheck&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC PlayerRespawnY,X&lt;br /&gt;
  BPL CompareAbsoluteYDistanceToMinimum&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CompareAbsoluteYDistanceToMinimum&lt;br /&gt;
  CMP #$1E&lt;br /&gt;
  BCS SpawnSafetyCheckDoNextObject&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC PlayerRespawnX,X&lt;br /&gt;
  BPL CompareAbsoluteXDistanceToMinimum&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CompareAbsoluteXDistanceToMinimum&lt;br /&gt;
  CMP #$28&lt;br /&gt;
  BCS SpawnSafetyCheckDoNextObject&lt;br /&gt;
  JMP MarkSpawnPointUnsafeAndContinueCheck&lt;br /&gt;
SpawnSafetyCheckDoNextObject&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL CheckProximityToOtherObjectsLoop&lt;br /&gt;
  STX Temp60&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
MarkSpawnPointUnsafeAndContinueCheck&lt;br /&gt;
  PLA&lt;br /&gt;
  PHA&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BCS SafetyCheckLoop_Player&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$04&lt;br /&gt;
  BCC SafetyCheckLoop&lt;br /&gt;
  JMP MarkSpawnPointUnsafeAndExit&lt;br /&gt;
SafetyCheckLoop_Player&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SafetyCheckLoop&lt;br /&gt;
MarkSpawnPointUnsafeAndExit&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetupEggWave&lt;br /&gt;
; Initializes all egg objects for an Egg Wave. It randomly places eggs on&lt;br /&gt;
; available platforms, ensuring they are not too clustered.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetupEggWave&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA EnemyBirdCount&lt;br /&gt;
  LDA #$07&lt;br /&gt;
  TAX&lt;br /&gt;
  LDY #$0C&lt;br /&gt;
  STY EggsPresentCount&lt;br /&gt;
  DEY&lt;br /&gt;
; this is the start of the random egg placement code.&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
GetNewEggPosition&lt;br /&gt;
  STX Temp64&lt;br /&gt;
  CMP NewEggXMaximum,X&lt;br /&gt;
  BCC EggXRangeFitsPlatform&lt;br /&gt;
GetNewEggPositionLoop&lt;br /&gt;
  LDX Temp64&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL GetNewEggPosition&lt;br /&gt;
  LDX #$07&lt;br /&gt;
  JMP GetNewEggPosition&lt;br /&gt;
EggXRangeFitsPlatform&lt;br /&gt;
  CLC                            ; The width of the random X range used fits&lt;br /&gt;
  ADC NewEggXOffset,X            ; the platform width, so we just need to add&lt;br /&gt;
  STA EggX,Y                     ; to EggX to reach the X of the platform.&lt;br /&gt;
  LDA NewEggYCoordinate,X&lt;br /&gt;
  STA EggY,Y&lt;br /&gt;
  CPY #$0B                       ; first egg? if so then skip&lt;br /&gt;
  BEQ EggLocationValidationDone  ; egg position validation&lt;br /&gt;
&lt;br /&gt;
EggLocationValidation&lt;br /&gt;
; We first ensure that no more than 5 eggs already exist on the same&lt;br /&gt;
; platform. Otherwise we fetch new egg coordinates.&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDX #$0B&lt;br /&gt;
  LDA EggY,Y&lt;br /&gt;
EggYCountCheckLoop&lt;br /&gt;
  CMP EggY,X&lt;br /&gt;
  BNE EggNotAtSameY1&lt;br /&gt;
  DEC Temp65&lt;br /&gt;
  BEQ GetNewEggPositionLoop&lt;br /&gt;
EggNotAtSameY1&lt;br /&gt;
  DEX&lt;br /&gt;
  STX Temp66&lt;br /&gt;
  CPY Temp66             ; only check eggs up until the current one&lt;br /&gt;
  BNE EggYCountCheckLoop&lt;br /&gt;
&lt;br /&gt;
; Now we ensure that our egg is at least 5 pixels away from any other&lt;br /&gt;
; eggs on the same platform. Otherwise we fetch new egg coordinates.&lt;br /&gt;
  LDX #$0B&lt;br /&gt;
EggDistanceCheckLoop&lt;br /&gt;
  LDA EggY,Y&lt;br /&gt;
  CMP EggY,X&lt;br /&gt;
  BNE EggNotAtSameY2&lt;br /&gt;
  LDA EggX,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC EggX,X                ; Distance is OurEggX - ThisEggX&lt;br /&gt;
  BPL SkipDistanceInversion&lt;br /&gt;
; if we have a negative distance, we need to invert it (A=255-A)&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
SkipDistanceInversion&lt;br /&gt;
  CMP #$05&lt;br /&gt;
  BCC GetNewEggPositionLoop&lt;br /&gt;
EggNotAtSameY2&lt;br /&gt;
  DEX&lt;br /&gt;
  STX Temp66&lt;br /&gt;
  CPY Temp66&lt;br /&gt;
  BNE EggDistanceCheckLoop&lt;br /&gt;
&lt;br /&gt;
EggLocationValidationDone&lt;br /&gt;
  LDA EggWaveEnemyType&lt;br /&gt;
  STA EggLevelAndType,Y&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA.w EggState,Y&lt;br /&gt;
  JSR CalculateLevelDifficultyRandomTimer&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA $232E,Y&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA $2315,Y&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA $2347,Y&lt;br /&gt;
  STA $221B,Y&lt;br /&gt;
  STA $227F,Y&lt;br /&gt;
  STA $22CA,Y&lt;br /&gt;
  STA $22FC,Y&lt;br /&gt;
  STA $2298,Y&lt;br /&gt;
  STA $22B1,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BMI ExitEggWaveSetup&lt;br /&gt;
  JMP GetNewEggPositionLoop&lt;br /&gt;
ExitEggWaveSetup&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; CalculateLevelDifficultyRandomTimer&lt;br /&gt;
; Calculates a 16-bit random timer value influenced by game level and difficulty.&lt;br /&gt;
; Used for Pterodactyl appearance delays and egg hatching countdowns.&lt;br /&gt;
; The final timer is primarily based on a random value plus difficulty-scaled&lt;br /&gt;
; additions, with an initial offset to the high byte determined by the level.&lt;br /&gt;
; Outputs: Temp5E (Lo), Temp5F (Hi)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
CalculateLevelDifficultyRandomTimer&lt;br /&gt;
  TXA  ; Preserve X register&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA  ; Preserve Y register&lt;br /&gt;
  PHA&lt;br /&gt;
&lt;br /&gt;
  LDA #InitialTimerHiByteValue  ; Initialize high byte of timer&lt;br /&gt;
  STA Temp5F                    ; Temp5F will act as the high byte accumulator&lt;br /&gt;
&lt;br /&gt;
; Calculate loop counter for difficulty-based additions.&lt;br /&gt;
; Loop runs (DifficultyLoopCounterBase - Difficulty + 1) times.&lt;br /&gt;
  LDA #DifficultyLoopCounterBase&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Difficulty  ; A = DifficultyLoopCounterBase - Difficulty&lt;br /&gt;
  TAX             ; X will be the loop counter (0 to 3)&lt;br /&gt;
&lt;br /&gt;
; Calculate an 8-bit term based on the current level.&lt;br /&gt;
  LDA #TimerLevelCalcBaseValue&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Level  ; A = TimerLevelCalcBaseValue - Level&lt;br /&gt;
&lt;br /&gt;
; Multiply this level-based term by 8 (ASL A three times).&lt;br /&gt;
; The carry from the third ASL (representing bit 8 of an 9-bit result)&lt;br /&gt;
; is added to Temp5F (timer high byte). The 8 LSBs in A are then discarded.&lt;br /&gt;
  ASL                                    ; A = A * 2&lt;br /&gt;
  ASL                                    ; A = A * 4&lt;br /&gt;
  ASL                                    ; A = A * 8. Carry C holds the 9th bit.&lt;br /&gt;
  BCC CalculateTimer_LevelComponentDone  ; If C=0, no carry into 9th bit.&lt;br /&gt;
  INC Temp5F                             ; C=1, (LevelTerm*8) overflowed 8 bits. Add to TimerHi.&lt;br /&gt;
&lt;br /&gt;
CalculateTimer_LevelComponentDone&lt;br /&gt;
&lt;br /&gt;
; A currently holds (TimerLevelCalcBaseValue - Level)*8 AND $FF. This value is about to be overwritten.&lt;br /&gt;
; Temp5F holds 0 or 1 based on the carry from the above calculation.&lt;br /&gt;
&lt;br /&gt;
  JSR ReturnRandInA                  ; A = RandomByte&lt;br /&gt;
                                     ; The subsequent ADC loop will start with this random byte as the LSB,&lt;br /&gt;
                                     ; and Temp5F as the initial MSB.&lt;br /&gt;
CalculateTimer_DifficultyLoop        ; Loop (X+1) times, adding to the (Temp5F,A) 16-bit value.&lt;br /&gt;
  ADC #RandomTimerLoopAddend         ; A = A + RandomTimerLoopAddend + CarryFromPreviousADC (initially 0 for first ADC)&lt;br /&gt;
  BCC CalculateTimer_EndLoopIter     ; If no carry from ADC to high byte&lt;br /&gt;
  INC Temp5F                         ; Add carry to high byte of timer&lt;br /&gt;
CalculateTimer_EndLoopIter&lt;br /&gt;
  DEX                                ; Decrement difficulty-based loop counter&lt;br /&gt;
  BPL CalculateTimer_DifficultyLoop  ; Loop if X &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
  STA Temp5E                         ; Store final low byte of timer in Temp5E&lt;br /&gt;
&lt;br /&gt;
  PLA                                ; Restore Y register&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA                                ; Restore X register&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; RunPterryCountdown&lt;br /&gt;
; Main logic for managing the Pterodactyl appearance timer and spawning.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
RunPterryCountdown&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  BEQ RunPterryCountdownExit&lt;br /&gt;
  LDA PterryAliveCount&lt;br /&gt;
  CMP #$03  ; 3 Pterrys max&lt;br /&gt;
  BEQ RunPterryCountdownExit&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA PterryCountdownLo&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  STA PterryCountdownLo&lt;br /&gt;
  LDA PterryCountdownHi&lt;br /&gt;
  BMI CheckForLiveEnemyBirds&lt;br /&gt;
  SBC #$00&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  BMI CheckForLiveEnemyBirds&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DelayPterry&lt;br /&gt;
  INC PterryCountdownLo&lt;br /&gt;
RunPterryCountdownExit&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CheckForLiveEnemyBirds&lt;br /&gt;
  LDX #$09         ; last bird object&lt;br /&gt;
CheckForLiveEnemyBirdsLoop&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$07         ; if a bird is being born2...&lt;br /&gt;
  BEQ DelayPterry  ; ...delay spawning a pterry.&lt;br /&gt;
  CMP #$06         ; if a bird is transporting-in...&lt;br /&gt;
  BEQ DelayPterry  ; ...delay spawning a pterry.&lt;br /&gt;
  CMP #$03         ; if a bird is being born1...&lt;br /&gt;
  BEQ DelayPterry  ; ...delay spawning a pterry.&lt;br /&gt;
  DEX              ; Check another Enemy bird object so long&lt;br /&gt;
  CPX #$02         ; as we haven't reached the player birds.&lt;br /&gt;
  BCS CheckForLiveEnemyBirdsLoop&lt;br /&gt;
&lt;br /&gt;
  LDA #SFX_PterryCharging&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  INC PterryAliveCount&lt;br /&gt;
  LDX #$0A&lt;br /&gt;
FindDeadPterryLoop&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  BEQ InitializeNewPterryObject&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$0D&lt;br /&gt;
  BCC FindDeadPterryLoop&lt;br /&gt;
PterrySpawnFailCrashLoop&lt;br /&gt;
  BCS PterrySpawnFailCrashLoop  ; crash loop, but shouldn't ever trigger&lt;br /&gt;
InitializeNewPterryObject&lt;br /&gt;
  LDA #$0A                      ; Normal Pterry state&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA GameObjectAnimationCounter,X&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
  LDA #$FA&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA GameObjectAITimerLo,X&lt;br /&gt;
  JSR SetPterryInitialSpawnParameters&lt;br /&gt;
  CPX #$0A&lt;br /&gt;
  BNE UpdatePterryRespawnTimerAndExit&lt;br /&gt;
  LDA PterryAgressionFlag&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE UpdatePterryRespawnTimerAndExit&lt;br /&gt;
  LDA PterryAgressionFlag+1&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BEQ ResetPterryCountdownForced&lt;br /&gt;
UpdatePterryRespawnTimerAndExit&lt;br /&gt;
  JSR UpdatePterryRespawnTimer&lt;br /&gt;
  LSR PterryCountdownHi  ; divide the pterry&lt;br /&gt;
  ROR PterryCountdownLo  ; countdown by two&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ResetPterryCountdownForced&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  LDA #$14&lt;br /&gt;
  STA PterryCountdownLo&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; Look-up table for initial Y coordinates for Pterodactyl spawn.&lt;br /&gt;
; Indexed by (RandomByte AND PTERRY_SPAWN_Y_COORD_MASK).&lt;br /&gt;
PterrySpawnYCoordLUT&lt;br /&gt;
 .byte $94, $52, $52, $15&lt;br /&gt;
&lt;br /&gt;
; Look-up table for initial X coordinates for Pterodactyl spawn.&lt;br /&gt;
; Indexed by (RandomByte AND PTERRY_SPAWN_XDIRVEL_MASK).&lt;br /&gt;
PterrySpawnXCoordLUT&lt;br /&gt;
 .byte $15, $BA&lt;br /&gt;
&lt;br /&gt;
; Look-up table for initial facing direction for Pterodactyl spawn.&lt;br /&gt;
; $01 = Right, $FF = Left.&lt;br /&gt;
; Indexed by (RandomByte AND PTERRY_SPAWN_XDIRVEL_MASK).&lt;br /&gt;
PterrySpawnDirectionLUT&lt;br /&gt;
 .byte Direction_Right, Direction_Left&lt;br /&gt;
&lt;br /&gt;
; Look-up table for initial X velocities for Pterodactyl spawn.&lt;br /&gt;
PterrySpawnXVelocityLUT&lt;br /&gt;
 .byte $05, $FB&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetPterryInitialSpawnParameters&lt;br /&gt;
; Sets the initial spawn parameters for a new Pterodactyl and ensures it does&lt;br /&gt;
; not spawn too close to a player. Re-randomizes if it's too close.&lt;br /&gt;
; Input: X = Pterodactyl object index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetPterryInitialSpawnParameters&lt;br /&gt;
TryNewPterrySpawnParameters&lt;br /&gt;
  JSR ReturnRandInA               ; Get a random byte in A&lt;br /&gt;
  AND #PTERRY_SPAWN_Y_COORD_MASK  ; Mask to get index 0-3 for Y LUT&lt;br /&gt;
  TAY                             ; Y = random index for Y coordinate&lt;br /&gt;
  LDA PterrySpawnYCoordLUT,Y      ; Load Y coordinate&lt;br /&gt;
  STA GameObjectYCoordHi,X        ; Set Pterry's initial Y&lt;br /&gt;
&lt;br /&gt;
  JSR ReturnRandInA               ; Get another random byte&lt;br /&gt;
  AND #PTERRY_SPAWN_XDIRVEL_MASK  ; Mask to get index 0-1 for X/Dir/XVel LUTs&lt;br /&gt;
  TAY                             ; Y = random index for X, Direction, X-Velocity&lt;br /&gt;
  LDA PterrySpawnXCoordLUT,Y      ; Load X coordinate&lt;br /&gt;
  STA GameObjectXCoordHi,X        ; Set Pterry's initial X&lt;br /&gt;
  LDA PterrySpawnDirectionLUT,Y   ; Load direction&lt;br /&gt;
  STA GameObjectDirection,X       ; Set Pterry's initial direction&lt;br /&gt;
  LDA PterrySpawnXVelocityLUT,Y   ; Load X-velocity&lt;br /&gt;
  STA GameObjectXVelocity,X       ; Set Pterry's initial X-velocity&lt;br /&gt;
&lt;br /&gt;
  LDY PlayerCount                           ; Y = number of players (0 for 1P, 1 for 2P; used as player object index)&lt;br /&gt;
                                            ; Player 0 is index 0, Player 1 is index 1.&lt;br /&gt;
CheckPterrySpawnProximityToPlayerLoop&lt;br /&gt;
; Calculate absolute X distance to current player Y&lt;br /&gt;
  LDA GameObjectXCoordHi,X                  ; Pterry's X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GameObjectXCoordHi,Y                  ; Pterry's X - Player Y's X&lt;br /&gt;
  BMI PterryXDistIsNegativeOrZero           ; If result is negative (PlayerX &amp;gt; PterryX)&lt;br /&gt;
  EOR #$FF                                  ; Make positive (abs value part 1)&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                                  ; Make positive (abs value part 2)&lt;br /&gt;
PterryXDistIsNegativeOrZero&lt;br /&gt;
  CMP #PTERRY_MIN_SPAWN_DIST_X              ; Compare |PterryX - PlayerX| with $30&lt;br /&gt;
  BCS PterrySpawnIsFarEnoughFromThisPlayer  ; If dist &amp;gt;= $30, X is okay for this player.&lt;br /&gt;
&lt;br /&gt;
                                            ; X distance &amp;lt; PTERRY_MIN_SPAWN_DIST_X, now check Y distance&lt;br /&gt;
  LDA GameObjectYCoordHi,X                  ; Pterry's Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GameObjectYCoordHi,Y                  ; Pterry's Y - Player Y's Y&lt;br /&gt;
  BMI PterryYDistIsNegativeOrZero           ; If result is negative (PlayerY &amp;gt; PterryY)&lt;br /&gt;
  EOR #$FF                                  ; Make positive (abs value part 1)&lt;br /&gt;
PterryYDistIsNegativeOrZero                 ; Note: CLC ADC #$01 for abs value missing if BMI not taken.&lt;br /&gt;
                                            ; However, since we only care about CMP &amp;lt; $20, a large positive&lt;br /&gt;
                                            ; (if PterryY &amp;gt; PlayerY) will correctly fail the BCC.&lt;br /&gt;
                                            ; If PterryY &amp;lt; PlayerY, BMI is taken, and it becomes positive small.&lt;br /&gt;
  CMP #PTERRY_MIN_SPAWN_DIST_Y              ; Compare |PterryY - PlayerY| with $20&lt;br /&gt;
  BCC SetPterryInitialSpawnParameters       ; If dist &amp;lt; $20, Pterry is too close. Re-randomize.&lt;br /&gt;
&lt;br /&gt;
PterrySpawnIsFarEnoughFromThisPlayer&lt;br /&gt;
  DEY                                       ; Next player index (from PlayerCount down to -1)&lt;br /&gt;
  BPL CheckPterrySpawnProximityToPlayerLoop ; If Y &amp;gt;= 0, check next player.&lt;br /&gt;
&lt;br /&gt;
  RTS                                       ; Pterry spawn position is okay for all players.&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; RunPterryProcessing&lt;br /&gt;
; Main routine to update the state and behavior of a Pterodactyl object.&lt;br /&gt;
; This is a state machine handling its movement, AI, and collision.&lt;br /&gt;
; Input: X = Pterodactyl object index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
RunPterryProcessing&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  BNE PterryIsAliveAndNotDeadState&lt;br /&gt;
  JMP ExitPterryProcessing_NoAction   ; If state is 0 (dead), do nothing&lt;br /&gt;
&lt;br /&gt;
PterryIsAliveAndNotDeadState&lt;br /&gt;
  CMP #PterryState_DefeatedVisual     ; Is Pterry in its &amp;quot;defeated&amp;quot; visual effect state ($0D)?&lt;br /&gt;
  BNE PterryNotInDefeatedVisualState  ; If not, proceed to normal state processing&lt;br /&gt;
&lt;br /&gt;
; Pterry is in &amp;quot;defeated&amp;quot; visual state (e.g., spinning off screen)&lt;br /&gt;
  DEC GameObjectXCoordLo,X                    ; Update sub-pixel X for visual effect&lt;br /&gt;
  BEQ PterryDefeatedVisual_UpdateY_And_Frame  ; If XCoordLo wrapped, update Y and frame&lt;br /&gt;
  RTS                                         ; Otherwise, visual effect continues&lt;br /&gt;
&lt;br /&gt;
PterryDefeatedVisual_UpdateY_And_Frame&lt;br /&gt;
  INC GameObjectAnimationFrame,X           ; Advance animation frame for defeat visual&lt;br /&gt;
  DEC GameObjectYCoordLo,X                 ; Update sub-pixel Y for visual effect&lt;br /&gt;
  BEQ PterryDefeatedVisual_FullyOffscreen  ; If YCoordLo wrapped, Pterry is gone&lt;br /&gt;
  LDA #$0A                                 ; Reset XCoordLo for next part of visual effect&lt;br /&gt;
  STA GameObjectXCoordLo,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PterryDefeatedVisual_FullyOffscreen&lt;br /&gt;
  LDA #State_Dead                       ; Pterry is now fully dead and off-screen&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  DEC PterryAliveCount                  ; Decrement count of active Pterodactyls&lt;br /&gt;
  LDA #$01                              ; Flag related to Pterry state or scoring?&lt;br /&gt;
  STA PterryDefeatedFlag,X              ; Store this flag (unknown purpose, maybe related to next Pterry spawn timing)&lt;br /&gt;
  LDA GameObjectYCoordHi,X              ; Store Pterry's last Y position&lt;br /&gt;
  STA TempPterryCoordY&lt;br /&gt;
  LDA GameObjectXCoordHi,X              ; Store Pterry's last X position&lt;br /&gt;
  STA TempPterryCoordX&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA TempPterryScoreValue&lt;br /&gt;
  JMP CreateScorePopupAtObjectLocation  ; Create a score popup&lt;br /&gt;
&lt;br /&gt;
PterryNotInDefeatedVisualState&lt;br /&gt;
  JSR CheckPterryPlatformCollision  ; Returns collision type in A, Temp65/Temp66 updated with new coords if bounced&lt;br /&gt;
  BEQ PterryNoPlatformCollision     ; If A is 0, no collision or standard fall-through&lt;br /&gt;
  BMI PterryHitPlatform_MoveUp      ; If A is negative, hit bottom of platform, bounce up&lt;br /&gt;
&lt;br /&gt;
; Pterry hit side or top of platform (A is positive)&lt;br /&gt;
  CLC&lt;br /&gt;
  LSR                                           ; A = A / 2 (collision type to direction/action bits)&lt;br /&gt;
  BCS PterryHitPlatform_FaceLeftAndReverseXVel  ; Bit 0 set: hit right side&lt;br /&gt;
  LSR                                           ; A = A / 2&lt;br /&gt;
  BCS PterryHitPlatform_MoveDownSlightly        ; Bit 1 set: hit top, shallow bounce&lt;br /&gt;
  LSR                                           ; A = A / 2&lt;br /&gt;
  BCS PterryHitPlatform_MoveDownSlightly        ; Bit 2 set: hit top, shallow bounce (alternative condition)&lt;br /&gt;
  LSR                                           ; A = A / 2&lt;br /&gt;
  BCC PterryNoPlatformCollision                 ; Bit 3 clear: no significant horizontal reaction needed&lt;br /&gt;
&lt;br /&gt;
                             ; Bit 3 set: hit left side&lt;br /&gt;
  LDA #Direction_Right       ; Change direction to right&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA GameObjectXVelocity,X  ; Reverse X velocity&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  JMP PterryPlatformCollision_FinalizeBounce&lt;br /&gt;
&lt;br /&gt;
PterryHitPlatform_MoveDownSlightly   ; Hit top of platform, shallow bounce down&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$02                           ; Move Pterry down slightly (adjust Y coord up on screen)&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  JMP PterryPlatformCollision_FinalizeBounce&lt;br /&gt;
&lt;br /&gt;
PterryHitPlatform_MoveUp  ; Hit bottom of platform, bounce up&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02                 ; Move Pterry up slightly (adjust Y coord down on screen)&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  JMP PterryPlatformCollision_FinalizeBounce&lt;br /&gt;
&lt;br /&gt;
PterryHitPlatform_FaceLeftAndReverseXVel   ; Hit right side of platform&lt;br /&gt;
  LDA #Direction_Left                      ; Change direction to left&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA GameObjectXVelocity,X                ; Reverse X velocity&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
                                           ; Fall through to PterryPlatformCollision_FinalizeBounce&lt;br /&gt;
&lt;br /&gt;
PterryPlatformCollision_FinalizeBounce     ; Common code after platform collision&lt;br /&gt;
  LDA #SFX_BirdPlatformBounce              ; Pterry uses bird bounce sound for platforms&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA Temp65                               ; Temp65 holds adjusted X from CheckPterryPlatformCollision&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  LDA Temp66                               ; Temp66 holds adjusted Y from CheckPterryPlatformCollision&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
&lt;br /&gt;
PterryNoPlatformCollision                  ; No platform collision or handled above&lt;br /&gt;
  JSR UpdateAirborneObjectPhysics          ; Apply standard airborne physics (gravity, X/Y movement)&lt;br /&gt;
&lt;br /&gt;
CheckPterryStateAfterPhysics&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #PterryState_Leaving                           ; Is Pterry leaving the screen?&lt;br /&gt;
  BNE CheckPterryState_NormalOrCharging&lt;br /&gt;
  JSR SetPterryVelocityForChargingScreen             ; Set fast velocity&lt;br /&gt;
  JSR AdjustBirdYBasedOnAltitude                     ; Fine-tune Y velocity for leaving&lt;br /&gt;
  JMP UpdatePterryTargetingAndVerticalVelocity_Main  ; Further Y velocity adjustments and animation&lt;br /&gt;
&lt;br /&gt;
CheckPterryState_NormalOrCharging&lt;br /&gt;
  CMP #PterryState_Normal            ; If Pterry is normal do his regular logic&lt;br /&gt;
  BEQ HandlePterryNormalStateLogic&lt;br /&gt;
&lt;br /&gt;
                                     ; Pterry must be in Charging state ($0B)&lt;br /&gt;
  LDA GameObjectChargingTimer,X      ; Check charging timer&lt;br /&gt;
  BEQ PterryChargeTimerExpired&lt;br /&gt;
  DEC GameObjectChargingTimer,X      ; Decrement charging timer&lt;br /&gt;
  JMP ExitPterryProcessing_NoAction  ; Continue charging&lt;br /&gt;
&lt;br /&gt;
PterryChargeTimerExpired&lt;br /&gt;
  LDA #PterryState_Normal            ; Charge finished, switch to normal state&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$FA                           ; Reset timer for next charge cycle (long delay)&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
&lt;br /&gt;
; Set velocity back to normal Pterry speed&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  BPL SetPterryNormalVelocity_RightFacing&lt;br /&gt;
  LDA #$00                           ; Why? This could have just been LDA #$FD. :|&lt;br /&gt;
  SEC                                ; Maybe the velocity was originally a variable&lt;br /&gt;
  SBC #$03                           ; instead of a constant.&lt;br /&gt;
  JMP SetPterryNormalVelocity_Store&lt;br /&gt;
SetPterryNormalVelocity_RightFacing&lt;br /&gt;
  LDA #$03  ; Normal speed right&lt;br /&gt;
SetPterryNormalVelocity_Store&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
ExitPterryProcessing_NoAction&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HandlePterryNormalStateLogic&lt;br /&gt;
  LDA GameObjectChargingTimer,X      ; Timer before Pterry starts charging&lt;br /&gt;
  BEQ PterryStartChargingSequence&lt;br /&gt;
  DEC GameObjectChargingTimer,X&lt;br /&gt;
  JMP ProcessPterryAIAndAnimation&lt;br /&gt;
&lt;br /&gt;
PterryStartChargingSequence&lt;br /&gt;
  LDA #SFX_PterryCharging&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #PterryState_Charging          ; Switch to charging state&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$02                           ; Initial animation frame for charging&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
  LDA #$03                           ; Initial animation counter for charging&lt;br /&gt;
  STA GameObjectAnimationCounter,X&lt;br /&gt;
  LDA #$00                           ; Zero out Y velocity when starting charge&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA #$5A                           ; Duration of the charge&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
                                     ; Fall through to SetPterryVelocityForChargingScreen&lt;br /&gt;
&lt;br /&gt;
SetPterryVelocityForChargingScreen&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  BPL SetPterryChargeVelocity_RightFacing&lt;br /&gt;
  LDA #$00                           ; Again, this could have been LDA #$FB&lt;br /&gt;
  SEC                                ; since all of the values are constants,&lt;br /&gt;
  SBC #$05                           ; instead of subtracting.&lt;br /&gt;
  JMP SetPterryChargeVelocity_Store&lt;br /&gt;
SetPterryChargeVelocity_RightFacing&lt;br /&gt;
  LDA #$05  ; Charge speed right&lt;br /&gt;
SetPterryChargeVelocity_Store&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessPterryAIAndAnimation&lt;br /&gt;
  LDA GameObjectAITimerLo,X               ; Low byte of AI decision timer&lt;br /&gt;
  BEQ PterryAITimerExpired_MakeDecision&lt;br /&gt;
  DEC GameObjectAITimerLo,X&lt;br /&gt;
  LDA PterryYVelocityZero                 ; Set Y velocity to 0 (ROM const $00)&lt;br /&gt;
  JMP UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
&lt;br /&gt;
PterryAITimerExpired_MakeDecision&lt;br /&gt;
  LDA #$02                                ; Reset AI action timer low byte&lt;br /&gt;
  STA GameObjectAITimerLo,X&lt;br /&gt;
  JSR FindBestTargetForGameObject         ; Find a player target&lt;br /&gt;
  LDY GameObjectPreyIndex,X               ; Y = index of targeted player&lt;br /&gt;
  BMI PterryNoValidTarget_AdjustYVel      ; If no target (or target invalid), just adjust Y based on altitude&lt;br /&gt;
&lt;br /&gt;
                                          ; Target acquired, adjust Y velocity to intercept&lt;br /&gt;
  LDA GameObjectYCoordHi,Y                ; Target's Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02                                ; Add slight offset to target Y (aim slightly below target)&lt;br /&gt;
  CMP GameObjectYCoordHi,X                ; Compare with Pterry's Y&lt;br /&gt;
  BCS PterryTargetIsLowerOrSame_FlyDown   ; If Pterry is above target (TargetY &amp;gt;= PterryY), fly down&lt;br /&gt;
&lt;br /&gt;
                                          ; Pterry is below target, needs to fly up&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                                ; Add a bit more to make comparison for &amp;quot;slightly up&amp;quot;&lt;br /&gt;
  CMP GameObjectYCoordHi,X&lt;br /&gt;
  BCC PterryTargetIsHigher_FlyUpSlightly  ; If Pterry is still significantly below, fly up slightly&lt;br /&gt;
&lt;br /&gt;
; Pterry is very close vertically, fly level&lt;br /&gt;
  LDA PterryYVelocityZero&lt;br /&gt;
  JMP UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
&lt;br /&gt;
PterryNoValidTarget_AdjustYVel            ; No target, or lost target&lt;br /&gt;
  JSR AdjustBirdYBasedOnAltitude          ; Adjust Y based on general altitude zones&lt;br /&gt;
  JMP UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
&lt;br /&gt;
PterryTargetIsHigher_FlyUpSlightly&lt;br /&gt;
  LDA PterryYVelocitySlightUp             ; Set Y velocity to slight up (ROM const $FF)&lt;br /&gt;
  JMP UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
&lt;br /&gt;
PterryTargetIsLowerOrSame_FlyDown&lt;br /&gt;
  LDA PterryYVelocitySlightDown           ; Set Y velocity to slight down (ROM const $01)&lt;br /&gt;
                                          ; Fall through to UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
&lt;br /&gt;
UpdatePterryTargetingAndVerticalVelocity_Main&lt;br /&gt;
  STA GameObjectYVelocityHi,X             ; Store determined Y velocity&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectAnimationDelay,X          ; Check animation delay timer&lt;br /&gt;
  BEQ PterryAnimationDelay_Expired&lt;br /&gt;
  DEC GameObjectAnimationDelay,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PterryAnimationDelay_Expired&lt;br /&gt;
  LDY GameObjectAnimationCounter,X     ; Get current animation sequence counter&lt;br /&gt;
  LDA PterryFrameIndexAdjustmentLUT,Y  ; Get frame adjustment based on counter&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC GameObjectAnimationFrame,X       ; Add to current animation frame&lt;br /&gt;
  STA GameObjectAnimationFrame,X       ; Store new frame&lt;br /&gt;
  DEC GameObjectAnimationCounter,X     ; Decrement animation sequence counter&lt;br /&gt;
  BPL SkipPterryAnimCounterWrap&lt;br /&gt;
  LDA #$03                             ; Wrap counter if it went negative&lt;br /&gt;
  STA GameObjectAnimationCounter,X&lt;br /&gt;
SkipPterryAnimCounterWrap&lt;br /&gt;
  LDA #$04                             ; Reset animation delay timer&lt;br /&gt;
  STA GameObjectAnimationDelay,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Player vs Pterodactyl Collision&lt;br /&gt;
; Input: X = Player index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandlePlayerVsPterry&lt;br /&gt;
  LDY #$0C&lt;br /&gt;
PlayerVsPterryCollisionLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ CheckNextPterryForCollision&lt;br /&gt;
  CMP #$0D&lt;br /&gt;
  BEQ CheckNextPterryForCollision&lt;br /&gt;
  JSR GameObjCollisionDetection  ; returns carry is clear on collision&lt;br /&gt;
  BCC PlayerVsPterryDetermineJoustWinner&lt;br /&gt;
CheckNextPterryForCollision&lt;br /&gt;
  DEY&lt;br /&gt;
  CPY #$0A&lt;br /&gt;
  BCS PlayerVsPterryCollisionLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlayerVsPterryDetermineJoustWinner&lt;br /&gt;
; Collision occurred. Check vertical alignment to see who wins.&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  DEC Temp5E&lt;br /&gt;
  DEC Temp5E&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BEQ PterryAndPlayerSameHeight  ; Player is slightly above Pterry&lt;br /&gt;
  INC Temp5E&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BEQ PterryAndPlayerSameHeight  ; Player is level with Pterry&lt;br /&gt;
  INC Temp5E&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BEQ PterryAndPlayerSameHeight  ; Player is slightly below Pterry&lt;br /&gt;
  JMP StartPlayerDeath           ; Player is too low, player dies&lt;br /&gt;
&lt;br /&gt;
PterryAndPlayerSameHeight&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  CMP GameObjectDirection,Y&lt;br /&gt;
  BNE PlayerJoustedPterry&lt;br /&gt;
  JMP StartPlayerDeath           ; Player wasn't facing pterry, player dies&lt;br /&gt;
&lt;br /&gt;
PlayerJoustedPterry&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  STA GameObjectXVelocity,Y&lt;br /&gt;
  LDA #SFX_PterryDefeated&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$0D&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA GameObjectYCoordLo,Y&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectXCoordLo,Y&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA GameObjectAnimationFrame,Y&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  JMP UpdatePlayerScoreAndBonus&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetAnyPterrysToLeaving&lt;br /&gt;
; Sets the state of all active Pterodactyls to &amp;quot;Leaving&amp;quot; ($0C).&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetAnyPterrysToLeaving&lt;br /&gt;
  LDY #$0C&lt;br /&gt;
  STY PterryCountdownHi&lt;br /&gt;
SetAnyPterrysToLeavingLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ SkipPterryLeavingUpdate  ; skip if pterry is dead and gone&lt;br /&gt;
  CMP #$0D&lt;br /&gt;
  BEQ SkipPterryLeavingUpdate  ; skip if pterry is offscreen&lt;br /&gt;
  LDA #$0C&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
SkipPterryLeavingUpdate&lt;br /&gt;
  DEY&lt;br /&gt;
  CPY #$0A&lt;br /&gt;
  BCS SetAnyPterrysToLeavingLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Collision Detection Data&lt;br /&gt;
; These LUTs define parameters for the simplified collision detection.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ObjectOffsetXLUT&lt;br /&gt;
 .byte $04,$04,$04,$04,$04,$04,$04,$04,$04,$04          ; birds&lt;br /&gt;
 .byte $07,$07,$07                                      ; pterrys&lt;br /&gt;
 .byte $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02  ; eggs&lt;br /&gt;
&lt;br /&gt;
ObjectOffsetYLUT&lt;br /&gt;
 .byte $05,$06,$05,$05,$05,$05,$05,$05,$05,$05          ; birds&lt;br /&gt;
 .byte $05,$05,$05                                      ; pterrys&lt;br /&gt;
 .byte $03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03  ; eggs&lt;br /&gt;
&lt;br /&gt;
ObjectCollisionWidthLUT&lt;br /&gt;
 .byte $07,$07,$07,$07,$07,$07,$07,$07,$07,$07          ; birds&lt;br /&gt;
 .byte $0C,$0C,$0C                                      ; pterrys&lt;br /&gt;
 .byte $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05  ; eggs&lt;br /&gt;
&lt;br /&gt;
ObjectCollisionHeightLUT&lt;br /&gt;
 .byte $09,$0B,$09,$09,$09,$09,$09,$09,$09,$09          ; birds&lt;br /&gt;
 .byte $09,$09,$09                                      ; pterrys&lt;br /&gt;
 .byte $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07  ; eggs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; GameObjCollisionDetection&lt;br /&gt;
; Performs a simplified Axis-Aligned Bounding Box (AABB) collision check&lt;br /&gt;
; between two game objects.&lt;br /&gt;
; Input: X = Index of the first game object.&lt;br /&gt;
;        Y = Index of the second game object.&lt;br /&gt;
; Output: Carry Flag: SET if NO collision, CLEAR if collision.&lt;br /&gt;
;         TempCollisionOverlap holds absolute Y-distance on collision.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
GameObjCollisionDetection&lt;br /&gt;
; Calculate Effective X coordinate for Object X&lt;br /&gt;
  LDA GameObjectXCoordHi,X        ; Load ObjX's base X coord&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectOffsetXLUT,X          ; Add ObjX's X offset&lt;br /&gt;
  STA Temp5E                      ; Store EffX_ObjX in Temp5E&lt;br /&gt;
&lt;br /&gt;
; Calculate absolute difference between Effective X of ObjX and Effective X of ObjY&lt;br /&gt;
  LDA GameObjectXCoordHi,Y        ; Load ObjY's base X coord&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectOffsetXLUT,Y          ; Add ObjY's X offset (EffX_ObjY)&lt;br /&gt;
  SEC                             ; Prepare for subtraction&lt;br /&gt;
  SBC Temp5E                      ; A = EffX_ObjY - EffX_ObjX&lt;br /&gt;
  BPL CalculateAbsX_IsPositive    ; If result is positive, it's the absolute difference&lt;br /&gt;
  EOR #$FF                        ; Negate the result (part 1)&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                        ; Negate the result (part 2, to get absolute value)&lt;br /&gt;
CalculateAbsX_IsPositive&lt;br /&gt;
  STA Temp66                      ; Store absolute X-distance in Temp66&lt;br /&gt;
&lt;br /&gt;
; Check for X-axis overlap using Object Y's collision width threshold&lt;br /&gt;
  CMP ObjectCollisionWidthLUT,Y   ; Compare abs X-distance with ObjY's collision width threshold&lt;br /&gt;
  BCS NoCollisionDetected_Return  ; If DistX &amp;gt;= Width_Y, no X-overlap. Set Carry and RTS.&lt;br /&gt;
&lt;br /&gt;
; X-axis overlaps, now check Y-axis&lt;br /&gt;
; Calculate Effective Y coordinate for Object X&lt;br /&gt;
  LDA GameObjectYCoordHi,X        ; Load ObjX's base Y coord&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectOffsetYLUT,X          ; Add ObjX's Y offset&lt;br /&gt;
  STA Temp5E                      ; Store EffY_ObjX in Temp5E&lt;br /&gt;
&lt;br /&gt;
; Calculate absolute difference between Effective Y of ObjX and Effective Y of ObjY&lt;br /&gt;
  LDA GameObjectYCoordHi,Y        ; Load ObjY's base Y coord&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectOffsetYLUT,Y          ; Add ObjY's Y offset (EffY_ObjY)&lt;br /&gt;
  SEC                             ; Prepare for subtraction&lt;br /&gt;
  SBC Temp5E                      ; A = EffY_ObjY - EffY_ObjX&lt;br /&gt;
  BPL CalculateAbsY_IsPositive    ; If positive, it's the absolute difference&lt;br /&gt;
  EOR #$FF                        ; Negate (part 1)&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01                        ; Negate (part 2, to get absolute value)&lt;br /&gt;
CalculateAbsY_IsPositive&lt;br /&gt;
  STA TempCollisionOverlap        ; Store absolute Y-distance&lt;br /&gt;
&lt;br /&gt;
; Special collision height check if Object Y is Player 1&lt;br /&gt;
  CPY #PLAYER1_OBJECT_INDEX            ; Is Object Y Player 1?&lt;br /&gt;
  BEQ CheckCollision_Player1_Y_Height  ; Yes, branch to P1 specific height check&lt;br /&gt;
&lt;br /&gt;
; Object Y is not Player 1, use its standard collision height from LUT&lt;br /&gt;
  CMP ObjectCollisionHeightLUT,Y  ; Compare abs Y-distance with ObjY's collision height threshold&lt;br /&gt;
; Carry will be CLEAR if DistY &amp;lt; Height_Y (collision)&lt;br /&gt;
; Carry will be SET if DistY &amp;gt;= Height_Y (no collision)&lt;br /&gt;
; Fall through to RTS. If BCS was taken (no collision), Carry is SET.&lt;br /&gt;
; If CMP results in DistY &amp;lt; Height_Y, Carry is CLEAR (collision).&lt;br /&gt;
&lt;br /&gt;
NoCollisionDetected_Return&lt;br /&gt;
  RTS  ; Return with Carry SET (no collision) or CLEAR (collision)&lt;br /&gt;
&lt;br /&gt;
CheckCollision_Player1_Y_Height&lt;br /&gt;
; Player 1 specific Y-collision height check (functionally same as LUT for P1)&lt;br /&gt;
  CMP #PLAYER1_COLLISION_HEIGHT_SPECIAL  ; Compare abs Y-distance with P1's specific height value&lt;br /&gt;
; Carry will be CLEAR if DistY &amp;lt; Value (collision)&lt;br /&gt;
; Carry will be SET if DistY &amp;gt;= Value (no collision)&lt;br /&gt;
  RTS ; Return with Carry status from CMP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; ESRoutineScheduler&lt;br /&gt;
; Event Scheduler main loop. Iterates through 18 event slots.&lt;br /&gt;
; If an event's index is positive, it executes the corresponding routine.&lt;br /&gt;
; If an event's index is negative, it treats it as a countdown timer. When the&lt;br /&gt;
; timer reaches zero, the index is made positive so it will run on the next pass.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ESRoutineScheduler&lt;br /&gt;
  INC IncrementingRandSeed&lt;br /&gt;
  LDX #$11&lt;br /&gt;
ESRoutineSchedulerLoop&lt;br /&gt;
  LDA ESRoutineIndex,X&lt;br /&gt;
  BEQ ESRoutineSchedulerLoopBottom     ; if index=0 handler is off&lt;br /&gt;
  BMI UpdateEventTimers                ; if index&amp;lt;0 update this timer&lt;br /&gt;
                                       ; if index&amp;gt;0 run this routine&lt;br /&gt;
  ASL&lt;br /&gt;
  TAY                                  ; y=index*2 (table has sequential lo+hi pairs)&lt;br /&gt;
  LDA ESRoutinesLo,Y&lt;br /&gt;
  STA TempPoint5ACurrentESRoutineLo&lt;br /&gt;
  LDA ESRoutinesHi,Y&lt;br /&gt;
  STA TempPoint5ACurrentESRoutineHi&lt;br /&gt;
  JMP (TempPoint5ACurrentESRoutineLo)&lt;br /&gt;
&lt;br /&gt;
UpdateEventTimers&lt;br /&gt;
  DEC ESRoutineTimer,X&lt;br /&gt;
  BNE EventTimerStillCountingDown&lt;br /&gt;
; Once the timer expires, we invert the function index to turn off&lt;br /&gt;
; the timer. The next time the handler loop is called, it will run.&lt;br /&gt;
  LDA ESRoutineIndex,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  STA ESRoutineIndex,X&lt;br /&gt;
  INC ESRoutineIndex,X&lt;br /&gt;
EventTimerStillCountingDown&lt;br /&gt;
  JMP ESRoutineSchedulerLoopBottom&lt;br /&gt;
&lt;br /&gt;
ESScheduleNextRoutine&lt;br /&gt;
; Common endpoint for many ES Jump table functions. Sets/Resets timer&lt;br /&gt;
; and advances and inverts the index. (index=0-index+1) &lt;br /&gt;
  STA ESRoutineTimer,X&lt;br /&gt;
  LDA ESRoutineIndex,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
ESUpdateRoutineIndex&lt;br /&gt;
  STA ESRoutineIndex,X&lt;br /&gt;
ESRoutineSchedulerLoopBottom&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ESRoutineSchedulerLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ESCancelRoutine&lt;br /&gt;
; Cancels the currently running event by setting its index to 0.&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  BEQ ESUpdateRoutineIndex&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Event Scheduler Routine Jump Table&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ESRoutinesLo              ; Event Timer jump table&lt;br /&gt;
 .byte &amp;lt;ESGameColdInit    ; event index $00&lt;br /&gt;
ESRoutinesHi&lt;br /&gt;
 .byte &amp;gt;ESGameColdInit&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESSetPointedValueFromRandom  ; event index $01&lt;br /&gt;
 .byte &amp;gt;ESSetPointedValueFromRandom&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_AdvanceLavaSparkleFrame   ; event index $02&lt;br /&gt;
 .byte &amp;gt;ES_AdvanceLavaSparkleFrame&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_ReverseLavaSparkleFrame   ; event index $03&lt;br /&gt;
 .byte &amp;gt;ES_ReverseLavaSparkleFrame&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_SetRandomLavaSparkleFrameAndCancel  ; event index $04&lt;br /&gt;
 .byte &amp;gt;ES_SetRandomLavaSparkleFrameAndCancel&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESSetupFlameAnimation     ; event index $05&lt;br /&gt;
 .byte &amp;gt;ESSetupFlameAnimation&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESDoFlameAnimation        ; event index $06&lt;br /&gt;
 .byte &amp;gt;ESDoFlameAnimation&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESSetupBridgeBurning      ; event index $07&lt;br /&gt;
 .byte &amp;gt;ESSetupBridgeBurning&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESAnimateBridgeBurning    ; event index $08&lt;br /&gt;
 .byte &amp;gt;ESAnimateBridgeBurning&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESAnimateBridgeReforming  ; event index $09&lt;br /&gt;
 .byte &amp;gt;ESAnimateBridgeReforming&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESWave1StartRoutines      ; event index $0A &lt;br /&gt;
 .byte &amp;gt;ESWave1StartRoutines&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESRaiseLavaWave1          ; event index $0B&lt;br /&gt;
 .byte &amp;gt;ESRaiseLavaWave1&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESWave2StartRoutines      ; event index $0C&lt;br /&gt;
 .byte &amp;gt;ESWave2StartRoutines&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESRaiseLavaWave2          ; event index $0D&lt;br /&gt;
 .byte &amp;gt;ESRaiseLavaWave2&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESWave3StartRoutines      ; event index $0E&lt;br /&gt;
 .byte &amp;gt;ESWave3StartRoutines&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESRaiseLavaWave3          ; event index $0F&lt;br /&gt;
 .byte &amp;gt;ESRaiseLavaWave3&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_StartEndOfWaveBonusDisplayTimer ; event index $10&lt;br /&gt;
 .byte &amp;gt;ES_StartEndOfWaveBonusDisplayTimer&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESTransitionToNextLevel            ; event index $11&lt;br /&gt;
 .byte &amp;gt;ESTransitionToNextLevel&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_StartBuzzardBaitWarningDelay    ; event index $12&lt;br /&gt;
 .byte &amp;gt;ES_StartBuzzardBaitWarningDelay&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShowBuzzardBaitText              ; event index $13&lt;br /&gt;
 .byte &amp;gt;ESShowBuzzardBaitText&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ES_StartPreWaveEnemySpawnDelay     ; event index $14&lt;br /&gt;
 .byte &amp;gt;ES_StartPreWaveEnemySpawnDelay&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESIfEggWaveDoSetup                 ; event index $15&lt;br /&gt;
 .byte &amp;gt;ESIfEggWaveDoSetup&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_AdvanceBottomPlatformDissolve  ; event index $16&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_AdvanceBottomPlatformDissolve&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_AdvanceBottomPlatformDissolve  ; event index $17&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_AdvanceBottomPlatformDissolve&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_AdvanceBottomPlatformDissolve  ; event index $18&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_AdvanceBottomPlatformDissolve&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_AdvanceBottomPlatformDissolve  ; event index $19&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_AdvanceBottomPlatformDissolve&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_SetBottomPlatformDissolveDelay ; event index $1A&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_SetBottomPlatformDissolveDelay&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;UNUSED_ES_CleanupBottomPlatformDissolve  ; event index $1B&lt;br /&gt;
 .byte &amp;gt;UNUSED_ES_CleanupBottomPlatformDissolve&lt;br /&gt;
&lt;br /&gt;
; this sequence of functions does the top center platform (4) dissolve animation...&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Left   ; event index $1C &lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Right  ; event index $1D&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Left   ; event index $1E&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Right  ; event index $1F&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Left   ; event index $20&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Right  ; event index $21&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Left   ; event index $22&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform4Right  ; event index $23&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform4Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESStartPlatform4DissolveVisuals       ; event index $24&lt;br /&gt;
 .byte &amp;gt;ESStartPlatform4DissolveVisuals&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $25&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $26&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $27&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;AdvancePlatform4DissolveFrame         ; event index $28&lt;br /&gt;
 .byte &amp;gt;AdvancePlatform4DissolveFrame&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $29&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $2A&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform4DissolveParticles    ; event index $2B&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform4DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESDissolvingPlatformAnimationCleanup  ; event index $2C&lt;br /&gt;
 .byte &amp;gt;ESDissolvingPlatformAnimationCleanup&lt;br /&gt;
&lt;br /&gt;
; this sequence of functions does the top side-wrapping platform (5+6) dissolve animation...&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Left   ; event index $2D&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Right  ; event index $2E&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Left   ; event index $2F&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Right  ; event index $30&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Left   ; event index $31&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Right  ; event index $32&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Left   ; event index $33&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatforms56Right  ; event index $34&lt;br /&gt;
 .byte &amp;gt;ESShakePlatforms56Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESStartPlatforms56DissolveVisuals     ; event index $35&lt;br /&gt;
 .byte &amp;gt;ESStartPlatforms56DissolveVisuals&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $36&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $37&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $38&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESAdvancePlatforms56DissolveFrame     ; event index $39&lt;br /&gt;
 .byte &amp;gt;ESAdvancePlatforms56DissolveFrame&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $3A&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $3B&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatforms56DissolveParticles  ; event index $3C&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESDissolvingPlatformAnimationCleanup  ; event index $3D&lt;br /&gt;
 .byte &amp;gt;ESDissolvingPlatformAnimationCleanup&lt;br /&gt;
&lt;br /&gt;
; this sequence of functions does the low center platform (0) dissolve animation...&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Left   ; event index $3E&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Right  ; event index $3F&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Left   ; event index $40&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Right  ; event index $41&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Left   ; event index $42&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Right  ; event index $43&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Left   ; event index $44&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Left&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESShakePlatform0Right  ; event index $45&lt;br /&gt;
 .byte &amp;gt;ESShakePlatform0Right&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESStartPlatform0DissolveVisuals       ; event index $46&lt;br /&gt;
 .byte &amp;gt;ESStartPlatform0DissolveVisuals&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $47&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $48&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $49&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESAdvancePlatform0DissolveFrame       ; event index $4A&lt;br /&gt;
 .byte &amp;gt;ESAdvancePlatform0DissolveFrame&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $4B&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $4C&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESUpdatePlatform0DissolveParticles    ; event index $4D&lt;br /&gt;
 .byte &amp;gt;ESUpdatePlatform0DissolveParticles&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;lt;ESDissolvingPlatformAnimationCleanup  ; event index $4E&lt;br /&gt;
 .byte &amp;gt;ESDissolvingPlatformAnimationCleanup&lt;br /&gt;
&lt;br /&gt;
UNUSED_ES_AdvanceBottomPlatformDissolve&lt;br /&gt;
  INC SpawnPlatformDissolved1,X&lt;br /&gt;
UNUSED_ES_SetBottomPlatformDissolveDelay&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
UNUSED_ES_CleanupBottomPlatformDissolve&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA SpawnPlatformDissolved1,X&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
ES_StartPreWaveEnemySpawnDelay&lt;br /&gt;
  LDA #$50&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESIfEggWaveDoSetup&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  JSR InitializeWave&lt;br /&gt;
  LDA IsEggWave&lt;br /&gt;
  BEQ EggWaveSetupDone&lt;br /&gt;
  JSR SetupEggWave&lt;br /&gt;
EggWaveSetupDone&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
ESDissolvingPlatformAnimationCleanup&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDY #$05&lt;br /&gt;
PlatformAnimationCleanupLoop&lt;br /&gt;
  STA PlatformDissolveAnimationFlag0,Y  ; reset all 6 flags&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL PlatformAnimationCleanupLoop&lt;br /&gt;
  STA ESRoutineIndex,X&lt;br /&gt;
  JMP ESRoutineSchedulerLoopBottom&lt;br /&gt;
&lt;br /&gt;
; Platforms by number:&lt;br /&gt;
; 0: Bottom center&lt;br /&gt;
; 1: Bottom left (wraps)&lt;br /&gt;
; 2: Bottom right (wraps)&lt;br /&gt;
; 3: Mid-level platform&lt;br /&gt;
; 4: Top center&lt;br /&gt;
; 5: Top left (wraps)&lt;br /&gt;
; 6: Top right (wraps)&lt;br /&gt;
&lt;br /&gt;
ESShakePlatform4Left&lt;br /&gt;
  DEC Platform4XCoordinate&lt;br /&gt;
  DEC SpawnPoint4XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESShakePlatform4Right&lt;br /&gt;
  INC Platform4XCoordinate&lt;br /&gt;
  INC SpawnPoint4XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESStartPlatform4DissolveVisuals&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Platform4PaletteWidth&lt;br /&gt;
  STA Platform4GfxLo&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PlatformDissolveAnimationFlag0&lt;br /&gt;
  STA PlatformDissolveAnimationFlag1&lt;br /&gt;
  LDA #$32&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord0&lt;br /&gt;
  LDA #$3E&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord1&lt;br /&gt;
  LDA #$41&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord0&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord1&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESUpdatePlatform4DissolveParticles&lt;br /&gt;
  INC PlatformDissolveAnimationXCoord0&lt;br /&gt;
  DEC PlatformDissolveAnimationXCoord1&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord0&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord1&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
AdvancePlatform4DissolveFrame&lt;br /&gt;
  INC PlatformDissolveAnimationFlag0&lt;br /&gt;
  INC PlatformDissolveAnimationFlag1&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESShakePlatforms56Left      ; this label is misleading, but named to match the existing pattern&lt;br /&gt;
                            ; The two platform halves shake by moving in and out.&lt;br /&gt;
  DEC Platform5XCoordinate&lt;br /&gt;
  INC Platform6XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESShakePlatforms56Right&lt;br /&gt;
  INC Platform5XCoordinate&lt;br /&gt;
  DEC Platform6XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESStartPlatforms56DissolveVisuals&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Platform56PaletteWidth&lt;br /&gt;
  STA Platform56GfxLo&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PlatformDissolveAnimationFlag2&lt;br /&gt;
  STA PlatformDissolveAnimationFlag3&lt;br /&gt;
  LDA #$90&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord2&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord3&lt;br /&gt;
  LDA #$39&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord2&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord3&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESUpdatePlatforms56DissolveParticles&lt;br /&gt;
  INC PlatformDissolveAnimationXCoord2&lt;br /&gt;
  DEC PlatformDissolveAnimationXCoord3&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord2&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord3&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESAdvancePlatforms56DissolveFrame&lt;br /&gt;
  INC PlatformDissolveAnimationFlag2&lt;br /&gt;
  INC PlatformDissolveAnimationFlag3&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESShakePlatform0Left&lt;br /&gt;
  DEC Platform0XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESShakePlatform0Right&lt;br /&gt;
  INC Platform0XCoordinate&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESStartPlatform0DissolveVisuals&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Platform0PaletteWidth&lt;br /&gt;
  STA Platform0GfxLo&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PlatformDissolveAnimationFlag4&lt;br /&gt;
  STA PlatformDissolveAnimationFlag5&lt;br /&gt;
  LDA #$39&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord4&lt;br /&gt;
  LDA #$45&lt;br /&gt;
  STA PlatformDissolveAnimationXCoord5&lt;br /&gt;
  LDA #$81&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord4&lt;br /&gt;
  STA PlatformDissolveAnimationYCoord5&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESUpdatePlatform0DissolveParticles&lt;br /&gt;
  INC PlatformDissolveAnimationXCoord4&lt;br /&gt;
  DEC PlatformDissolveAnimationXCoord5&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord4&lt;br /&gt;
  INC PlatformDissolveAnimationYCoord5&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESAdvancePlatform0DissolveFrame&lt;br /&gt;
  INC PlatformDissolveAnimationFlag4&lt;br /&gt;
  INC PlatformDissolveAnimationFlag5&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ES_StartBuzzardBaitWarningDelay&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESShowBuzzardBaitText&lt;br /&gt;
  TXA                    ; save X and Y&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDA #$02               ; &amp;quot;buzzard bait&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  PLA                    ; restore X and Y&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
ES_StartEndOfWaveBonusDisplayTimer&lt;br /&gt;
  LDA #$46&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESTransitionToNextLevel&lt;br /&gt;
  LDA PterryState1&lt;br /&gt;
  ORA PterryState2&lt;br /&gt;
  ORA PterryState3&lt;br /&gt;
  BEQ NoPterrysAlive2&lt;br /&gt;
  JSR SetAnyPterrysToLeaving&lt;br /&gt;
  DEC ESRoutineIndex,X       ; Change event to the event above this one&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
NoPterrysAlive2&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  JSR DisplayLevelStartMsg&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
ESSetupBridgeBurning&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA BridgeBurningWidth&lt;br /&gt;
  LDA #$05                  ; schedule flame sprite frame animation&lt;br /&gt;
  STA ESRoutineIndex+8&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA $6E&lt;br /&gt;
  LDA #$14&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESAnimateBridgeBurning&lt;br /&gt;
  INC BridgeBurningWidth&lt;br /&gt;
  DEC $6E&lt;br /&gt;
  BMI ESAnimateBridgeBurningChangeState&lt;br /&gt;
  INC BridgeLeftGfxByte1&lt;br /&gt;
  INC BridgeLeftGfxByte3&lt;br /&gt;
  INC BridgeLeftGfxByte2&lt;br /&gt;
  DEC BridgeRightGfxByte1&lt;br /&gt;
  DEC BridgeRightGfxByte3&lt;br /&gt;
  DEC BridgeRightGfxByte2&lt;br /&gt;
ESBridgeAnimationScheduleNextFrame&lt;br /&gt;
  DEC ESRoutineIndex,X&lt;br /&gt;
  LDA #$0F&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESAnimateBridgeBurningChangeState&lt;br /&gt;
  LDA #$10&lt;br /&gt;
  STA $6E&lt;br /&gt;
  LDA #$0F&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ESAnimateBridgeReforming&lt;br /&gt;
  DEC $6E&lt;br /&gt;
  BMI FinishBridgeReforming&lt;br /&gt;
  DEC BridgeLeftGfxByte1&lt;br /&gt;
  DEC BridgeLeftGfxByte3&lt;br /&gt;
  INC BridgeRightGfxByte1&lt;br /&gt;
  INC BridgeRightGfxByte3&lt;br /&gt;
  JMP ESBridgeAnimationScheduleNextFrame&lt;br /&gt;
FinishBridgeReforming&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
TopFlameAnimationGfxLoLUT&lt;br /&gt;
 .byte $3A, $38, $36, $2E, $2C, $2A, $28, $26&lt;br /&gt;
 .byte $24, $22, $20, $34, $32, $30, $2E, $2C&lt;br /&gt;
 .byte $2A, $28, $26, $24, $22, $20 &lt;br /&gt;
&lt;br /&gt;
BottomFlameAnimationGfxLoLUT&lt;br /&gt;
 .byte $56, $54, $52, $4A, $48, $46, $44, $42 &lt;br /&gt;
 .byte $40, $3E, $3C, $50, $4E, $4C, $4A, $48 &lt;br /&gt;
 .byte $46, $44, $42, $40, $3E, $3C &lt;br /&gt;
&lt;br /&gt;
ESSetupFlameAnimation               ; event index $05&lt;br /&gt;
  LDA #$15&lt;br /&gt;
  STA LeftFlameAnimationIndex&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  STA RightFlameAnimationIndex&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESDoFlameAnimation                  ; event index $06&lt;br /&gt;
  LDY LeftFlameAnimationIndex&lt;br /&gt;
  LDA TopFlameAnimationGfxLoLUT,Y&lt;br /&gt;
  STA $1F50&lt;br /&gt;
  LDA BottomFlameAnimationGfxLoLUT,Y&lt;br /&gt;
  STA $1FA6&lt;br /&gt;
  LDY RightFlameAnimationIndex&lt;br /&gt;
  LDA TopFlameAnimationGfxLoLUT,Y&lt;br /&gt;
  STA $1F4C&lt;br /&gt;
  LDA BottomFlameAnimationGfxLoLUT,Y&lt;br /&gt;
  STA $1FA2&lt;br /&gt;
&lt;br /&gt;
  DEC LeftFlameAnimationIndex&lt;br /&gt;
  BPL SkipWrapFixLeftFlameIndex&lt;br /&gt;
  LDA #$15&lt;br /&gt;
  STA LeftFlameAnimationIndex&lt;br /&gt;
SkipWrapFixLeftFlameIndex&lt;br /&gt;
  DEC RightFlameAnimationIndex&lt;br /&gt;
  BPL SkipWrapFixRightFlameIndex&lt;br /&gt;
  LDA #$15&lt;br /&gt;
  STA RightFlameAnimationIndex&lt;br /&gt;
SkipWrapFixRightFlameIndex&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  DEC ESRoutineIndex,X&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESWave1StartRoutines       ; event index $0A&lt;br /&gt;
  LDA #$06&lt;br /&gt;
SetValueThenESScheduleNextRoutine&lt;br /&gt;
  STA ESTemp6ELavaRiseCounter&lt;br /&gt;
  LDA #$0F&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESWave2StartRoutines&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA $1FC4&lt;br /&gt;
  LDA #$7C&lt;br /&gt;
  STA $1FC8&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  JMP SetValueThenESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESWave3StartRoutines&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA $1FB1&lt;br /&gt;
  LDA #$7C&lt;br /&gt;
  STA $1FAD&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP SetValueThenESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ESRaiseLavaWave1&lt;br /&gt;
  DEC LeftLavaLevelWave1&lt;br /&gt;
  DEC RightLavaLevelWave1&lt;br /&gt;
  DEC ESTemp6ELavaRiseCounter&lt;br /&gt;
  BMI DoneRisingLavaWave1&lt;br /&gt;
ScheduleThisRoutineAgainAfterDelay&lt;br /&gt;
  LDA #$0F                   ; Number of ticks to wait before running.&lt;br /&gt;
  DEC ESRoutineIndex,X       ; Decrement this timer so the &amp;quot;next&amp;quot;&lt;br /&gt;
  JMP ESScheduleNextRoutine  ; routine is this one again.&lt;br /&gt;
DoneRisingLavaWave1&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA ESRoutineIndex+3&lt;br /&gt;
  STA ESRoutineIndex+4&lt;br /&gt;
  JMP ESCancelRoutine        ; We're done&lt;br /&gt;
&lt;br /&gt;
ESRaiseLavaWave2&lt;br /&gt;
  DEC LeftLavaLevelWave2&lt;br /&gt;
  DEC RightLavaLevelWave2&lt;br /&gt;
  DEC ESTemp6ELavaRiseCounter&lt;br /&gt;
  BMI DoneRisingLavaWave2&lt;br /&gt;
  JMP ScheduleThisRoutineAgainAfterDelay&lt;br /&gt;
DoneRisingLavaWave2&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA ESRoutineIndex+1&lt;br /&gt;
  STA ESRoutineIndex+2&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
ESRaiseLavaWave3&lt;br /&gt;
  DEC LeftLavaLevelWave3&lt;br /&gt;
  DEC RightLavaLevelWave3&lt;br /&gt;
  DEC ESTemp6ELavaRiseCounter&lt;br /&gt;
  BMI DoneRisingLavaWave3&lt;br /&gt;
  JMP ScheduleThisRoutineAgainAfterDelay&lt;br /&gt;
&lt;br /&gt;
DoneRisingLavaWave3&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA ESRoutineIndex&lt;br /&gt;
  LDA #$07              ; Schedule the ESSetupBridgeBurning routine&lt;br /&gt;
  STA ESRoutineIndex+7  ; in 8th slot. (8th slot significance unknown)&lt;br /&gt;
  JMP ESCancelRoutine&lt;br /&gt;
&lt;br /&gt;
ESSetPointedValueFromRandom&lt;br /&gt;
  JSR ES_LoadLavaSparkleGfxPtr&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
ClampRandomValueLoop&lt;br /&gt;
  CMP #$20&lt;br /&gt;
  BCC StoreRandomValueAndScheduleNext&lt;br /&gt;
  CMP #$79&lt;br /&gt;
  BCC ContinueClampingRandomValue&lt;br /&gt;
  CMP #$99&lt;br /&gt;
  BCC StoreRandomValueAndScheduleNext&lt;br /&gt;
ContinueClampingRandomValue&lt;br /&gt;
  SBC #$3B&lt;br /&gt;
  JMP ClampRandomValueLoop&lt;br /&gt;
StoreRandomValueAndScheduleNext&lt;br /&gt;
  LDY #$03&lt;br /&gt;
  STA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ES_AdvanceLavaSparkleFrame&lt;br /&gt;
  JSR ES_LoadLavaSparkleGfxPtr&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  LDA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
ES_ReverseLavaSparkleFrame&lt;br /&gt;
  JSR ES_LoadLavaSparkleGfxPtr&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  LDA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  STA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BNE ScheduleNextESRoutineShortDelay&lt;br /&gt;
  LDA #$B0&lt;br /&gt;
  LDY #$03&lt;br /&gt;
  STA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
ScheduleNextESRoutineShortDelay&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
ES_LoadLavaSparkleGfxPtr&lt;br /&gt;
  LDA ES_LavaSparkleAnimationPtrLoLUT,X&lt;br /&gt;
  STA TempPoint5ACurrentESRoutineLo&lt;br /&gt;
  LDA ES_LavaSparkleAnimationPtrHiLUT,X&lt;br /&gt;
  STA TempPoint5ACurrentESRoutineHi&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ES_SetRandomLavaSparkleFrameAndCancel&lt;br /&gt;
  JSR ES_LoadLavaSparkleGfxPtr&lt;br /&gt;
  LDA #$B0&lt;br /&gt;
  LDY #$03&lt;br /&gt;
  STA (TempPoint5ACurrentESRoutineLo),Y&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA ESRoutineIndex,X&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
  AND #$1F&lt;br /&gt;
  JMP ESScheduleNextRoutine&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; ReturnRandInA&lt;br /&gt;
; A simple pseudo-random number generator.&lt;br /&gt;
; It uses an incrementing seed to read 4 bytes from ROM code space ($B0xx) and&lt;br /&gt;
; adds them together.&lt;br /&gt;
; Returns: A = random byte. Preserves Y.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ReturnRandInA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  INC IncrementingRandSeed&lt;br /&gt;
  LDA IncrementingRandSeed&lt;br /&gt;
  STA Temp68&lt;br /&gt;
  LDA #$B0&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  LDY #$03&lt;br /&gt;
RandLoop&lt;br /&gt;
  ADC ($68),Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RandLoop&lt;br /&gt;
  STA Temp68&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA Temp68&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; TrollAiLogic&lt;br /&gt;
; Manages the troll that lives in the lava. If conditions are right, it will&lt;br /&gt;
; jump out to grab a bird and pull it into the lava.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TrollAiLogic&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$03                      ; Troll only appears on level 3 and higher&lt;br /&gt;
  BMI TrollTargetSearchFailed&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  BEQ TrollTargetSearchFailed                     ; Troll does not appear on Beginner difficulty&lt;br /&gt;
  LDA TrollState&lt;br /&gt;
  BEQ SearchForTrollTarget      ; 0=troll hiding in lava&lt;br /&gt;
  BMI TrollInAirProcessing                     ; ff=troll jumping at bird&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE ProcessTrollState                     ; 02=troll holding a bird&lt;br /&gt;
  JMP TrollHoldingBirdUpdateState&lt;br /&gt;
ProcessTrollState&lt;br /&gt;
  JMP TrollIsRetreating&lt;br /&gt;
SearchForTrollTarget&lt;br /&gt;
  LDX #$09&lt;br /&gt;
SearchForTrollTargetLoop&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP TrollMinimumTargetYCoord&lt;br /&gt;
  BCC TrollTargetSearch_CheckNextObject&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BNE TrollTargetSearch_CheckNextObject&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BEQ TrollTargetSearch_CheckNextObject&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  CMP #$33&lt;br /&gt;
  BCC TrollTargetFound&lt;br /&gt;
  CMP #$A4&lt;br /&gt;
  BCS TrollTargetFound&lt;br /&gt;
TrollTargetSearch_CheckNextObject&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SearchForTrollTargetLoop&lt;br /&gt;
TrollTargetSearchFailed&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TrollTargetFound&lt;br /&gt;
  STX TrollTargetIndex&lt;br /&gt;
  LDA #$B6&lt;br /&gt;
  STA TrollYCoord&lt;br /&gt;
Troll_StartJump&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  STA TrollXCoord&lt;br /&gt;
  LDA #$FF        ; troll is jumping at a bird&lt;br /&gt;
  STA TrollState&lt;br /&gt;
  LDA #SFX_TrollJumping&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
SetTrollGrabGfxFrame&lt;br /&gt;
  LDA ObjectGrabYOffsetLUT,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC TrollYCoord&lt;br /&gt;
  BPL SelectTrollJumpFrameByDistance&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
SelectTrollJumpFrameByDistance&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BCS TrollGfxSelectMediumDistanceFrame&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  JMP TrollGfxFrameUpdate&lt;br /&gt;
TrollGfxSelectMediumDistanceFrame&lt;br /&gt;
  CMP #$06&lt;br /&gt;
  BCS TrollGfxSelectFarDistanceFrame&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP TrollGfxFrameUpdate&lt;br /&gt;
TrollGfxSelectFarDistanceFrame&lt;br /&gt;
  CMP #$09&lt;br /&gt;
  BCS TrollGfxSetDefaultOrRetreat&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  JMP TrollGfxFrameUpdate&lt;br /&gt;
TrollGfxSetDefaultOrRetreat&lt;br /&gt;
  LDA #$00&lt;br /&gt;
TrollGfxFrameUpdate&lt;br /&gt;
  STA TrollGfxOffset&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
TrollInAirProcessing&lt;br /&gt;
; Troll is in the air, check if it should grab the bird or retreat&lt;br /&gt;
  LDX TrollTargetIndex&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BNE TrollTargetInvalid&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BEQ TrollTargetInvalid&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP TrollMinimumTargetYCoord&lt;br /&gt;
  BCC TrollTargetInvalid&lt;br /&gt;
  LDY GameObjectXCoordHi,X&lt;br /&gt;
  CPY #$33&lt;br /&gt;
  BCC TrollTargetStillValid&lt;br /&gt;
  CPY #$A4&lt;br /&gt;
  BCS TrollTargetStillValid&lt;br /&gt;
TrollTargetInvalid&lt;br /&gt;
; troll retreats&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA TrollState&lt;br /&gt;
  BPL SetTrollGrabGfxFrame&lt;br /&gt;
TrollTargetStillValid&lt;br /&gt;
; Target is still valid, continue moving towards it&lt;br /&gt;
  STY TrollXCoord&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectGrabYOffsetLUT,X&lt;br /&gt;
  CMP TrollYCoord&lt;br /&gt;
  BCS TrollGrabbedBirdCheckGrabHeight&lt;br /&gt;
  LDA TrollYCoord&lt;br /&gt;
  CMP TrollMinimumGrabYCoord&lt;br /&gt;
  BCC TrollContinuesJump&lt;br /&gt;
  DEC TrollYCoord&lt;br /&gt;
TrollContinuesJump&lt;br /&gt;
  JMP SetTrollGrabGfxFrame&lt;br /&gt;
TrollHoldingBirdUpdateState&lt;br /&gt;
  LDX TrollTargetIndex&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$04                                ; alive&lt;br /&gt;
  BEQ TrollHoldingBirdUpdateGrabPosition&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BEQ TrollTargetInvalid&lt;br /&gt;
TrollHoldingBirdUpdateGrabPosition&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC ObjectGrabYOffsetLUT,X&lt;br /&gt;
TrollGrabbedBirdCheckGrabHeight&lt;br /&gt;
  CMP TrollMinimumGrabYCoord&lt;br /&gt;
  BCS TrollGrabbedTheBird&lt;br /&gt;
  JMP Troll_StartJump&lt;br /&gt;
TrollGrabbedTheBird&lt;br /&gt;
  STA TrollYCoord&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC TrollPullingVelocity&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  LDA TrollXCoord&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  JMP SetTrollGrabGfxFrame&lt;br /&gt;
TrollIsRetreating&lt;br /&gt;
  INC TrollYCoord&lt;br /&gt;
  LDA TrollYCoord&lt;br /&gt;
  CMP #$B6&lt;br /&gt;
  BCC TrollUpdateRetreatingFrame&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA TrollState                          ; troll in lava (default)&lt;br /&gt;
  STA TrollYCoord&lt;br /&gt;
TrollUpdateRetreatingFrame&lt;br /&gt;
  JMP TrollGfxSetDefaultOrRetreat&lt;br /&gt;
&lt;br /&gt;
ObjectGrabYOffsetLUT  ; bird objects only&lt;br /&gt;
 .byte $0A, $0C, $0A, $0A, $0A, $0A, $0A, $0A, $0A, $0A&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Platform Collision Detection Routines&lt;br /&gt;
; These routines check for collisions between a game object and the platforms.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
CheckPlatformCollision&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  STY Temp68&lt;br /&gt;
  LDY Temp69&lt;br /&gt;
  LDA PlatformCollisionCheckPointXLUT,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5E&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA PlatformCollisionCheckPointYLUT,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5F&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  LDY #$06&lt;br /&gt;
CheckCollisionAgainstEachPlatformLoop&lt;br /&gt;
  LSR Temp63&lt;br /&gt;
  BCS CheckCollisionWithPresentPlatform&lt;br /&gt;
CollisionCheckNextPlatform&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL CheckCollisionAgainstEachPlatformLoop&lt;br /&gt;
  JMP CheckCollisionWithLavaBridge&lt;br /&gt;
CheckCollisionWithPresentPlatform&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  CMP PlatformYTop,Y&lt;br /&gt;
  BCS PlatformCollisionCheckYBottomAndXBounds&lt;br /&gt;
  JMP PlatformCollisionNoHitReturnZero&lt;br /&gt;
PlatformCollisionCheckYBottomAndXBounds&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  CMP PlatformYBottom,Y&lt;br /&gt;
  BCS CollisionCheckNextPlatform&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  CMP PlatformXLeftEdge,Y&lt;br /&gt;
  BEQ CollisionCheckNextPlatform&lt;br /&gt;
  BCC CollisionCheckNextPlatform&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CMP PlatformXRightEdge,Y&lt;br /&gt;
  BCS CollisionCheckNextPlatform&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$04&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC PlatformXLeftBounce,Y&lt;br /&gt;
  BMI InitializeRightSideCollisionCheck&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp60&lt;br /&gt;
  BCS HandleLeftSidePlatformCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
HandleLeftSidePlatformCollision&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC TempCollisionOverlap&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  JMP ContinueRightSideCollisionCheck&lt;br /&gt;
InitializeRightSideCollisionCheck&lt;br /&gt;
  LDA #$64&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
ContinueRightSideCollisionCheck&lt;br /&gt;
  LDA PlatformXRightBounce,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp5E&lt;br /&gt;
  BMI ContinueCollisionCheckWithYAxis&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp60&lt;br /&gt;
  BCS UpdateClosestRightSideCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
UpdateClosestRightSideCollision&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BCS ContinueCollisionCheckWithYAxis&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5E&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp64&lt;br /&gt;
ContinueCollisionCheckWithYAxis&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC PlatformYBottomForBounceCheckLUT,Y&lt;br /&gt;
  BMI CheckPlatformTopCollision&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp60&lt;br /&gt;
  BCS UpdateClosestBottomSideCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
UpdateClosestBottomSideCollision&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BCS CheckPlatformTopCollision&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp64&lt;br /&gt;
CheckPlatformTopCollision&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA PlatformYTopForBounceCheckLUT,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp5F&lt;br /&gt;
  BMI SkipUpdatingClosestCollision&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp60&lt;br /&gt;
  BCS UpdateClosestBottomPlatformCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
UpdateClosestBottomPlatformCollision&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BCS SkipUpdatingClosestCollision&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA Temp64&lt;br /&gt;
SkipUpdatingClosestCollision&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC PlatformYTop,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BEQ UpdateClosestCollisionPoint&lt;br /&gt;
  BCC UpdateClosestCollisionPoint&lt;br /&gt;
  JMP FinalizePlatformCollisionCheck&lt;br /&gt;
UpdateClosestCollisionPoint&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP PlatformXLeftEdge,Y&lt;br /&gt;
  BCS FinalizeTopPlatformCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
FinalizeTopPlatformCollision&lt;br /&gt;
  LDA PlatformXRightEdge,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BCS HandlePlatformTopCollision&lt;br /&gt;
  JMP CollisionCheckNextPlatform&lt;br /&gt;
HandlePlatformTopCollision&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC TempCollisionOverlap&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  INC Temp66&lt;br /&gt;
  JMP FinalizePlatformCollisionCheck&lt;br /&gt;
CheckCollisionWithLavaBridge&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$AF&lt;br /&gt;
  BMI PlatformCollisionNoHitReturnZero&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC BridgeBurningWidth&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  INC TempCollisionOverlap&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC TempCollisionOverlap&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA #$E0&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC BridgeBurningWidth&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp5E&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BCS PrioritizeLavaBridgeHorizontalCollision&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  INC TempCollisionOverlap&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC TempCollisionOverlap&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA Temp66&lt;br /&gt;
PrioritizeLavaBridgeHorizontalCollision&lt;br /&gt;
  LDA Temp60&lt;br /&gt;
  CMP TempCollisionOverlap&lt;br /&gt;
  BCS FinalizePlatformCollisionCheck&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP BridgeBurningWidth&lt;br /&gt;
  BCS CheckLavaBridgeXBounds&lt;br /&gt;
  JMP PlatformCollisionNoHitReturnZero&lt;br /&gt;
CheckLavaBridgeXBounds&lt;br /&gt;
  LDA #$E0&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC BridgeBurningWidth&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BCS HandleLavaBridgeTopCollision&lt;br /&gt;
  JMP PlatformCollisionNoHitReturnZero&lt;br /&gt;
HandleLavaBridgeTopCollision&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Temp60&lt;br /&gt;
  STA Temp66&lt;br /&gt;
FinalizePlatformCollisionCheck&lt;br /&gt;
  LDY Temp68&lt;br /&gt;
  LDA Temp64&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlatformCollisionNoHitReturnZero&lt;br /&gt;
  LDY Temp68&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SelectEggCollisionPointAndCheck&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
SelectCollisionPointsAndCheckPlatform&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BNE SelectCollisionPointsForSkiddingBird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
SelectCollisionPointsForSkiddingBird&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
CheckForShallowPlatformCollision&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  CMP #$B0&lt;br /&gt;
  BCS FallbackToStandardCollisionCheck&lt;br /&gt;
  CMP #$AA&lt;br /&gt;
  BEQ FallbackToStandardCollisionCheck&lt;br /&gt;
  BCC FallbackToStandardCollisionCheck&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$66&lt;br /&gt;
  BCS FallbackToStandardCollisionCheck&lt;br /&gt;
  CMP #$62&lt;br /&gt;
  BCC FallbackToStandardCollisionCheck&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BPL FallbackToStandardCollisionCheck&lt;br /&gt;
  LDA #$AA&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA #$73&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
FallbackToStandardCollisionCheck&lt;br /&gt;
  CPX #$01&lt;br /&gt;
  BNE SelectCollisionPointForOtherBirds&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
SelectCollisionPointForOtherBirds&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
&lt;br /&gt;
CheckPterryPlatformCollision&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  CMP #$AD&lt;br /&gt;
  BCS SelectCollisionPointsForPterry&lt;br /&gt;
  CMP #$AA&lt;br /&gt;
  BCC SelectCollisionPointsForPterry&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$67&lt;br /&gt;
  BCS SelectCollisionPointsForPterry&lt;br /&gt;
  CMP #$62&lt;br /&gt;
  BCC SelectCollisionPointsForPterry&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BPL SelectCollisionPointsForPterry&lt;br /&gt;
  LDA #$AA&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA #$73&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SelectCollisionPointsForPterry&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  JMP CheckPlatformCollision&lt;br /&gt;
CheckIfEggSlippingOffPlatform&lt;br /&gt;
  STY Temp64&lt;br /&gt;
  LDY #$04&lt;br /&gt;
  JMP PerformPlatformEdgeCheck&lt;br /&gt;
CheckIfBirdNearPlatformEdge&lt;br /&gt;
  STY Temp64&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BNE SelectCollisionPointForSkiddingBird&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  JMP PerformPlatformEdgeCheck&lt;br /&gt;
SelectCollisionPointForSkiddingBird&lt;br /&gt;
  LDY #$0A&lt;br /&gt;
PerformPlatformEdgeCheck&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA PlatformCollisionCheckPointYLUT,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5F&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  INC Temp61&lt;br /&gt;
  LDA PlatformCollisionCheckPointXLUT,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5E&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  LDY #$06&lt;br /&gt;
PlatformEdgeCheckLoop&lt;br /&gt;
  LSR Temp63&lt;br /&gt;
  BCC CheckNextPlatformForEdge&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  CMP PlatformYTop,Y&lt;br /&gt;
  BEQ ConfirmBirdIsOnPlatform&lt;br /&gt;
  BCS CheckNextPlatformForEdge&lt;br /&gt;
  JMP FinishPlatformEdgeCheck&lt;br /&gt;
ConfirmBirdIsOnPlatform&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP PlatformXLeftEdge,Y&lt;br /&gt;
  BCC CheckNextPlatformForEdge&lt;br /&gt;
  LDA PlatformXRightEdge,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$03&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BCC CheckNextPlatformForEdge&lt;br /&gt;
  JMP PlatformEdgeCheckOnPlatformReturnTrue&lt;br /&gt;
CheckNextPlatformForEdge&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL PlatformEdgeCheckLoop&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  CMP #$B0&lt;br /&gt;
  BNE FinishPlatformEdgeCheck&lt;br /&gt;
  LDA #$E0&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC BridgeBurningWidth&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BEQ FinishPlatformEdgeCheck&lt;br /&gt;
  BCC FinishPlatformEdgeCheck&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  CMP BridgeBurningWidth&lt;br /&gt;
  BEQ FinishPlatformEdgeCheck&lt;br /&gt;
  BCC FinishPlatformEdgeCheck&lt;br /&gt;
  LDA #$E0&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC BridgeBurningWidth&lt;br /&gt;
  CMP Temp5E&lt;br /&gt;
  BEQ FinishPlatformEdgeCheck&lt;br /&gt;
  BCC FinishPlatformEdgeCheck&lt;br /&gt;
PlatformEdgeCheckOnPlatformReturnTrue&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp60&lt;br /&gt;
FinishPlatformEdgeCheck&lt;br /&gt;
  LDY Temp64&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; Pairs of coordinates used for platform collision checks&lt;br /&gt;
PlatformCollisionCheckPointXLUT&lt;br /&gt;
 .byte $08&lt;br /&gt;
PlatformCollisionCheckPointYLUT&lt;br /&gt;
 .byte $0F&lt;br /&gt;
 .byte $08,$0A&lt;br /&gt;
 .byte $04,$05&lt;br /&gt;
 .byte $10,$09&lt;br /&gt;
 .byte $08,$0C&lt;br /&gt;
 .byte $08,$0E&lt;br /&gt;
&lt;br /&gt;
PlatformXLeftEdge&lt;br /&gt;
 .byte $57,$AB,$18,$8D,$4E,$18,$A8&lt;br /&gt;
&lt;br /&gt;
PlatformXRightEdge&lt;br /&gt;
 .byte $7B,$CD,$44,$AE,$7D,$33,$C4&lt;br /&gt;
&lt;br /&gt;
PlatformYTop&lt;br /&gt;
 .byte $80,$70,$70,$68,$40,$38,$38&lt;br /&gt;
&lt;br /&gt;
PlatformYBottom&lt;br /&gt;
 .byte $86,$77,$76,$72,$46,$3E,$3E&lt;br /&gt;
&lt;br /&gt;
PlatformXLeftBounce  ; used to start low-approacing bird bouncing&lt;br /&gt;
 .byte $47,$9D,$0A,$80,$46,$11,$A1&lt;br /&gt;
&lt;br /&gt;
PlatformYBottomForBounceCheckLUT&lt;br /&gt;
 .byte $6D,$4A,$6A,$47,$2D,$34,$11&lt;br /&gt;
PlatformYTopForBounceCheckLUT&lt;br /&gt;
 .byte $9F,$A4,$82,$9D,$5F,$48,$6B&lt;br /&gt;
&lt;br /&gt;
PlatformXRightBounce  ; used to start low-approacing bird bouncing&lt;br /&gt;
 .byte $8B,$DB,$52,$BB,$85,$3A,$CB&lt;br /&gt;
&lt;br /&gt;
; Platform information tables used by riderless bird figuring out which&lt;br /&gt;
; direction to start with to get to it's hatched rider.&lt;br /&gt;
PlatformTopCoordinate&lt;br /&gt;
 .byte $32,$3A,$62,$6A,$7A,$AA,$AA&lt;br /&gt;
PlatformLeftsideCoordinate&lt;br /&gt;
 .byte $A8,$4E,$8D,$AB,$4D,$3C,$A4&lt;br /&gt;
PlatformRightsideCoordinate&lt;br /&gt;
 .byte $C0,$65,$9D,$C0,$89,$70,$C0&lt;br /&gt;
&lt;br /&gt;
; Doesn't seem to be referenced during play, even indirectly.&lt;br /&gt;
UnusedPterrySpawnYCoordLUT  &lt;br /&gt;
 .byte $15,$52,$52,$52,$52,$94,$94&lt;br /&gt;
&lt;br /&gt;
; Data for random egg placement during Egg Waves&lt;br /&gt;
NewEggXMaximum&lt;br /&gt;
 .byte $10,$0B,$27,$1D,$20,$12,$20,$59&lt;br /&gt;
NewEggXOffset&lt;br /&gt;
 .byte $AB,$23,$51,$90,$23,$AE,$5A,$45&lt;br /&gt;
NewEggYCoordinate&lt;br /&gt;
 .byte $32,$32,$3A,$62,$6A,$6A,$7A,$AA&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdatePlayerScoreAndBonus&lt;br /&gt;
; Adds a score value to the current player's score and checks for extra lives.&lt;br /&gt;
; Input: X = player index. Temp60/61/62 = score value to add.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdatePlayerScoreAndBonus&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDA P0Lives,X&lt;br /&gt;
  BMI FinalizeScoreUpdateAndExit&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE FinalizeScoreUpdateAndExit&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  TXA&lt;br /&gt;
  BNE UpdatePlayer1Score&lt;br /&gt;
  LDY #$02&lt;br /&gt;
  SED&lt;br /&gt;
  CLC&lt;br /&gt;
AddScoreToPlayer0Loop&lt;br /&gt;
  LDA.w Temp60,Y&lt;br /&gt;
  ADC.w P0Score,Y&lt;br /&gt;
  STA.w P0Score,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL AddScoreToPlayer0Loop&lt;br /&gt;
  TXA&lt;br /&gt;
  JSR CheckForPlayer0BonusLife&lt;br /&gt;
  JMP FinalizeScoreUpdateAndExit&lt;br /&gt;
UpdatePlayer1Score&lt;br /&gt;
  LDY #$02&lt;br /&gt;
  SED&lt;br /&gt;
  CLC&lt;br /&gt;
AddScoreToPlayer1Loop&lt;br /&gt;
  LDA.w Temp60,Y&lt;br /&gt;
  ADC.w P1Score,Y&lt;br /&gt;
  STA.w P1Score,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL AddScoreToPlayer1Loop&lt;br /&gt;
  TXA&lt;br /&gt;
  JSR CheckForPlayer1BonusLife&lt;br /&gt;
FinalizeScoreUpdateAndExit&lt;br /&gt;
  JSR UpdateScoreDisplay&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CheckForPlayer0BonusLife&lt;br /&gt;
  LDY #$01&lt;br /&gt;
  CLC&lt;br /&gt;
AddScoreToBonusLifeCounterLoop: LDA.w Temp61,Y&lt;br /&gt;
  ADC.w P0ExtraLifeScore,Y&lt;br /&gt;
  STA.w P0ExtraLifeScore,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL AddScoreToBonusLifeCounterLoop&lt;br /&gt;
  CLD&lt;br /&gt;
  LDA P0ExtraLifeScore&lt;br /&gt;
  BMI NoBonusLifeAwarded&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$80&lt;br /&gt;
  STA P0ExtraLifeScore&lt;br /&gt;
  JMP AwardBonusLife&lt;br /&gt;
NoBonusLifeAwarded&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CheckForPlayer1BonusLife&lt;br /&gt;
  LDY #$01&lt;br /&gt;
  CLC&lt;br /&gt;
AddScoreToP1BonusLifeCounterLoop&lt;br /&gt;
  LDA.w Temp61,Y&lt;br /&gt;
  ADC.w P1ExtraLifeScore,Y&lt;br /&gt;
  STA.w P1ExtraLifeScore,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL AddScoreToP1BonusLifeCounterLoop&lt;br /&gt;
  CLD&lt;br /&gt;
  LDA P1ExtraLifeScore&lt;br /&gt;
  BMI NoBonusLifeAwarded&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$80&lt;br /&gt;
  STA P1ExtraLifeScore&lt;br /&gt;
  JMP AwardBonusLife&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; InitPlayerLivesAndBonus&lt;br /&gt;
; Initializes lives and bonus score thresholds at the start of a game.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
InitPlayerLivesAndBonus&lt;br /&gt;
; Initializes the lives and bonus score for one or both players&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA P1Lives&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA P0Lives&lt;br /&gt;
  LDX PlayerCount&lt;br /&gt;
  BEQ InitPlayerLivesDone  ; leave P1Lives=FF for one player mode&lt;br /&gt;
  STA P1Lives&lt;br /&gt;
InitPlayerLivesDone&lt;br /&gt;
  LDA #$80&lt;br /&gt;
  STA P0ExtraLifeScore&lt;br /&gt;
  STA P1ExtraLifeScore&lt;br /&gt;
  ASL&lt;br /&gt;
  STA P0ExtraLifeScore+1&lt;br /&gt;
  STA P1ExtraLifeScore+1&lt;br /&gt;
EarlyReturn3&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DeadPlayerChecks&lt;br /&gt;
; Handles the logic when a player dies: decrements lives, checks for game over.&lt;br /&gt;
; Input: X = player index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DeadPlayerChecks&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA LevelWasSurvived       ; No survival points if you die.&lt;br /&gt;
  STA P0EggPointLevel,X&lt;br /&gt;
  DEC P0Lives,X              ; Lose a life and return&lt;br /&gt;
  LDA P0Lives,X              ; only if you have more.&lt;br /&gt;
  BPL EarlyReturn3&lt;br /&gt;
  LDA P0Lives                ; when both player lives are zero, we skip&lt;br /&gt;
  EOR P1Lives                ; over player death notifications, and &lt;br /&gt;
  BEQ SkipPlayerGameOverMsg  ; instead display &amp;quot;thy game is over&amp;quot;&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE EarlyReturn3&lt;br /&gt;
  TXA&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$08                   ; game message 8=&amp;quot;player one&amp;quot;, 9=&amp;quot;player two&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  LDA #$0A                   ; &amp;quot;game over&amp;quot;&lt;br /&gt;
  JMP DisplayGameMessage&lt;br /&gt;
SkipPlayerGameOverMsg&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE EarlyReturn3&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameActiveFlag&lt;br /&gt;
  LDA #$0B                   ; &amp;quot;thy game is over&amp;quot;&lt;br /&gt;
  JMP DisplayGameMessage&lt;br /&gt;
AwardBonusLife&lt;br /&gt;
  LDA P0Lives,X&lt;br /&gt;
  CMP #$7F                   ; Maximum lives is $7F&lt;br /&gt;
  BEQ ScheduleFreeBirdSound&lt;br /&gt;
  INC P0Lives,X&lt;br /&gt;
  JSR UpdatePlayerLivesDisplayed&lt;br /&gt;
ScheduleFreeBirdSound&lt;br /&gt;
  LDA #SFX_FreeBird&lt;br /&gt;
  JMP ScheduleSFX&lt;br /&gt;
UpdateScoreDisplay&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  TAX&lt;br /&gt;
UpdateScoreDisplayP0HandleLeadingZeros&lt;br /&gt;
  LDA P0Score,X&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  BNE UpdateScoreDisplayP0ProcessDigit&lt;br /&gt;
  JSR AddSpaceToScoreHudString&lt;br /&gt;
  LDA P0Score,X&lt;br /&gt;
  AND #$0F&lt;br /&gt;
  BNE UpdateScoreDisplayP0ProcessUnitsDigit&lt;br /&gt;
  JSR AddSpaceToScoreHudString&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$03&lt;br /&gt;
  BMI UpdateScoreDisplayP0HandleLeadingZeros&lt;br /&gt;
  JMP FinalizeP0ScoreDisplay&lt;br /&gt;
UpdateScoreDisplayP0Loop&lt;br /&gt;
  LDA P0Score,X&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
UpdateScoreDisplayP0ProcessDigit&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  LDA P0Score,X&lt;br /&gt;
  AND #$0F&lt;br /&gt;
UpdateScoreDisplayP0ProcessUnitsDigit&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$03&lt;br /&gt;
  BMI UpdateScoreDisplayP0Loop&lt;br /&gt;
FinalizeP0ScoreDisplay&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  LDA PlayerCount&lt;br /&gt;
  BNE UpdatePlayer1ScoreDisplay&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
UpdatePlayer1ScoreDisplay&lt;br /&gt;
  LDA #$0D&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDX #$00&lt;br /&gt;
UpdateScoreDisplayP1HandleLeadingZeros&lt;br /&gt;
  LDA P1Score,X&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  BNE UpdateScoreDisplayP1ProcessDigit&lt;br /&gt;
  JSR AddSpaceToScoreHudString&lt;br /&gt;
  LDA P1Score,X&lt;br /&gt;
  AND #$0F&lt;br /&gt;
  BNE UpdateScoreDisplayP1ProcessUnitsDigit&lt;br /&gt;
  JSR AddSpaceToScoreHudString&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$03&lt;br /&gt;
  BMI UpdateScoreDisplayP1HandleLeadingZeros&lt;br /&gt;
  BPL FinalizeP1ScoreDisplay&lt;br /&gt;
UpdateScoreDisplayP1Loop&lt;br /&gt;
  LDA P1Score,X&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
UpdateScoreDisplayP1ProcessDigit&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0C&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  LDA P1Score,X&lt;br /&gt;
  AND #$0F&lt;br /&gt;
UpdateScoreDisplayP1ProcessUnitsDigit&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0C&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$03&lt;br /&gt;
  BMI UpdateScoreDisplayP1Loop&lt;br /&gt;
FinalizeP1ScoreDisplay&lt;br /&gt;
  LDA #$0C&lt;br /&gt;
  BNE AddCharToScoreHudString&lt;br /&gt;
&lt;br /&gt;
UpdatePlayerLivesDisplayed&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE UpdatePlayerLivesExit&lt;br /&gt;
  LDA HudPlayerLivesStartXOffsetLUT,X&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDY #$03&lt;br /&gt;
DrawPlayerLivesLoop&lt;br /&gt;
  TYA&lt;br /&gt;
  CMP P0Lives,X&lt;br /&gt;
  BPL DrawEmptyLifeSlot&lt;br /&gt;
  LDA HudPlayerLifeIconCharLUT,X&lt;br /&gt;
  JSR AddCharToScoreHudString&lt;br /&gt;
  JMP UpdatePlayerLivesContinueLoop&lt;br /&gt;
DrawEmptyLifeSlot&lt;br /&gt;
  JSR AddSpaceToScoreHudString&lt;br /&gt;
UpdatePlayerLivesContinueLoop&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL DrawPlayerLivesLoop&lt;br /&gt;
UpdatePlayerLivesExit&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HudPlayerLifeIconCharLUT&lt;br /&gt;
 .byte $0B,$16  ; Character codes for P0 and P1 life icons&lt;br /&gt;
HudPlayerLivesStartXOffsetLUT&lt;br /&gt;
 .byte $07,$14  ; Start offsets in HUD buffer for P0 and P1 lives&lt;br /&gt;
&lt;br /&gt;
AddSpaceToScoreHudString&lt;br /&gt;
  LDA #$00 ; character index for space&lt;br /&gt;
AddCharToScoreHudString&lt;br /&gt;
  STY Temp5F&lt;br /&gt;
  LDY Temp5E&lt;br /&gt;
  STA HudDisplayStringBuffer,Y&lt;br /&gt;
  LDY Temp5F&lt;br /&gt;
  INC Temp5E&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DisplayGameMessage&lt;br /&gt;
; Schedules a message to be displayed on screen.&lt;br /&gt;
; Input: A = message index&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DisplayGameMessage&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDA Temp69&lt;br /&gt;
  TAX&lt;br /&gt;
  LDY MessageLineNumber,X&lt;br /&gt;
  LDA Temp69&lt;br /&gt;
  STA $2038,Y&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; ManageMessageTimers&lt;br /&gt;
; Manages the timers for on-screen messages, clearing them when they expire.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
ManageMessageTimers&lt;br /&gt;
  LDX #$03&lt;br /&gt;
UpdateMessageDisplayTimers&lt;br /&gt;
  LDA $2038,X&lt;br /&gt;
  BMI ManageMessageTimersCheckNextLine&lt;br /&gt;
  LDA MessageLine0Timer,X&lt;br /&gt;
  BPL ManageMessageTimersCheckNextLine&lt;br /&gt;
  LDA $2038,X&lt;br /&gt;
  JSR DisplayMessageAndSetTimer&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA $2038,X&lt;br /&gt;
ManageMessageTimersCheckNextLine&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL UpdateMessageDisplayTimers&lt;br /&gt;
  LDX #$03&lt;br /&gt;
ClearExpiredMessageTimersLoop: LDA MessageLine0Timer,X&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BEQ CheckNextMessageTimer&lt;br /&gt;
  LDA MessageLine0Timer,X&lt;br /&gt;
  BMI CheckNextMessageTimer&lt;br /&gt;
  DEC MessageLine0Timer,X&lt;br /&gt;
  BNE CheckNextMessageTimer&lt;br /&gt;
  LDA MsgBufferLo,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA MsgBufferHi,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
  LDY #$0F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
ClearMessageBufferLoop&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL ClearMessageBufferLoop&lt;br /&gt;
CheckNextMessageTimer&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ClearExpiredMessageTimersLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DisplayMessageAndSetTimer&lt;br /&gt;
  STA Temp69&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDX Temp69&lt;br /&gt;
  LDA MessageLineNumber,X&lt;br /&gt;
  TAX&lt;br /&gt;
  LDY Temp69&lt;br /&gt;
  LDA MessageDisplayTime,Y&lt;br /&gt;
  STA MessageLine0Timer,X&lt;br /&gt;
  JSR UpdateDLWithMessageString&lt;br /&gt;
  LDA Temp69&lt;br /&gt;
  BNE FinishDisplayingMessage&lt;br /&gt;
  TAX&lt;br /&gt;
  TAY&lt;br /&gt;
  JSR UpdateDLWithMessageString&lt;br /&gt;
  LDA LevelBCD&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  BEQ DisplayWaveNumberProcessUnitsDigit&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0C&lt;br /&gt;
  STA HudWaveNumberDigit1&lt;br /&gt;
DisplayWaveNumberProcessUnitsDigit&lt;br /&gt;
  LDA LevelBCD&lt;br /&gt;
  AND #$0F&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0C&lt;br /&gt;
  STA HudWaveNumberDigit2&lt;br /&gt;
FinishDisplayingMessage&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
UpdateDLWithMessageString&lt;br /&gt;
  LDA MsgBufferLo,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA MsgBufferHi,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
  TYA&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL  ; A = Y * 16&lt;br /&gt;
  PHP&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #&amp;lt;GameMessages&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  BCC AddHiByteWithNoCarry&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  BNE FinalizeMessagePointerHiByte&lt;br /&gt;
AddHiByteWithNoCarry&lt;br /&gt;
  LDA #$00&lt;br /&gt;
FinalizeMessagePointerHiByte&lt;br /&gt;
  PLP&lt;br /&gt;
  ADC #&amp;gt;GameMessages&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDY #$0F&lt;br /&gt;
CopyMessageStringToBufferLoop&lt;br /&gt;
  LDA (Temp5E),Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL CopyMessageStringToBufferLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
MessageLineNumber&lt;br /&gt;
 .byte 0,2,3,1,1,1,1,1,2,2,3,2,1,1,1,2,1,1,1&lt;br /&gt;
&lt;br /&gt;
MessageDisplayTime&lt;br /&gt;
 .byte $3C, $46, $28, $3C, $3C, $3C, $3C, $3C&lt;br /&gt;
 .byte $3C, $3C, $3C, $F0, $3C, $3C, $3C, $3C&lt;br /&gt;
 .byte $3C, $3C, $3C &lt;br /&gt;
&lt;br /&gt;
MsgBufferLo&lt;br /&gt;
 .byte &amp;lt;$2671 &lt;br /&gt;
 .byte &amp;lt;$2685 &lt;br /&gt;
 .byte &amp;lt;$2699 &lt;br /&gt;
 .byte &amp;lt;$26AD &lt;br /&gt;
&lt;br /&gt;
MsgBufferHi&lt;br /&gt;
 .byte &amp;gt;$2671 &lt;br /&gt;
 .byte &amp;gt;$2685 &lt;br /&gt;
 .byte &amp;gt;$2699 &lt;br /&gt;
 .byte &amp;gt;$26AD &lt;br /&gt;
&lt;br /&gt;
GameMessages&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
            ; &amp;quot;WAVE&amp;quot;&lt;br /&gt;
 .byte $29  ; 'W' &lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
            ; &amp;quot;PREPARE TO JOUST&amp;quot;&lt;br /&gt;
 .byte $23  ; 'P' &lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $23  ; 'P'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1F  ; 'J' &lt;br /&gt;
 .byte $0C  ; '0' &lt;br /&gt;
 .byte $27  ; 'U' &lt;br /&gt;
 .byte $25  ; 'S' &lt;br /&gt;
 .byte $26  ; 'T' &lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
            ; &amp;quot;BUZZARD BAIT&amp;quot;&lt;br /&gt;
 .byte $18  ; 'B' &lt;br /&gt;
 .byte $27  ; 'U'&lt;br /&gt;
 .byte $2C  ; 'Z'&lt;br /&gt;
 .byte $2C  ; 'Z'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $18  ; 'B' &lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
            ; &amp;quot;EGG WAVE&amp;quot;&lt;br /&gt;
 .byte $1B  ; 'E' &lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $29  ; 'W'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1C  ; 'G' &lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $0C  ; 'O'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $29  ; 'W' &lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $23  ; 'P' &lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $2B  ; 'Y'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $29  ; 'W' &lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $25  ; 'S' &lt;br /&gt;
 .byte $27  ; 'U'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $29  ; 'W' &lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $29  ; 'W'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $23  ; 'P'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $2B  ; 'Y'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0D  ; '1'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $23  ; 'P'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $2B  ; 'Y'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0E  ; '2'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $1D  ; 'H'&lt;br /&gt;
 .byte $2B  ; 'Y'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $25  ; 'S'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0F  ; '3'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $25  ; 'S'&lt;br /&gt;
 .byte $27  ; 'U'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0F  ; '3'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00  ;&lt;br /&gt;
 .byte $00  ;&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $0F  ; '3'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $23  ; 'P'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $22  ; 'N'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $25  ; 'S'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $29  ; 'W'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $22  ; 'N'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $25  ; 'S'&lt;br /&gt;
 .byte $27  ; 'U'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $28  ; 'V'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $22  ; 'N'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $22  ; 'N'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1C  ; 'G'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $1A  ; 'D'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $0C  ; 'O'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
StringCopyright&lt;br /&gt;
 .byte $2E  ; 1/2 (c) symbol&lt;br /&gt;
 .byte $2F  ; 1/2 (c) symbol&lt;br /&gt;
 .byte $00  ; ' '&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $00  ; ' '&lt;br /&gt;
 .byte $0D  ; '1'&lt;br /&gt;
 .byte $15  ; '9'&lt;br /&gt;
 .byte $14  ; '8'&lt;br /&gt;
 .byte $10  ; '4' &lt;br /&gt;
 .byte $2E  ; 1/2 (c) symbol&lt;br /&gt;
 .byte $2F  ; 1/2 (c) symbol&lt;br /&gt;
 .byte $00  ; ' '&lt;br /&gt;
 .byte $29  ; 'W'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $1E  ; 'I'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $21  ; 'M'&lt;br /&gt;
 .byte $25  ; 'S'&lt;br /&gt;
 .byte $00  ; ' '&lt;br /&gt;
 .byte $0D  ; '1'&lt;br /&gt;
 .byte $15  ; '9'&lt;br /&gt;
 .byte $14  ; '8'&lt;br /&gt;
 .byte $0E  ; '2'&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DisplayRoutineInit&lt;br /&gt;
; Initializes the working Display List pointers in RAM ($242B/$2443)&lt;br /&gt;
; from the master pointers in ROM. It then proceeds to build the render list&lt;br /&gt;
; for the current frame by processing all active game objects.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DisplayRoutineInit&lt;br /&gt;
  LDX #$17  ; 24 DLs&lt;br /&gt;
InitializeDisplayListPointers&lt;br /&gt;
  LDA DisplayListLoLUT,X&lt;br /&gt;
  STA DisplayListLo,X&lt;br /&gt;
  LDA DisplayListHiLUT,X&lt;br /&gt;
  STA DisplayListHi,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL InitializeDisplayListPointers&lt;br /&gt;
&lt;br /&gt;
; loop through all of the birds...&lt;br /&gt;
  LDY #$09&lt;br /&gt;
RenderBirdObjectsLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ RenderNextBird      ; if state is dead then skip&lt;br /&gt;
  CMP #$03                ; if state is born1&lt;br /&gt;
  BEQ RenderNextBird      ; then skip&lt;br /&gt;
  JSR PrepareBirdSpriteForRenderList&lt;br /&gt;
  LDA GameObjectInAir,Y&lt;br /&gt;
  BNE RenderAirborneBirdRider&lt;br /&gt;
  JSR PrepareOnPlatformBirdSprite&lt;br /&gt;
RenderAirborneBirdRider&lt;br /&gt;
  LDA.w GameObjectAlive,Y&lt;br /&gt;
  BEQ RenderNextBird&lt;br /&gt;
  JSR PrepareRiderOnBirdSpriteForRenderList&lt;br /&gt;
RenderNextBird&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RenderBirdObjectsLoop&lt;br /&gt;
&lt;br /&gt;
; loop through all of the pterrys...&lt;br /&gt;
  LDY #$02&lt;br /&gt;
RenderPterryObjectsLoop&lt;br /&gt;
  LDA.w PterryState1,Y&lt;br /&gt;
  BEQ RenderNextPterry&lt;br /&gt;
  JSR PreparePterrySpriteForRenderList&lt;br /&gt;
RenderNextPterry&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RenderPterryObjectsLoop&lt;br /&gt;
&lt;br /&gt;
; loop through all of the eggs...&lt;br /&gt;
  LDY #$0B&lt;br /&gt;
RenderEggObjectsLoop&lt;br /&gt;
  LDA.w EggState,Y&lt;br /&gt;
  BEQ RenderNextEggObject&lt;br /&gt;
  JSR PrepareEggSpriteForRenderList&lt;br /&gt;
RenderNextEggObject&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RenderEggObjectsLoop&lt;br /&gt;
&lt;br /&gt;
; loop through all of the player birds...&lt;br /&gt;
  LDY #$01&lt;br /&gt;
RenderPlayerDeathExplosionLoop&lt;br /&gt;
  LDA.w P0DeathState,Y&lt;br /&gt;
  BEQ RenderNextPlayerDeathExplosion&lt;br /&gt;
  JSR PreparePlayerExplosionSpriteForRenderList&lt;br /&gt;
RenderNextPlayerDeathExplosion&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RenderPlayerDeathExplosionLoop&lt;br /&gt;
&lt;br /&gt;
  LDY #$05&lt;br /&gt;
RenderDissolvingPlatformObjectsLoop&lt;br /&gt;
  LDA PlatformDissolveAnimationFlag0,Y&lt;br /&gt;
  BEQ RenderNextDissolvingParticle&lt;br /&gt;
  JSR PrepareDissolvingPlatformParticleForRenderList&lt;br /&gt;
RenderNextDissolvingParticle&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL RenderDissolvingPlatformObjectsLoop&lt;br /&gt;
  LDA TrollState&lt;br /&gt;
  BEQ RenderTrollIfVisible      ; Troll hiding in lava?&lt;br /&gt;
  JSR PrepareTrollSpriteForRenderList&lt;br /&gt;
RenderTrollIfVisible&lt;br /&gt;
  STX RenderListCount&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA RenderListDirty&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PrepareTrollSpriteForRenderList&lt;br /&gt;
  LDA TrollGfxOffset&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA TrollXCoord&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$9A&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA TrollYCoord&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  LDY TrollTargetIndex&lt;br /&gt;
  CPY #$01&lt;br /&gt;
  BNE StoreTrollSpriteYCoord&lt;br /&gt;
  SBC #$02&lt;br /&gt;
StoreTrollSpriteYCoord&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
PrepareDissolvingPlatformParticleForRenderList&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$78&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$1C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA PlatformDissolveAnimationXCoord0,Y&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$A1&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA PlatformDissolveAnimationYCoord0,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
PreparePlayerExplosionSpriteForRenderList&lt;br /&gt;
  LDA.w P0DeathState,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  ASL&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$70&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$7E&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA.w PlayerExplosionXCoord,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$A2&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA.w PlayerExplosionYCoord,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
&lt;br /&gt;
; This appears to be dead menu code. Apparently at one point in development&lt;br /&gt;
; changing menu options would update the DL with the relevant character object.&lt;br /&gt;
; This was abandoned for the current character-buffer update system.&lt;br /&gt;
  STY Temp65&lt;br /&gt;
  LDA #$8F&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$27&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA UNUSED_TitleMenuTextAddrLoLUT,Y&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA UNUSED_TitleMenuTextAddrHiLUT,Y&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA UNUSED_TitleMenuDLZoneLUT,Y&lt;br /&gt;
  TAY&lt;br /&gt;
  JSR UpdateRenderList&lt;br /&gt;
  LDY Temp65&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PreparePterrySpriteForRenderList&lt;br /&gt;
  LDA $2344,Y ; pterry direction&lt;br /&gt;
  BMI SetPterryBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$44&lt;br /&gt;
  JMP StorePterryBaseGfxAndContinue&lt;br /&gt;
SetPterryBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$2C&lt;br /&gt;
StorePterryBaseGfxAndContinue&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA $236A,Y ; pterry animation frame&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ADC Temp5EGfxDataLo&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  STX Temp61&lt;br /&gt;
  LDA $236A,Y&lt;br /&gt;
  TAX&lt;br /&gt;
  LDA PterrySpritePaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDX Temp61&lt;br /&gt;
  LDA $015E,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$9A&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA $0177,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
PrepareEggSpriteForRenderList&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BEQ PrepareRiderSpriteForRenderList&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BEQ PrepareRiderSpriteForRenderList&lt;br /&gt;
  LDA $221B,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$80&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA EggX,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$9F&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$A4&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA EggY,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$0F&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
PrepareRiderSpriteForRenderList&lt;br /&gt;
  LDA.w EggState,Y&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BNE RenderHatchedRiderSprite&lt;br /&gt;
  LDA #$CB&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$C0&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$9E&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA EggX,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$21&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA EggY,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$0C&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STY TempCollisionOverlap&lt;br /&gt;
  TAY&lt;br /&gt;
  JSR UpdateRenderList&lt;br /&gt;
  LDY TempCollisionOverlap&lt;br /&gt;
RenderHatchedRiderSprite&lt;br /&gt;
  LDA EggLevelAndType,Y&lt;br /&gt;
  ASL&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$58&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$C0&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA #$5E&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA EggX,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA EggY,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$0C&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STY TempCollisionOverlap&lt;br /&gt;
  TAY&lt;br /&gt;
  JSR UpdateRenderList&lt;br /&gt;
  LDY TempCollisionOverlap&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PrepareRiderOnBirdSpriteForRenderList&lt;br /&gt;
  LDA RiderObjectPaletteAndWidth,Y&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA GameObjectDirection,Y&lt;br /&gt;
  BMI SetRiderBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$5E&lt;br /&gt;
  JMP StoreRiderBaseGfxAndContinue&lt;br /&gt;
SetRiderBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$5C&lt;br /&gt;
StoreRiderBaseGfxAndContinue&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  CPY #$02&lt;br /&gt;
  BCS CalculateEnemyRiderGfxOffset    ; branch if non-player enemy bird&lt;br /&gt;
  TYA&lt;br /&gt;
  JMP CalculateFinalRiderGfxPointer&lt;br /&gt;
CalculateEnemyRiderGfxOffset&lt;br /&gt;
  LDA ObjectBirdLevelAndType,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02&lt;br /&gt;
CalculateFinalRiderGfxPointer&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ADC Temp5EGfxDataLo&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC GameObjectDirection,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDA #$A1&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$0F&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
  JMP AddSpriteToRenderList&lt;br /&gt;
PrepareOnPlatformBirdSprite&lt;br /&gt;
  STX TempCollisionOverlap&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  CMP #$06                            ; invincible&lt;br /&gt;
  BNE RenderBirdOnPlatform&lt;br /&gt;
  LDA BirdObjectPaletteAndWidth,Y&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA BirdSpawnGfxOffsetLUT,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  LDX GameObjectDirection,Y&lt;br /&gt;
  BMI SetSpawnGfxForLeftFacingBird&lt;br /&gt;
  ADC #$02&lt;br /&gt;
SetSpawnGfxForLeftFacingBird&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$05&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  AND #$07&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp64&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA Temp66&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  JMP FinalizeOnPlatformSpriteCoordsAndRender&lt;br /&gt;
&lt;br /&gt;
RenderBirdOnPlatform&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$AB&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA GameObjectFootstepAnimIndex,Y&lt;br /&gt;
  ASL&lt;br /&gt;
  LDX GameObjectDirection,Y&lt;br /&gt;
  BMI SelectLeftFacingWalkFrame&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0A&lt;br /&gt;
SelectLeftFacingWalkFrame&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$C4&lt;br /&gt;
  ADC BirdWalkCycleGfxOffsetLUT,Y&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$07&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA Temp66&lt;br /&gt;
FinalizeOnPlatformSpriteCoordsAndRender&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  LDX GameObjectDirection,Y&lt;br /&gt;
  CLC&lt;br /&gt;
  BMI SetLeftFacingOnPlatformSpriteXCoord&lt;br /&gt;
  ADC #$01&lt;br /&gt;
SetLeftFacingOnPlatformSpriteXCoord&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61SpriteXCoord&lt;br /&gt;
  LDX TempCollisionOverlap&lt;br /&gt;
  STY Temp65&lt;br /&gt;
  LDY Temp66&lt;br /&gt;
  JSR UpdateRenderList&lt;br /&gt;
  LDY Temp65&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PrepareBirdSpriteForRenderList&lt;br /&gt;
  STX TempCollisionOverlap&lt;br /&gt;
  LDA BirdObjectPaletteAndWidth,Y&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA GameObjectDirection,Y&lt;br /&gt;
  BMI SetBirdSpriteBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  JMP ContinuePrepareBirdSprite&lt;br /&gt;
SetBirdSpriteBaseGfxForLeftFacing&lt;br /&gt;
  LDA #$00&lt;br /&gt;
ContinuePrepareBirdSprite&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectInAir,Y&lt;br /&gt;
  BEQ SetOnPlatformAnimationOffset&lt;br /&gt;
  LDA GameObjectAnimationFrame,Y&lt;br /&gt;
  ASL&lt;br /&gt;
  JMP CalculateFinalBirdGfxPointer&lt;br /&gt;
SetOnPlatformAnimationOffset&lt;br /&gt;
  LDA #$04&lt;br /&gt;
CalculateFinalBirdGfxPointer&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5E&lt;br /&gt;
  ADC BirdGfxAnimationOffsetLUT,Y&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDX TempCollisionOverlap&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$20&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA #$9C&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  CMP #$F0&lt;br /&gt;
  BCC SkipClampYCoord&lt;br /&gt;
  LDA #$00&lt;br /&gt;
SkipClampYCoord&lt;br /&gt;
  STA Temp63SpriteYCoord&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; AddSpriteToRenderList&lt;br /&gt;
; Takes sprite parameters from ZP temps and adds one or more 8-pixel tall sprite&lt;br /&gt;
; slices to the render list. It handles breaking down taller sprites into&lt;br /&gt;
; multiple slices and calculating their positions in the Display List zones.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
AddSpriteToRenderList&lt;br /&gt;
  STY Temp65               ; save Y&lt;br /&gt;
  LDA Temp63SpriteYCoord&lt;br /&gt;
  AND #$07&lt;br /&gt;
  STA Temp64SpriteYOffset  ; Y offset in zone&lt;br /&gt;
  LDA Temp5FGfxDataHi&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp64SpriteYOffset&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDA Temp63SpriteYCoord&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  TAY                      ; Y is zone index for this sprite&lt;br /&gt;
AddAllSpriteSlicesToRenderListLoop&lt;br /&gt;
  JSR UpdateRenderList&lt;br /&gt;
  LDA Temp5FGfxDataHi&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$08&lt;br /&gt;
  CMP Temp62&lt;br /&gt;
  BCC FinishMultiSliceSpriteRender&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  INY&lt;br /&gt;
  JMP AddAllSpriteSlicesToRenderListLoop&lt;br /&gt;
FinishMultiSliceSpriteRender&lt;br /&gt;
  LDY Temp65               ; restore Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdateRenderList&lt;br /&gt;
; The core function that adds a single sprite slice to the render list arrays.&lt;br /&gt;
; It also decrements the pointer for the corresponding DL zone to make space.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdateRenderList&lt;br /&gt;
  CPY #$16&lt;br /&gt;
  BCS UpdateRenderList_Exit&lt;br /&gt;
  INX&lt;br /&gt;
  LDA Temp5EGfxDataLo&lt;br /&gt;
  STA RenderListGfxDataLo,X&lt;br /&gt;
  LDA Temp5FGfxDataHi&lt;br /&gt;
  STA RenderListGfxDataHi,X&lt;br /&gt;
  LDA Temp60PaletteAndWidth&lt;br /&gt;
  STA RenderListPaletteAndWidth,X&lt;br /&gt;
  LDA Temp61SpriteXCoord&lt;br /&gt;
  STA RenderListXCoord,X&lt;br /&gt;
&lt;br /&gt;
  LDA DisplayListLo,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$04&lt;br /&gt;
  STA DisplayListLo,Y&lt;br /&gt;
  STA RenderListDLLo,X&lt;br /&gt;
  LDA DisplayListHi,Y&lt;br /&gt;
  SBC #$00&lt;br /&gt;
  STA DisplayListHi,Y&lt;br /&gt;
  STA RenderListDLHi,X&lt;br /&gt;
UpdateRenderList_Exit&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; UpdateDLWithBackgroundSprites&lt;br /&gt;
; Initializes the static background elements of the Display Lists by copying&lt;br /&gt;
; data from ROM tables into their respective DL object locations in RAM.&lt;br /&gt;
; This sets up platforms, lava, and other non-interactive scenery.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
UpdateDLWithBackgroundSprites&lt;br /&gt;
  LDX #$20&lt;br /&gt;
BackgroundSpriteUpdateLoop&lt;br /&gt;
  LDA GameDLStartLutLo,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA GameDLStartLutHi,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
&lt;br /&gt;
  LDA BackgroundSpriteGfxLoLUT,X&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  LDA BackgroundSpritePaletteWidthLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  LDA BackgroundSpriteGfxHiLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  LDA BackgroundSpriteXCoordLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL BackgroundSpriteUpdateLoop&lt;br /&gt;
&lt;br /&gt;
  LDX #$05&lt;br /&gt;
UpdateDLWithMsgAndHUDCharObjects&lt;br /&gt;
  LDA HUDCharDLAddrLoLUT,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA HUDCharDLAddrHiLUT,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
&lt;br /&gt;
; DL byte 0&lt;br /&gt;
  LDA MsgAndHUDCharObjectStringLoLUT,X&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
&lt;br /&gt;
; DL byte 1&lt;br /&gt;
  LDA #$60 ; character mode&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
&lt;br /&gt;
; DL byte 2&lt;br /&gt;
  LDA MsgAndHUDCharObjectStringHiLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
&lt;br /&gt;
; DL byte 3&lt;br /&gt;
  LDA MsgAndHUDCharObjectPaletteAndWidthLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
&lt;br /&gt;
; DL byte 4&lt;br /&gt;
  LDA MsgAndHUDCharObjectXLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y&lt;br /&gt;
&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL UpdateDLWithMsgAndHUDCharObjects&lt;br /&gt;
&lt;br /&gt;
  LDA DisplayEasterEggFlag&lt;br /&gt;
  BEQ SkipEasterEggDisplaySetup&lt;br /&gt;
&lt;br /&gt;
  LDX #$0E&lt;br /&gt;
CopyEasterEggDataToRamLoop&lt;br /&gt;
  LDA EasterEggDisplayData,X&lt;br /&gt;
  STA $21FF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyEasterEggDataToRamLoop&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA $1FEF&lt;br /&gt;
SkipEasterEggDisplaySetup&lt;br /&gt;
  LDX #$09                            ; loop through all of the birds&lt;br /&gt;
InitializeBirdPalettesLoop&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA BirdObjectPaletteAndWidth,X&lt;br /&gt;
  LDA RiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA RiderObjectPaletteAndWidth,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL InitializeBirdPalettesLoop&lt;br /&gt;
; Initialize the working Display List pointers from the master ROM table&lt;br /&gt;
  LDX #$17&lt;br /&gt;
InitializeWorkDLPointerLoop&lt;br /&gt;
  LDA DisplayListLoLUT,X&lt;br /&gt;
  STA DisplayListLo,X&lt;br /&gt;
  LDA DisplayListHiLUT,X&lt;br /&gt;
  STA DisplayListHi,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL InitializeWorkDLPointerLoop&lt;br /&gt;
  LDX #$00&lt;br /&gt;
  LDY #$00&lt;br /&gt;
CopyWorkDLToFinalDLLLoop&lt;br /&gt;
  LDA DisplayListHi,X&lt;br /&gt;
  STA $275E,Y&lt;br /&gt;
  LDA DisplayListLo,X&lt;br /&gt;
  STA $275F,Y&lt;br /&gt;
  INY&lt;br /&gt;
  INY&lt;br /&gt;
  INY&lt;br /&gt;
  INX&lt;br /&gt;
  CPX #$18&lt;br /&gt;
  BNE CopyWorkDLToFinalDLLLoop&lt;br /&gt;
  LDX #$18&lt;br /&gt;
InitializeScorePopupJumpTable&lt;br /&gt;
  LDA ReturnFromScorePopupCreation,X&lt;br /&gt;
  STA $27B2,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE InitializeScorePopupJumpTable&lt;br /&gt;
EasterEggDisplayData&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; easter egg data&lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $29 &lt;br /&gt;
 .byte $21 &lt;br /&gt;
 .byte $26 &lt;br /&gt;
 .byte $21 &lt;br /&gt;
 .byte $FD &lt;br /&gt;
 .byte $1B &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $21 &lt;br /&gt;
 .byte $23 &lt;br /&gt;
 .byte $23 &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $23 &lt;br /&gt;
 .byte $1C &lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetupTitleScrDLs&lt;br /&gt;
; Initializes all Display List objects specifically for the title screen.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetupTitleScrDLs&lt;br /&gt;
  LDX #$50&lt;br /&gt;
SetupTitleScrCharacterDLs&lt;br /&gt;
; destination memory for next DL object...&lt;br /&gt;
  LDA TitleScrDLAddrLoLUT,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA TitleScrDLAddrHiLUT,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrCharObject_LoAddress,X&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  STA (TempPointLo5A),Y                   ; Byte 0: Lo Address&lt;br /&gt;
&lt;br /&gt;
  LDA #$60                                ; Indirect/Character Object&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                   ; Byte 1: Mode&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrCharObject_HiAddress,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                   ; Byte 2: Hi Address&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrCharObject_PalleteWidth,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                   ; Byte 3: Palette+Width&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrCharObject_XCoordinate,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                   ; Byte 4: X Coordinate&lt;br /&gt;
&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SetupTitleScrCharacterDLs&lt;br /&gt;
&lt;br /&gt;
  LDX #$0C&lt;br /&gt;
SetupTitleScrSpriteDLs&lt;br /&gt;
; destination memory for next DL object...&lt;br /&gt;
  LDA TitleScrCharacterObjectLoLUT,X&lt;br /&gt;
  STA TempPointLo5A&lt;br /&gt;
  LDA TitleScrCharacterObjectHiLUT,X&lt;br /&gt;
  STA TempPointHi5B&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrSpriteObjectLoLUT,X&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  STA (TempPointLo5A),Y                    ; Byte 0: Lo Address&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrSpriteObject_PaletteWidth,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                    ; Byte 1: Palette+Width&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrSpriteObjectHiLUT,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                    ; Byte 2: Hi Address&lt;br /&gt;
&lt;br /&gt;
  LDA TitleScrSpriteObject_XCoordinate,X&lt;br /&gt;
  INY&lt;br /&gt;
  STA (TempPointLo5A),Y                    ; Byte 3: X Coordinate&lt;br /&gt;
&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SetupTitleScrSpriteDLs&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; SetColorRegisters&lt;br /&gt;
; Copies the 24-byte color palette from RAM ($0190) to the hardware color&lt;br /&gt;
; registers ($20-$3F) every frame.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
SetColorRegisters&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA BACKGRND&lt;br /&gt;
  LDA PaletteInRam+$00&lt;br /&gt;
  STA P0C1&lt;br /&gt;
  LDA PaletteInRam+$01&lt;br /&gt;
  STA P0C2&lt;br /&gt;
  LDA PaletteInRam+$02&lt;br /&gt;
  STA P0C3&lt;br /&gt;
  LDA PaletteInRam+$03&lt;br /&gt;
  STA P1C1&lt;br /&gt;
  LDA PaletteInRam+$04&lt;br /&gt;
  STA P1C2&lt;br /&gt;
  LDA PaletteInRam+$05&lt;br /&gt;
  STA P1C3&lt;br /&gt;
  LDA PaletteInRam+$06&lt;br /&gt;
  STA P2C1&lt;br /&gt;
  LDA PaletteInRam+$07&lt;br /&gt;
  STA P2C2&lt;br /&gt;
  LDA PaletteInRam+$08&lt;br /&gt;
  STA P2C3&lt;br /&gt;
  LDA PaletteInRam+$09&lt;br /&gt;
  STA P3C1&lt;br /&gt;
  LDA PaletteInRam+$0A&lt;br /&gt;
  STA P3C2&lt;br /&gt;
  LDA PaletteInRam+$0B&lt;br /&gt;
  STA P3C3&lt;br /&gt;
  LDA PaletteInRam+$0C&lt;br /&gt;
  STA P4C1&lt;br /&gt;
  LDA PaletteInRam+$0D&lt;br /&gt;
  STA P4C2&lt;br /&gt;
  LDA PaletteInRam+$0E&lt;br /&gt;
  STA P4C3&lt;br /&gt;
  LDA PaletteInRam+$0F&lt;br /&gt;
  STA P5C1&lt;br /&gt;
  LDA PaletteInRam+$10&lt;br /&gt;
  STA P5C2&lt;br /&gt;
  LDA PaletteInRam+$11&lt;br /&gt;
  STA P5C3&lt;br /&gt;
  LDA PaletteInRam+$12&lt;br /&gt;
  STA P6C1&lt;br /&gt;
  LDA PaletteInRam+$13&lt;br /&gt;
  STA P6C2&lt;br /&gt;
  LDA PaletteInRam+$14&lt;br /&gt;
  STA P6C3&lt;br /&gt;
  LDA PaletteInRam+$15&lt;br /&gt;
  STA P7C1&lt;br /&gt;
  LDA PaletteInRam+$16&lt;br /&gt;
  STA P7C2&lt;br /&gt;
  LDA PaletteInRam+$17&lt;br /&gt;
  STA P7C3&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; well, how did I get here?&lt;br /&gt;
; (clear the HUD display string buffer)&lt;br /&gt;
  LDX #$67&lt;br /&gt;
  LDA #$00&lt;br /&gt;
ClearHudDisplayStringBuffer&lt;br /&gt;
  STA HudDisplayStringBuffer,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ClearHudDisplayStringBuffer&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
InitializeFinalDisplayListPointers&lt;br /&gt;
  LDX #$56&lt;br /&gt;
CopyFinalDllPointersLoop&lt;br /&gt;
  LDA DllLUT,X&lt;br /&gt;
  STA $2700,X&lt;br /&gt;
  STA $2757,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL CopyFinalDllPointersLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; CreateScorePopupAtObjectLocation&lt;br /&gt;
; Creates a score popup (e.g., &amp;quot;500&amp;quot;) at a specified location. It finds an&lt;br /&gt;
; available popup slot and initializes its timer, position, and character value.&lt;br /&gt;
; Input: Temp5E/Temp5F = Y/X coordinates. Temp60 = score value index.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
CreateScorePopupAtObjectLocation&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDX #$0B&lt;br /&gt;
FindAvailableScorePopupSlot&lt;br /&gt;
  LDA $26C4,X&lt;br /&gt;
  BEQ FoundAvailableScorePopupSlotInitialize&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL FindAvailableScorePopupSlot&lt;br /&gt;
  LDX #$0B&lt;br /&gt;
FoundAvailableScorePopupSlotInitialize&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA $26C4,X&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$10&lt;br /&gt;
  BPL CalculateScorePopupZone&lt;br /&gt;
  CMP #$E0&lt;br /&gt;
  BCC CalculateScorePopupZone&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$12&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
CalculateScorePopupZone&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA $26DC,X&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$26&lt;br /&gt;
  CMP #$91&lt;br /&gt;
  BCC StoreClampedScorePopupXCoord&lt;br /&gt;
  CMP #$C0&lt;br /&gt;
  BCC ClampScorePopupXTooFarRight&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  BEQ StoreClampedScorePopupXCoord&lt;br /&gt;
ClampScorePopupXTooFarRight&lt;br /&gt;
  LDA #$90&lt;br /&gt;
StoreClampedScorePopupXCoord&lt;br /&gt;
  STA $26D0,X&lt;br /&gt;
  LDY Temp60&lt;br /&gt;
  LDA ScorePopupValues,Y&lt;br /&gt;
  STA $26E8,X&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
ReturnFromScorePopupCreation&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; Data for score popups&lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $13 &lt;br /&gt;
&lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
&lt;br /&gt;
ScorePopupValues  ; scores 250, 500, 750, ...&lt;br /&gt;
 .byte $B3 &lt;br /&gt;
 .byte $B7 &lt;br /&gt;
 .byte $BB &lt;br /&gt;
 .byte $BF &lt;br /&gt;
 .byte $C3 &lt;br /&gt;
 .byte $C7 &lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; NMI_ROUTINE&lt;br /&gt;
; Non-Maskable Interrupt handler. This is the heart of the game's frame-by-frame&lt;br /&gt;
; processing. It is responsible for sound, input, palette updates, and, most&lt;br /&gt;
; importantly, processing the render list to update the hardware display lists.&lt;br /&gt;
; It supports three modes via NMIModeFlag:&lt;br /&gt;
;     $00: Normal in-game processing.&lt;br /&gt;
;     $01: Title screen, 160A mode (left/right borders).&lt;br /&gt;
;     $FF: Title screen, 320A mode (central logo area).&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
NMI_ROUTINE&lt;br /&gt;
NMI_SaveRegisters&lt;br /&gt;
  PHA                                     ; Save A&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA                                     ; Save X&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA                                     ; Save Y&lt;br /&gt;
&lt;br /&gt;
  LDA NMIModeFlag                         ; Check current NMI mode&lt;br /&gt;
  BEQ NMI_ProcessNormalGame               ; If $00, handle normal game NMI&lt;br /&gt;
  BMI NMI_ProcessSplitScreen_320A_Mode    ; If $FF (negative), handle 320A part of split screen&lt;br /&gt;
&lt;br /&gt;
; This is the 160A portion of the title screen's split-screen rendering.&lt;br /&gt;
; It handles the scrolling borders on the left and right.&lt;br /&gt;
NMI_ProcessSplitScreen_160A_Mode          ; NMIModeFlag was $01&lt;br /&gt;
  LDA #CTRL_DMA_ON_160AB                  ; Set CTRL for 160A mode (normal width pixels)&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  JSR CycleTitleScreenPaletteAndCounters  ; Update title screen colors and border animation&lt;br /&gt;
  LDA #NMIMode_SplitScreen320A            ; Set flag for the *next* NMI to be the 320A part&lt;br /&gt;
  STA NMIModeFlag&lt;br /&gt;
  JMP NMI_ExitAndRestoreRegisters&lt;br /&gt;
&lt;br /&gt;
; This is the 320A portion of the title screen's split-screen rendering.&lt;br /&gt;
; It handles the central logo area with double-width pixels.&lt;br /&gt;
NMI_ProcessSplitScreen_320A_Mode          ; NMIModeFlag was $FF&lt;br /&gt;
  STA WSYNC                               ; Wait until the end of the line&lt;br /&gt;
  STA WSYNC                               ; Wait until the end of the line&lt;br /&gt;
  LDA #CTRL_DMA_ON_320AC                  ; Set CTRL for 320A mode (double-width pixels)&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  LDA #NMIMode_SplitScreen160A            ; Set flag for the *next* NMI to be the 160A part&lt;br /&gt;
  STA NMIModeFlag&lt;br /&gt;
  JMP NMI_ExitAndRestoreRegisters&lt;br /&gt;
&lt;br /&gt;
; This is the main NMI handler for gameplay and demo mode.&lt;br /&gt;
NMI_ProcessNormalGame&lt;br /&gt;
  JSR ServiceSFX                          ; Process active sound effects&lt;br /&gt;
&lt;br /&gt;
; Read Player 0 Fire Button with a one-frame debounce.&lt;br /&gt;
; P0LastFire holds the state from the previous NMI, P0CurrentFire holds this NMI's state.&lt;br /&gt;
; This prevents a single press from being registered on multiple consecutive frames.&lt;br /&gt;
  LDA INPT4                               ; Read Player 0 input port&lt;br /&gt;
  AND #Input_FireButtonMask               ; Isolate fire button bit&lt;br /&gt;
  CMP P0LastFire                          ; Compare with last latched state&lt;br /&gt;
  BEQ NMI_P0_Fire_NoChange                ; If same, no change in press state&lt;br /&gt;
  STA P0LastFire                          ; New state, update P0LastFire&lt;br /&gt;
  BNE NMI_P0_Fire_StoreCurrent            ; If different and non-zero (pressed), store it as current&lt;br /&gt;
NMI_P0_Fire_NoChange&lt;br /&gt;
  STA P0CurrentFire                       ; Store current state (either newly pressed or still same as last)&lt;br /&gt;
NMI_P0_Fire_StoreCurrent&lt;br /&gt;
&lt;br /&gt;
; Read Player 1 Fire Button with a one-frame debounce.&lt;br /&gt;
  LDA INPT5                     ; Read Player 1 input port&lt;br /&gt;
  AND #Input_FireButtonMask     ; Isolate fire button bit&lt;br /&gt;
  CMP P1LastFire                ; Compare with last latched state&lt;br /&gt;
  BEQ NMI_P1_Fire_NoChange      ; If same, no change in press state&lt;br /&gt;
  STA P1LastFire                ; New state, update P1LastFire&lt;br /&gt;
  BNE NMI_P1_Fire_StoreCurrent  ; If different and non-zero (pressed), store it as current&lt;br /&gt;
NMI_P1_Fire_NoChange&lt;br /&gt;
  STA P1CurrentFire             ; Store current state&lt;br /&gt;
NMI_P1_Fire_StoreCurrent&lt;br /&gt;
&lt;br /&gt;
; Increment global 16-bit frame timer&lt;br /&gt;
  INC TimerLo&lt;br /&gt;
  BNE NMI_Timer_HiByteNoInc        ; If TimerLo didn't wrap, skip TimerHi increment&lt;br /&gt;
  INC TimerHi&lt;br /&gt;
NMI_Timer_HiByteNoInc&lt;br /&gt;
&lt;br /&gt;
  JSR SetColorRegisters            ; Update hardware color palette registers from RAM&lt;br /&gt;
&lt;br /&gt;
  LDA RenderListDirty              ; Check if the game logic has prepared a new list of sprites to draw&lt;br /&gt;
  BNE ProcessDirtyRenderList       ; If dirty, branch to process it&lt;br /&gt;
  JMP NMI_ExitAndRestoreRegisters  ; If not dirty, nothing to render, so exit NMI&lt;br /&gt;
&lt;br /&gt;
ProcessDirtyRenderList&lt;br /&gt;
  LDX RenderListCount              ; Get number of sprites in the render list&lt;br /&gt;
  BMI FinalizeDisplayListPointers  ; If negative (e.g., $FF from init), skip sprite processing&lt;br /&gt;
&lt;br /&gt;
RenderSpritesFromListToDisplayList&lt;br /&gt;
; This loop iterates through the render list (built by the main game logic)&lt;br /&gt;
; and writes the 5-byte sprite definitions into the appropriate Display List zones.&lt;br /&gt;
  LDA RenderListDLLo,X             ; Get Lo byte of target DL entry address for this sprite&lt;br /&gt;
  STA TempPoint5CLo                ; Store in ZP pointer&lt;br /&gt;
  LDA RenderListDLHi,X             ; Get Hi byte of target DL entry address&lt;br /&gt;
  STA TempPoint5DHi                ; Store in ZP pointer&lt;br /&gt;
  LDY #$00                         ; Y will be offset into the 5-byte DL object&lt;br /&gt;
&lt;br /&gt;
  LDA RenderListGfxDataLo,X         ; Byte 0: Graphics Data Lo&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
&lt;br /&gt;
  LDA RenderListPaletteAndWidth,X   ; Byte 1: Palette and Width&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
&lt;br /&gt;
  LDA RenderListGfxDataHi,X         ; Byte 2: Graphics Data Hi&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
&lt;br /&gt;
  LDA RenderListXCoord,X            ; Byte 3: X Coordinate (Horizontal Position)&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL RenderSpritesFromListToDisplayList&lt;br /&gt;
&lt;br /&gt;
; After processing sprites, process score popups (if any)&lt;br /&gt;
  LDX #$0B                          ; Max index for score popups (12 popups, 0 to 11)&lt;br /&gt;
ProcessScorePopupsLoop&lt;br /&gt;
  LDA ScorePopup_ActiveTimerBase,X  ; Check if this score popup timer is active&lt;br /&gt;
  BEQ SkipThisScorePopup            ; If timer is 0, skip this popup&lt;br /&gt;
  DEC ScorePopup_ActiveTimerBase,X  ; Decrement active timer&lt;br /&gt;
&lt;br /&gt;
  LDY ScorePopup_ZoneIndexBase,X    ; Y = Zone index for this score popup&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA DisplayListLo,Y               ; Get current Lo pointer for this zone's DL&lt;br /&gt;
  SBC #$05                          ; Make space for a 5-byte character DL object by moving the pointer up&lt;br /&gt;
  STA DisplayListLo,Y               ; Store updated Lo pointer&lt;br /&gt;
  STA TempPoint5CLo                 ; Use ZP pointer for indirect write&lt;br /&gt;
  LDA DisplayListHi,Y               ; Get current Hi pointer&lt;br /&gt;
  SBC #$00                          ; Adjust Hi pointer if Lo underflowed&lt;br /&gt;
  STA DisplayListHi,Y               ; Store updated Hi pointer&lt;br /&gt;
  STA TempPoint5DHi                 ; Use ZP pointer&lt;br /&gt;
&lt;br /&gt;
  LDY #$00                          ; Y = offset into DL object&lt;br /&gt;
  LDA ScorePopup_CharDataLoBase,X   ; Byte 0: Character Data Lo (e.g., '2' for &amp;quot;250&amp;quot;)&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
  LDA #ScorePopup_DLModeByte        ; Byte 1: Mode (Indirect Character)&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
  LDA #ScorePopup_DLCharHiByte      ; Byte 2: Character Data Hi (High byte of HSC font base)&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
  LDA #$7C                          ; Byte 3: Palette &amp;amp; Width (seems fixed for score popups)&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
  INY&lt;br /&gt;
  LDA ScorePopup_XCoordBase,X       ; Byte 4: X Coordinate&lt;br /&gt;
  STA (TempPoint5CLo),Y&lt;br /&gt;
SkipThisScorePopup&lt;br /&gt;
  DEX                               ; Next score popup slot&lt;br /&gt;
  BPL ProcessScorePopupsLoop        ; Loop if X is not negative&lt;br /&gt;
&lt;br /&gt;
FinalizeDisplayListPointers&lt;br /&gt;
                                    ; Copy the adjusted DisplayListLo/Hi pointers (from $242B/$2443)&lt;br /&gt;
                                    ; into the final RAM area ($275E onwards) that Maria's DLL will use.&lt;br /&gt;
                                    ; This is done in reverse order because the final DLL structure is 3 bytes&lt;br /&gt;
                                    ; per entry (Interrupt/Height, Hi, Lo) and it's easier to fill from the end.&lt;br /&gt;
  LDX #$17                          ; Number of DL zones - 1 (0 to 23)&lt;br /&gt;
  LDY #$45                          ; Offset into FinalDLL_PointerStorage (starts at $275E + $45 = $27A3)&lt;br /&gt;
CopyDLLPointersToFinalRAMLoop&lt;br /&gt;
  LDA DisplayListHi,X               ; Get Hi byte of DL pointer for zone X&lt;br /&gt;
  STA FinalDLL_PointerStorage_Hi,Y  ; Store it&lt;br /&gt;
  LDA DisplayListLo,X               ; Get Lo byte of DL pointer for zone X&lt;br /&gt;
  STA FinalDLL_PointerStorage_Lo,Y  ; Store it&lt;br /&gt;
  DEY                               ; Next storage slot (lower address)&lt;br /&gt;
  DEY&lt;br /&gt;
  DEY                               ; DLL entries are 3 bytes (interrupt+height, Hi, Lo)&lt;br /&gt;
  DEX                               ; Next zone&lt;br /&gt;
  BPL CopyDLLPointersToFinalRAMLoop&lt;br /&gt;
&lt;br /&gt;
  INX                  ; X = 0&lt;br /&gt;
  STX RenderListDirty  ; Clear the dirty flag, signaling the main loop that rendering is complete.&lt;br /&gt;
&lt;br /&gt;
NMI_ExitAndRestoreRegisters&lt;br /&gt;
  PLA  ; Restore Y&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA  ; Restore X&lt;br /&gt;
  TAX&lt;br /&gt;
  PLA  ; Restore A&lt;br /&gt;
       ; Fall through to IRQ RTI&lt;br /&gt;
&lt;br /&gt;
IRQ_ROUTINE&lt;br /&gt;
  RTI &lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Title Screen and Menu Logic&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
AttractModeMain&lt;br /&gt;
  JSR SetupTitleScreen&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  STA $6E&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  STA Temp68&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp69&lt;br /&gt;
AttractMode_FrameLoop&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  CMP $6E&lt;br /&gt;
  BEQ AttractMode_FrameLoop&lt;br /&gt;
  STA $6E&lt;br /&gt;
  JSR HandleDemoModeJoyInput&lt;br /&gt;
  JSR AnimateTitleScreenFrame&lt;br /&gt;
  LDA Temp68&lt;br /&gt;
  CMP TimerLo&lt;br /&gt;
  BNE AttractMode_FrameLoop&lt;br /&gt;
  DEC Temp69&lt;br /&gt;
  BPL AttractMode_FrameLoop&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62&lt;br /&gt;
AttractMode_HSC_Loop&lt;br /&gt;
  JSR DoHscStatusCheck&lt;br /&gt;
  BMI HscLoopContinueOrExit&lt;br /&gt;
  JSR DoHscAttractMode&lt;br /&gt;
  LDA INPT4&lt;br /&gt;
  AND INPT5&lt;br /&gt;
  JSR CheckForAttractModeExit&lt;br /&gt;
HscLoopContinueOrExit&lt;br /&gt;
  INC Temp62&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BCC AttractMode_HSC_Loop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetupTitleScreen&lt;br /&gt;
  SEI&lt;br /&gt;
  LDA #$60&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  JSR ClearRamMuteAudio&lt;br /&gt;
  JSR LoadTitlePalette&lt;br /&gt;
  JSR SetColorRegisters&lt;br /&gt;
  JSR SetupTitleScrText&lt;br /&gt;
  JSR SetupTitleScrDLs&lt;br /&gt;
WaitVblankOver&lt;br /&gt;
  BIT MSTAT&lt;br /&gt;
  BMI WaitVblankOver&lt;br /&gt;
WaitVblankStart&lt;br /&gt;
  BIT MSTAT&lt;br /&gt;
  BPL WaitVblankStart&lt;br /&gt;
&lt;br /&gt;
; ** We're now in vblank&lt;br /&gt;
&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA DPPL&lt;br /&gt;
  LDA #$27&lt;br /&gt;
  STA DPPH  ; Register $2700 as the DLL location&lt;br /&gt;
&lt;br /&gt;
  LDA #$40  ; DMA on, single-width chars&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DisplayGameOptions&lt;br /&gt;
  JSR SetupTitleScreen&lt;br /&gt;
  LDX #$0F&lt;br /&gt;
CopyPlayerStringLoop&lt;br /&gt;
  LDA StringOnePlayer,X&lt;br /&gt;
  STA MenuLine2CharBuffer,X&lt;br /&gt;
  LDA StringTwoPlayer,X&lt;br /&gt;
  STA MenuLine1CharBuffer,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL CopyPlayerStringLoop&lt;br /&gt;
  JSR SetupGameOptionsText&lt;br /&gt;
  JSR SetMenuJoyDebounceTimerTo20&lt;br /&gt;
  JSR SetMenuSelectDebounceTimerTo20&lt;br /&gt;
  JSR SetMenuResetTimer  ; MenuResetTimer = Timerhi - 1&lt;br /&gt;
GameOptionsMenuLoop&lt;br /&gt;
  JSR CheckMenuFireButtonAndStartGame&lt;br /&gt;
  JSR SetupGameOptionsText&lt;br /&gt;
  JSR AnimateTitleScreenFrame&lt;br /&gt;
  LDA SWCHA&lt;br /&gt;
  AND #$F0&lt;br /&gt;
  CMP #$F0&lt;br /&gt;
  BNE MenuJoyInput_ProcessAfterDebounce&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA MenuJoyDebounceTimer&lt;br /&gt;
GoMenuHandlingAndUpdate&lt;br /&gt;
  JMP MenuHandlingAndUpdate&lt;br /&gt;
&lt;br /&gt;
; MenuJoyInput_ProcessAfterDebounce&lt;br /&gt;
; This code is reached after the joystick debounce timer (MenuJoyDebounceTimer)&lt;br /&gt;
; has expired, indicating it's time to process joystick input for the menu.&lt;br /&gt;
; Part of the DisplayGameOptions routine.&lt;br /&gt;
&lt;br /&gt;
MenuJoyInput_ProcessAfterDebounce&lt;br /&gt;
  DEC MenuJoyDebounceTimer         ; Decrement debounce timer&lt;br /&gt;
  BPL GoMenuHandlingAndUpdate      ; If timer still active, skip input processing for now&lt;br /&gt;
  JSR SetMenuJoyDebounceTimerTo20  ; Reset debounce timer for next input&lt;br /&gt;
&lt;br /&gt;
  LDA SWCHA                        ; Read Player 1 Joystick &amp;amp; Console Switches&lt;br /&gt;
                                   ; SWCHA bits (active low for joystick)&lt;br /&gt;
                                   ; 7654 3210&lt;br /&gt;
                                   ; ---- RLDU (Right, Left, Down, Up for P1 Joystick)&lt;br /&gt;
&lt;br /&gt;
  ASL                              ; Shift P1 Right (Bit 3) into Carry&lt;br /&gt;
  BCC HandleP0JoyRight&lt;br /&gt;
  ASL                              ; Shift P1 Left (Bit 2) into Carry&lt;br /&gt;
  BCC HandleP0JoyLeft&lt;br /&gt;
  ASL                              ; Shift P1 Down (Bit 1) into Carry&lt;br /&gt;
  BCS MenuJoyInput_CheckP1UpOrNoVerticalInput&lt;br /&gt;
  JMP MenuSelectOnePlayer          ; P1 Down IS pressed: Select 1 Player&lt;br /&gt;
&lt;br /&gt;
MenuJoyInput_CheckP1UpOrNoVerticalInput&lt;br /&gt;
  ASL                              ; Shift P1 Up (Bit 0) into Carry&lt;br /&gt;
  BCS HandleP0JoyRight&lt;br /&gt;
  JMP MenuSelectTwoPlayers         ; P1 Up IS pressed: Select 2 Players&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; HandleP0JoyRight&lt;br /&gt;
; Increases the game difficulty, capping at Difficulty_Expert.&lt;br /&gt;
; Resets the counters used for the menu easter egg.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandleP0JoyRight&lt;br /&gt;
  LDX Difficulty&lt;br /&gt;
  CPX #Difficulty_Expert      ; Max difficulty?&lt;br /&gt;
  BPL SkipDifficultyIncrease  ; If at or above max, skip&lt;br /&gt;
  INX                         ; Increase difficulty&lt;br /&gt;
  STX Difficulty&lt;br /&gt;
  JSR ClearScores             ; Clear scores when difficulty changes&lt;br /&gt;
SkipDifficultyIncrease&lt;br /&gt;
  LDA #$00                    ; Reset easter egg press counters&lt;br /&gt;
  STA EasterEggJoyDownCount&lt;br /&gt;
  STA EasterEggJoyLeftCount&lt;br /&gt;
  JMP MenuTextUpdate          ; Redraw menu text&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; HandleP0JoyLeft&lt;br /&gt;
; Decreases the game difficulty, bottoming out at Difficulty_Beginner.&lt;br /&gt;
; Jumps to update counters used for the menu easter egg.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandleP0JoyLeft&lt;br /&gt;
  LDX Difficulty&lt;br /&gt;
  BEQ SkipDifficultyDecrease  ; If already at Beginner, skip&lt;br /&gt;
  DEX                         ; Decrease difficulty&lt;br /&gt;
  STX Difficulty&lt;br /&gt;
  JSR ClearScores             ; Clear scores when difficulty changes&lt;br /&gt;
SkipDifficultyDecrease&lt;br /&gt;
  JMP MenuUpdateCounter&lt;br /&gt;
&lt;br /&gt;
; This section seems to be entirely dead. &lt;br /&gt;
; Emulation debugging during regular play shows no access.&lt;br /&gt;
; In assembly it would be &amp;quot;BIT $56, ORA $03, KIL, KIL&amp;quot;.&lt;br /&gt;
; It's not accessed by Maria, and isn't sensible in ASCII nor the game's character set.&lt;br /&gt;
 .byte $24  ; $9FFA&lt;br /&gt;
 .byte $56  ; $9FFB&lt;br /&gt;
 .byte $05  ; $9FFC&lt;br /&gt;
 .byte $03  ; $9FFD&lt;br /&gt;
 .byte $12  ; $9FFE&lt;br /&gt;
 .byte $12  ; $9FFF&lt;br /&gt;
&lt;br /&gt;
; ORG $A000&lt;br /&gt;
&lt;br /&gt;
; This upcoming bit is a bit ugly. It's mostly Maria gfx data, but they stuck some&lt;br /&gt;
; 6502 data in the middle of each page.&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A058&lt;br /&gt;
&lt;br /&gt;
BirdWalkCycleGfxOffsetLUT&lt;br /&gt;
 .byte $00, $14, $28, $28, $28, $28, $28, $28, $28, $28&lt;br /&gt;
&lt;br /&gt;
BirdSpawnGfxOffsetLUT&lt;br /&gt;
 .byte $82, $86, $8A, $8A, $8A, $8A, $8A, $8A, $8A, $8A &lt;br /&gt;
&lt;br /&gt;
BirdPaletteAndWidthLUT&lt;br /&gt;
 .byte $BE,$DE,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE&lt;br /&gt;
&lt;br /&gt;
RiderPaletteAndWidthLUT&lt;br /&gt;
 .byte $7E,$7E,$5E,$5E,$5E,$5E,$5E,$5E,$5E,$5E&lt;br /&gt;
&lt;br /&gt;
BirdGfxAnimationOffsetLUT&lt;br /&gt;
 .byte $08, $14, $20, $20, $20&lt;br /&gt;
&lt;br /&gt;
; This doesn't seem to be reached by Sally or Maria&lt;br /&gt;
 .byte $20, $20, $20, $20, $20&lt;br /&gt;
&lt;br /&gt;
; This is graphics data (A08E)&lt;br /&gt;
 .byte $03, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $F0, $3F, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $7F, $FD, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $7C, $00, $EB, $FF, $FF, $FB&lt;br /&gt;
 .byte $FF, $FA, $AF, $FF, $BE, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $EB, $FB, $AF, $AF&lt;br /&gt;
 .byte $FE, $FF, $AB, $BF, $FF, $AF, $FF, $FF&lt;br /&gt;
 .byte $A8, $0F, $BE, $A0, $00, $AF, $F8, $2F&lt;br /&gt;
 .byte $FF, $A8, $BB, $FA, $FC, $0F, $FF, $AF&lt;br /&gt;
 .byte $80, $FF, $EB, $E8, $2A, $C2, $BF, $E8&lt;br /&gt;
 .byte $F0, $EE, $AF, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
 ; A100&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00 &lt;br /&gt;
&lt;br /&gt;
; A180&lt;br /&gt;
&lt;br /&gt;
TitleScrSpriteObject_PaletteWidth&lt;br /&gt;
 .byte $FA, $FF, $F7, $FD, $F6, $F6, $FA, $F6&lt;br /&gt;
 .byte $F6, $FA, $33, $33, $34&lt;br /&gt;
&lt;br /&gt;
 .byte $00  ; not used&lt;br /&gt;
&lt;br /&gt;
; A18E&lt;br /&gt;
&lt;br /&gt;
 .byte $0E, $FA &lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $AB, $FF, $EA, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AF&lt;br /&gt;
 .byte $FC, $2F, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $00, $AB, $FF, $BF, $FA&lt;br /&gt;
 .byte $BF, $FF, $EA, $BE, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $EA, $BE, $BE, $AA, $AE, $FA&lt;br /&gt;
 .byte $AF, $FE, $AF, $EE, $AB, $FB, $AB, $FE&lt;br /&gt;
 .byte $AA, $0E, $BF, $A8, $02, $BF, $FE, $FF&lt;br /&gt;
 .byte $FA, $FE, $BF, $BF, $EA, $FF, $FE, $FB&lt;br /&gt;
 .byte $B3, $FF, $BA, $EA, $2F, $A2, $FA, $B0&lt;br /&gt;
 .byte $E0, $AA, $BB, $FC, $0A, $C0, $00, $00 &lt;br /&gt;
&lt;br /&gt;
; A200&lt;br /&gt;
&lt;br /&gt;
 .byte $F8, $00, $F8, $00, $3E, $00, $F0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A280&lt;br /&gt;
&lt;br /&gt;
TitleScrSpriteObject_XCoordinate&lt;br /&gt;
 .byte $41, $2F, $0F, $57, $31, $57, $7D, $31&lt;br /&gt;
 .byte $57, $7D, $B4, $B4, $B8&lt;br /&gt;
&lt;br /&gt;
 .byte $00  ; not used&lt;br /&gt;
&lt;br /&gt;
; A28E&lt;br /&gt;
 .byte $02, $BF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $F8, $0D, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $DF, $F7, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $DF, $00, $3A, $FB, $EB, $FF&lt;br /&gt;
 .byte $BF, $FF, $FA, $EF, $FF, $FF, $FE, $AF&lt;br /&gt;
 .byte $FE, $BF, $BE, $EE, $FF, $FA, $AB, $FF&lt;br /&gt;
 .byte $FF, $FE, $AF, $AA, $FA, $AF, $3F, $EA&lt;br /&gt;
 .byte $AA, $83, $FF, $E8, $00, $BF, $FF, $BF&lt;br /&gt;
 .byte $EF, $FF, $FE, $FE, $BE, $BF, $FE, $AF&lt;br /&gt;
 .byte $FE, $AF, $FE, $3F, $AB, $EF, $B8, $02&lt;br /&gt;
 .byte $AF, $FF, $FC, $AF, $BA, $F0, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A300&lt;br /&gt;
&lt;br /&gt;
 .byte $BE, $00, $BE, $00, $3F, $00, $FC, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $FC, $3A, $7C&lt;br /&gt;
 .byte $00, $00, $3F, $00, $3D, $AC, $00, $00&lt;br /&gt;
 .byte $00, $00, $BB, $C0, $00, $00, $00, $00&lt;br /&gt;
 .byte $03, $EE, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A380&lt;br /&gt;
&lt;br /&gt;
PterryFrameIndexAdjustmentLUT&lt;br /&gt;
 .byte $01, $01, $FF, $FF &lt;br /&gt;
&lt;br /&gt;
BirdBornSFXType&lt;br /&gt;
 .byte $09, $09, $0C, $0C, $0C, $0C, $0C, $0C, $0C, $0C&lt;br /&gt;
&lt;br /&gt;
; A38E&lt;br /&gt;
&lt;br /&gt;
 .byte $0F, $AF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FA&lt;br /&gt;
 .byte $A8, $37, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $F7, $DF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $F7, $C0, $3E, $BF, $FF, $FF&lt;br /&gt;
 .byte $FE, $AA, $EE, $AA, $FF, $FF, $EA, $FE&lt;br /&gt;
 .byte $FB, $AF, $FF, $EF, $EF, $FF, $BF, $FF&lt;br /&gt;
 .byte $FF, $FA, $EA, $BF, $FA, $A8, $03, $AB&lt;br /&gt;
 .byte $EA, $A2, $FF, $FA, $00, $FF, $FF, $EF&lt;br /&gt;
 .byte $FF, $FF, $EB, $FF, $FF, $EF, $FF, $EE&lt;br /&gt;
 .byte $EA, $BF, $FA, $AF, $BA, $AA, $A0, $0A&lt;br /&gt;
 .byte $FF, $FF, $F0, $EA, $FA, $EF, $AC, $00&lt;br /&gt;
&lt;br /&gt;
; A400&lt;br /&gt;
&lt;br /&gt;
 .byte $BF, $80, $BF, $80, $3F, $C0, $FF, $40&lt;br /&gt;
 .byte $00, $00, $0F, $B0, $00, $00, $00, $00&lt;br /&gt;
 .byte $0E, $F0, $00, $00, $03, $AF, $05, $6F&lt;br /&gt;
 .byte $02, $BF, $FA, $C0, $F9, $50, $FE, $80&lt;br /&gt;
 .byte $00, $00, $EE, $F0, $00, $00, $00, $00 &lt;br /&gt;
 .byte $0F, $BB, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00 &lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00 &lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00 ,$00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A48E&lt;br /&gt;
&lt;br /&gt;
 .byte $0F, $AB&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $EA, $AE, $AA, $AB, $FA, $AA, $FF&lt;br /&gt;
 .byte $FF, $FF, $AB, $FA, $AB, $FF, $EA, $AA&lt;br /&gt;
 .byte $AA, $BE, $EA, $AB, $FB, $FA, $AA, $AA&lt;br /&gt;
 .byte $FC, $3F, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $80, $0F, $AF, $FF, $FF&lt;br /&gt;
 .byte $FA, $AF, $FE, $FB, $BF, $FF, $EF, $FF&lt;br /&gt;
 .byte $EF, $FF, $FF, $FB, $FF, $FF, $EB, $EA&lt;br /&gt;
 .byte $BF, $FB, $FF, $FF, $FE, $BE, $00, $BF&lt;br /&gt;
 .byte $FE, $A8, $FF, $EA, $80, $3F, $FF, $FE&lt;br /&gt;
 .byte $FF, $FF, $EF, $FF, $FF, $FF, $EA, $FB&lt;br /&gt;
 .byte $BA, $BF, $FF, $EA, $AA, $BE, $88, $AA&lt;br /&gt;
 .byte $FF, $AA, $A0, $EF, $FE, $BF, $FF, $00&lt;br /&gt;
&lt;br /&gt;
; A500&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $E0, $3F, $E0, $3F, $F0, $FD, $80&lt;br /&gt;
 .byte $03, $F8, $03, $B8, $03, $B8, $2F, $C0&lt;br /&gt;
 .byte $2E, $C0, $2E, $C0, $05, $A8, $06, $A8&lt;br /&gt;
 .byte $06, $A8, $2A, $50, $2A, $90, $2A, $90&lt;br /&gt;
 .byte $01, $A8, $37, $AC, $45, $B8, $2A, $40&lt;br /&gt;
 .byte $3A, $DC, $2E, $51, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A58E&lt;br /&gt;
&lt;br /&gt;
 .byte $05, $55 &lt;br /&gt;
&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $57, $55&lt;br /&gt;
 .byte $55, $55, $D5, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $54, $3F, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $80, $0F, $EB, $FF, $FF&lt;br /&gt;
 .byte $BB, $FF, $FF, $FF, $FF, $FE, $FF, $FF&lt;br /&gt;
 .byte $BF, $FF, $FF, $FF, $FF, $FF, $FE, $BF&lt;br /&gt;
 .byte $EF, $FF, $FF, $FF, $FF, $AC, $00, $FF&lt;br /&gt;
 .byte $FA, $AA, $BE, $AA, $A0, $2F, $FF, $FF&lt;br /&gt;
 .byte $AA, $AF, $FF, $FE, $FF, $FF, $AF, $BF&lt;br /&gt;
 .byte $FE, $FF, $FF, $AA, $BB, $FF, $AA, $AB&lt;br /&gt;
 .byte $FA, $FA, $00, $EB, $BF, $AE, $AF, $C0&lt;br /&gt;
&lt;br /&gt;
; A600&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $F0, $3F, $FC, $BE, $FC, $39, $D0&lt;br /&gt;
 .byte $0F, $FF, $0F, $EB, $0F, $EE, $FF, $F0&lt;br /&gt;
 .byte $EB, $F0, $BB, $F0, $36, $A0, $35, $A0&lt;br /&gt;
 .byte $35, $A0, $0A, $9C, $0A, $5C, $0A, $5C&lt;br /&gt;
 .byte $46, $BA, $06, $E6, $56, $AE, $AE, $91&lt;br /&gt;
 .byte $9B, $90, $BA, $95, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A68E&lt;br /&gt;
 &lt;br /&gt;
 .byte $05, $55 &lt;br /&gt;
&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $5D, $55&lt;br /&gt;
 .byte $55, $55, $75, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $54, $EB, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FB, $EF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FB, $A0, $0E, $AF, $BF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $EF, $BC, $00, $EB&lt;br /&gt;
 .byte $EF, $FA, $BA, $FF, $AA, $2F, $FF, $EE&lt;br /&gt;
 .byte $AB, $EA, $FF, $FF, $FF, $FE, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $AB, $EB, $FF, $AA, $AF&lt;br /&gt;
 .byte $EB, $FF, $00, $FF, $FA, $AF, $AB, $C0&lt;br /&gt;
&lt;br /&gt;
; A700&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $F8, $3F, $F8, $BE, $FF, $3E, $60&lt;br /&gt;
 .byte $3C, $EE, $1C, $BA, $1F, $FA, $BB, $3C&lt;br /&gt;
 .byte $AE, $34, $AF, $F4, $16, $9B, $16, $80&lt;br /&gt;
 .byte $16, $80, $E6, $94, $02, $94, $02, $94&lt;br /&gt;
 .byte $56, $AC, $46, $A9, $1A, $BB, $3A, $95&lt;br /&gt;
 .byte $6A, $91, $EE, $A4, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $40, $00, $15, $54&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $15, $54, $00, $01&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A78E&lt;br /&gt;
&lt;br /&gt;
 .byte $05, $55 &lt;br /&gt;
&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $75, $55&lt;br /&gt;
 .byte $55, $55, $5D, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $54, $FE, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $EF, $FB, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $EF, $80, $0A, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $EF, $FC, $00, $3B&lt;br /&gt;
 .byte $EF, $FF, $AB, $FF, $AA, $AB, $EF, $EE&lt;br /&gt;
 .byte $BF, $FF, $AE, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FB, $FF, $FE, $AF, $FF, $FF, $EB, $FF&lt;br /&gt;
 .byte $FF, $FF, $00, $55, $55, $55, $55, $50&lt;br /&gt;
&lt;br /&gt;
; A800&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $F4, $3E, $F4, $FE, $F0, $3E, $F0&lt;br /&gt;
 .byte $13, $F8, $13, $FE, $13, $FC, $2F, $C4&lt;br /&gt;
 .byte $BF, $C4, $3F, $C4, $16, $57, $16, $00&lt;br /&gt;
 .byte $16, $00, $D5, $94, $00, $94, $00, $94&lt;br /&gt;
 .byte $16, $BA, $56, $A8, $0A, $A0, $AE, $94&lt;br /&gt;
 .byte $2A, $95, $0A, $A0, $00, $3F, $C0, $00&lt;br /&gt;
 .byte $50, $3F, $C0, $00, $14, $F1, $55, $50&lt;br /&gt;
 .byte $00, $00, $C3, $30, $00, $00, $C3, $00&lt;br /&gt;
 .byte $00, $00, $C0, $00, $00, $03, $FC, $00&lt;br /&gt;
 .byte $00, $03, $FC, $05, $05, $55, $4F, $14&lt;br /&gt;
 .byte $33, $0C, $00, $00, $03, $0C, $00, $00&lt;br /&gt;
 .byte $00, $0C, $00, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $3C, $3C, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A88E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00&lt;br /&gt;
 .byte $00, $00, $0F, $EF, $EA, $AA, $80, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A8C4&lt;br /&gt;
BirdSpawnInvulnAnimStateSequence_TypeA&lt;br /&gt;
 .byte $00, $00, $00, $00 &lt;br /&gt;
 .byte $00, $00, $00, $01, $02, $03, $04, $02&lt;br /&gt;
 .byte $03, $04, $02, $03, $04, $02, $03, $04&lt;br /&gt;
 .byte $02, $03, $04, $02, $03, $04, $02, $03&lt;br /&gt;
 .byte $04, $02, $03, $04, $02, $03, $04, $05&lt;br /&gt;
 .byte $06, $05, $06, $05, $06, $05, $06, $05&lt;br /&gt;
 .byte $06, $05, $06, $05, $06, $05, $06, $05&lt;br /&gt;
 .byte $06, $05, $06, $05, $06, $05, $06, $07&lt;br /&gt;
&lt;br /&gt;
; A900&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $FC, $3E, $FC, $FA, $FC, $3E, $A0&lt;br /&gt;
 .byte $10, $FC, $10, $00, $10, $00, $3F, $04&lt;br /&gt;
 .byte $00, $04, $00, $04, $38, $9A, $17, $00&lt;br /&gt;
 .byte $17, $00, $A6, $2C, $00, $D4, $00, $D4&lt;br /&gt;
 .byte $00, $AB, $14, $00, $00, $00, $EA, $00&lt;br /&gt;
 .byte $00, $14, $00, $00, $00, $FF, $FF, $C0&lt;br /&gt;
 .byte $35, $F1, $55, $C0, $05, $FD, $55, $00&lt;br /&gt;
 .byte $F3, $CF, $33, $C0, $03, $03, $00, $C0&lt;br /&gt;
 .byte $00, $00, $00, $00, $03, $FF, $FF, $00&lt;br /&gt;
 .byte $03, $55, $4F, $5C, $00, $55, $7F, $50&lt;br /&gt;
 .byte $0F, $33, $CF, $3C, $0C, $03, $03, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $82, $08&lt;br /&gt;
 .byte $02, $A8, $8A, $00, $02, $82, $00, $20&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; A98E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00&lt;br /&gt;
 .byte $00, $00, $AE, $BE, $BE, $FF, $A0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $2A&lt;br /&gt;
 .byte $A0, $00, $00, $00, $3C, $EB, $EB, $3F&lt;br /&gt;
 .byte $A0, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $10&lt;br /&gt;
&lt;br /&gt;
; A9C4&lt;br /&gt;
&lt;br /&gt;
BirdSpawnInvulnAnimStateSequence_TypeB&lt;br /&gt;
 .byte $02, $02, $02, $02&lt;br /&gt;
 .byte $02, $02, $02, $00, $04, $04, $04, $04&lt;br /&gt;
 .byte $04, $04, $03, $03, $03, $03, $03, $03&lt;br /&gt;
 .byte $02, $02, $02, $02, $02, $02, $02, $02&lt;br /&gt;
 .byte $02, $01, $01, $01, $00, $00, $00, $04&lt;br /&gt;
 .byte $04, $04, $04, $03, $03, $03, $03, $02&lt;br /&gt;
 .byte $02, $02, $02, $02, $02, $01, $01, $01&lt;br /&gt;
 .byte $01, $01, $01, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; AA00&lt;br /&gt;
&lt;br /&gt;
 .byte $3F, $CC, $3E, $CF, $FB, $CF, $3E, $F0&lt;br /&gt;
 .byte $10, $3E, $1C, $00, $30, $00, $BC, $04&lt;br /&gt;
 .byte $00, $34, $00, $0C, $38, $2B, $1C, $00&lt;br /&gt;
 .byte $1C, $00, $E8, $2C, $00, $34, $00, $34&lt;br /&gt;
 .byte $00, $2A, $00, $00, $00, $00, $A8, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $03, $C7, $FF, $FF&lt;br /&gt;
 .byte $3D, $45, $55, $5F, $FD, $45, $55, $CF&lt;br /&gt;
 .byte $33, $33, $3C, $00, $33, $30, $0C, $00&lt;br /&gt;
 .byte $33, $30, $00, $00, $FF, $FF, $D3, $C0&lt;br /&gt;
 .byte $F5, $55, $51, $7C, $F3, $55, $51, $7F&lt;br /&gt;
 .byte $00, $F3, $33, $30, $00, $C0, $33, $30&lt;br /&gt;
 .byte $00, $00, $33, $30, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $20, $20, $00, $00&lt;br /&gt;
 .byte $23, $E2, $8A, $80, $08, $82, $03, $28&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00&lt;br /&gt;
&lt;br /&gt;
; AA8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00&lt;br /&gt;
 .byte $00, $FF, $FB, $BF, $AB, $FE, $A0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $02, $80, $AA&lt;br /&gt;
 .byte $BC, $00, $00, $00, $AA, $BF, $FF, $FF&lt;br /&gt;
 .byte $FE, $EE, $00, $2A, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $10, $00&lt;br /&gt;
 .byte $00, $00, $10, $44&lt;br /&gt;
&lt;br /&gt;
; AAC4&lt;br /&gt;
&lt;br /&gt;
MaxEnemyBirdCountLUT&lt;br /&gt;
 .byte $06, $06, $06, $06, $06, $06, $08, $08, $08, $08&lt;br /&gt;
&lt;br /&gt;
EggWaveEnemyTypeLUT&lt;br /&gt;
 .byte $00, $00, $01, $01, $01, $01, $01, $01, $01, $01&lt;br /&gt;
&lt;br /&gt;
PlatformsInLevelLUT&lt;br /&gt;
 .byte $1F, $1F, $0F, $0F, $0D, $0C, $0C, $04, $0F, $07&lt;br /&gt;
 .byte $04, $04, $0F, $0F, $0F, $0F, $0E, $0E, $06, $06&lt;br /&gt;
 .byte $04, $04, $04, $04, $0F, $0F, $0D, $0D, $07, $0D&lt;br /&gt;
 .byte $05, $05, $0E, $06, $06, $04, $07, $0D, $05, $05&lt;br /&gt;
&lt;br /&gt;
; AB00&lt;br /&gt;
&lt;br /&gt;
 .byte $3C, $C0, $3C, $C0, $FC, $F0, $3E, $A0&lt;br /&gt;
 .byte $10, $3E, $1C, $00, $10, $00, $BC, $04&lt;br /&gt;
 .byte $00, $34, $00, $04, $34, $3F, $10, $00&lt;br /&gt;
 .byte $10, $00, $FC, $1C, $00, $04, $00, $04&lt;br /&gt;
 .byte $00, $2B, $00, $00, $00, $00, $E8, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $55, $07, $FC, $00&lt;br /&gt;
 .byte $05, $03, $FF, $C0, $01, $0D, $55, $5C&lt;br /&gt;
 .byte $CF, $30, $CF, $3C, $CC, $30, $00, $F0&lt;br /&gt;
 .byte $0C, $00, $00, $30, $00, $3F, $D0, $55&lt;br /&gt;
 .byte $03, $FF, $C0, $50, $35, $55, $70, $40&lt;br /&gt;
 .byte $F3, $CC, $33, $CC, $3C, $00, $30, $CC&lt;br /&gt;
 .byte $30, $00, $00, $C0, $55, $51, $45, $55&lt;br /&gt;
 .byte $AA, $A2, $8A, $AA, $55, $51, $45, $55&lt;br /&gt;
 .byte $AA, $A2, $8A, $AA, $FF, $F3, $CF, $FF&lt;br /&gt;
 .byte $00, $00, $01, $00, $01, $00, $08, $80&lt;br /&gt;
 .byte $23, $E0, $8E, $0C, $22, $A2, $00, $80&lt;br /&gt;
 .byte $28, $A0, $04, $14, $14, $10, $20, $38&lt;br /&gt;
 .byte $2C, $08, $70, $50, $05, $0D&lt;br /&gt;
&lt;br /&gt;
; AB8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00&lt;br /&gt;
 .byte $3A, $FF, $FF, $FF, $FF, $AA, $FF, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $AA, $AB, $AB&lt;br /&gt;
 .byte $AA, $BF, $00, $2A, $BF, $AA, $BF, $FF&lt;br /&gt;
 .byte $FF, $EA, $FE, $AA, $B0, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $10&lt;br /&gt;
 .byte $00, $00, $00, $10, $04, $14, $01, $40&lt;br /&gt;
 .byte $00, $50, $00, $14, $04, $10, $14, $10&lt;br /&gt;
 .byte $01, $40, $05, $00, $14, $00, $04, $10&lt;br /&gt;
 .byte $14, $05, $01, $80, $00, $10, $00, $04&lt;br /&gt;
 .byte $1C, $60, $50, $14, $02, $40, $04, $00&lt;br /&gt;
 .byte $10, $00, $09, $34, $70, $50, $06, $00&lt;br /&gt;
 .byte $01, $80, $00, $60, $14, $50, $05, $0D&lt;br /&gt;
 .byte $00, $90, $02, $40, $09, $00, $05, $14&lt;br /&gt;
&lt;br /&gt;
; AC00&lt;br /&gt;
&lt;br /&gt;
 .byte $0C, $C0, $3C, $F0, $FB, $3C, $3E, $F0&lt;br /&gt;
 .byte $14, $3F, $14, $00, $14, $00, $FC, $14&lt;br /&gt;
 .byte $00, $14, $00, $14, $04, $0F, $10, $00&lt;br /&gt;
 .byte $10, $00, $F0, $10, $00, $04, $00, $04&lt;br /&gt;
 .byte $00, $0E, $00, $00, $00, $00, $B0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $05, $41, $FC, $00&lt;br /&gt;
 .byte $10, $00, $00, $00, $04, $00, $00, $00&lt;br /&gt;
 .byte $0C, $33, $33, $30, $0C, $33, $03, $30&lt;br /&gt;
 .byte $00, $33, $03, $00, $00, $3F, $41, $50&lt;br /&gt;
 .byte $00, $00, $00, $04, $00, $00, $00, $10&lt;br /&gt;
 .byte $33, $33, $30, $C0, $33, $03, $30, $C0&lt;br /&gt;
 .byte $03, $03, $30, $00, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $15, $54, $00&lt;br /&gt;
 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00&lt;br /&gt;
 .byte $01, $40, $04, $40, $01, $10, $80, $08&lt;br /&gt;
 .byte $AB, $22, $BE, $2C, $23, $E0, $0A, $28&lt;br /&gt;
 .byte $AA, $A8, $01, $04, $10, $40, $08, $08&lt;br /&gt;
 .byte $20, $20, $30, $10, $04, $0C&lt;br /&gt;
&lt;br /&gt;
; AC8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00&lt;br /&gt;
 .byte $FF, $FA, $FF, $FF, $FF, $FF, $EF, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $FF, $AA, $EA&lt;br /&gt;
 .byte $FF, $FF, $00, $AE, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FF, $AB, $EB, $AB, $F0, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $DC&lt;br /&gt;
 .byte $00, $10, $00, $00, $01, $04, $00, $48&lt;br /&gt;
 .byte $00, $10, $00, $04, $04, $10, $10, $40&lt;br /&gt;
 .byte $21, $00, $04, $00, $10, $00, $04, $10&lt;br /&gt;
 .byte $05, $04, $02, $40, $00, $10, $00, $04&lt;br /&gt;
 .byte $04, $70, $10, $50, $01, $80, $04, $00&lt;br /&gt;
 .byte $10, $00, $0D, $10, $30, $10, $01, $00&lt;br /&gt;
 .byte $00, $40, $00, $10, $05, $24, $04, $0C&lt;br /&gt;
 .byte $00, $40, $01, $00, $04, $00, $18, $50&lt;br /&gt;
&lt;br /&gt;
; AD00&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $30, $30, $F3, $CC, $3E, $A0&lt;br /&gt;
 .byte $54, $0E, $54, $00, $54, $00, $B0, $15&lt;br /&gt;
 .byte $00, $15, $00, $15, $14, $0F, $50, $00&lt;br /&gt;
 .byte $50, $00, $F0, $14, $00, $05, $00, $05&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $5F, $C0&lt;br /&gt;
 .byte $40, $00, $00, $00, $10, $00, $00, $00&lt;br /&gt;
 .byte $30, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $03, $F5, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $01, $00, $00, $00, $04&lt;br /&gt;
 .byte $00, $00, $00, $30, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $24, $18, $00&lt;br /&gt;
 .byte $00, $18, $24, $00, $00, $34, $1C, $00&lt;br /&gt;
 .byte $00, $18, $24, $00, $00, $2C, $38, $00&lt;br /&gt;
 .byte $00, $00, $01, $00, $01, $00, $08, $80&lt;br /&gt;
 .byte $2B, $2A, $0F, $2C, $A8, $0A, $AE, $AB&lt;br /&gt;
 .byte $AA, $AA, $01, $44, $11, $40, $02, $20&lt;br /&gt;
 .byte $08, $80, $24, $10, $04, $18&lt;br /&gt;
&lt;br /&gt;
; AD8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF,$FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $0E&lt;br /&gt;
 .byte $FF, $FF, $FD, $55, $55, $57, $FE, $00&lt;br /&gt;
 .byte $00, $0B, $AE, $C0, $0E, $FF, $FF, $FA&lt;br /&gt;
 .byte $FA, $AF, $03, $FF, $EF, $55, $55, $55&lt;br /&gt;
 .byte $FA, $BF, $FE, $BF, $FE, $00, $05, $55&lt;br /&gt;
 .byte $55, $50, $0A, $AA, $AA, $A0, $00, $00&lt;br /&gt;
 .byte $10, $44, $00, $00, $01, $44, $00, $44&lt;br /&gt;
 .byte $00, $14, $00, $04, $01, $04, $11, $40&lt;br /&gt;
 .byte $11, $00, $14, $00, $10, $00, $10, $40&lt;br /&gt;
 .byte $01, $14, $00, $54, $00, $90, $14, $14&lt;br /&gt;
 .byte $01, $10, $14, $40, $15, $00, $06, $00&lt;br /&gt;
 .byte $14, $14, $04, $40, $24, $10, $01, $00&lt;br /&gt;
 .byte $00, $40, $30, $10, $01, $14, $04, $18&lt;br /&gt;
 .byte $00, $40, $01, $00, $04, $0C, $14, $40&lt;br /&gt;
&lt;br /&gt;
; AE00&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $00, $00, $F0, $F0, $2F, $B0&lt;br /&gt;
 .byte $10, $0B, $10, $00, $10, $00, $E0, $04&lt;br /&gt;
 .byte $00, $04, $00, $04, $38, $03, $D0, $00&lt;br /&gt;
 .byte $D0, $00, $C0, $2C, $00, $07, $00, $07&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $05, $5C&lt;br /&gt;
 .byte $00, $00, $00, $00, $40, $00, $00, $00&lt;br /&gt;
 .byte $C0, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $3F, $50, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $01&lt;br /&gt;
 .byte $00, $00, $00, $0C, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $3C, $3C, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $20, $20, $00, $00&lt;br /&gt;
 .byte $33, $AA, $0F, $AB, $AE, $2A, $A2, $8B&lt;br /&gt;
 .byte $AA, $2A, $00, $54, $15, $00, $00, $B0&lt;br /&gt;
 .byte $0E, $00, $04, $50, $05, $10&lt;br /&gt;
&lt;br /&gt;
; AE8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $35&lt;br /&gt;
 .byte $55, $55, $75, $55, $55, $55, $D5, $40&lt;br /&gt;
 .byte $02, $BB, $FF, $A0, $0A, $AA, $BF, $BF&lt;br /&gt;
 .byte $EA, $BB, $0F, $FF, $5D, $55, $55, $55&lt;br /&gt;
 .byte $7F, $FF, $FF, $FF, $FF, $C0, $15, $55&lt;br /&gt;
 .byte $55, $54, $2A, $AA, $AA, $A8, $00, $00&lt;br /&gt;
 .byte $00, $10, $00, $00, $00, $54, $00, $54&lt;br /&gt;
 .byte $00, $14, $01, $4C, $01, $44, $15, $00&lt;br /&gt;
 .byte $15, $00, $14, $00, $31, $40, $11, $40&lt;br /&gt;
 .byte $03, $D4, $03, $DC, $01, $DC, $07, $DC&lt;br /&gt;
 .byte $01, $55, $17, $C0, $37, $C0, $37, $40&lt;br /&gt;
 .byte $37, $D0, $55, $40, $04, $50, $01, $04&lt;br /&gt;
 .byte $00, $40, $0E, $D0, $00, $54, $05, $10&lt;br /&gt;
 .byte $10, $40, $01, $00, $07, $B0, $15, $00&lt;br /&gt;
&lt;br /&gt;
; AF00&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $00, $00, $C0, $00, $0B, $C0&lt;br /&gt;
 .byte $00, $03, $00, $00, $00, $00, $C0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $54&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $15, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $14, $14, $00&lt;br /&gt;
 .byte $00, $28, $28, $00, $00, $3C, $3C, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $82, $08&lt;br /&gt;
 .byte $C3, $A2, $BC, $3E, $A8, $22, $80, $00&lt;br /&gt;
 .byte $28, $0A, $00, $50, $05, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $0A, $90, $06, $A0&lt;br /&gt;
&lt;br /&gt;
; AF8E&lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF &lt;br /&gt;
&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $15&lt;br /&gt;
 .byte $55, $55, $D5, $55, $55, $55, $75, $40&lt;br /&gt;
 .byte $0A, $AA, $BE, $A8, $15, $55, $55, $55&lt;br /&gt;
 .byte $55, $57, $15, $55, $75, $55, $55, $55&lt;br /&gt;
 .byte $5D, $55, $55, $55, $55, $50, $55, $55&lt;br /&gt;
 .byte $55, $55, $AA, $AA, $AA, $AA, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $50, $00, $54&lt;br /&gt;
 .byte $00, $50, $00, $50, $00, $00, $05, $00&lt;br /&gt;
 .byte $15, $00, $05, $00, $05, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $0A, $90, $01, $90&lt;br /&gt;
 .byte $02, $60, $03, $E0, $00, $00, $06, $A0&lt;br /&gt;
 .byte $06, $40, $09, $80, $0B, $C0, $00, $00&lt;br /&gt;
&lt;br /&gt;
GameColdInit&lt;br /&gt;
ESGameColdInit&lt;br /&gt;
  SEI&lt;br /&gt;
  LDA #$60&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  LDA #$17&lt;br /&gt;
  STA INPTCTRL&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA OFFSET&lt;br /&gt;
  CLD&lt;br /&gt;
  LDX #$FF&lt;br /&gt;
  TXS&lt;br /&gt;
  JSR SystemHardwareInit&lt;br /&gt;
StartGameInDemoMode&lt;br /&gt;
  JSR AttractModeMain&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA DemoMode&lt;br /&gt;
  JSR InitializeNewGame&lt;br /&gt;
  LDA TimerHi&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$06&lt;br /&gt;
  STA DemoTimer    ; run demo for ~24-30 seconds&lt;br /&gt;
  JMP MainGameLoop&lt;br /&gt;
StartNewGameFromMenu&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA DemoMode&lt;br /&gt;
  JSR InitializeNewGame&lt;br /&gt;
&lt;br /&gt;
MainGameLoop&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  STA GamePacingTimer  ; Initialize the pacer with the current frame time&lt;br /&gt;
&lt;br /&gt;
MainGameLoop_CheckState&lt;br /&gt;
  LDA GameActiveFlag      ; Check if the game is active or in a game-over transition&lt;br /&gt;
  BEQ GameIsActiveOrDemo  ; If 0, game is running normally (or in demo)&lt;br /&gt;
&lt;br /&gt;
; Game is in the &amp;quot;ending&amp;quot; state (GameActiveFlag = 1)&lt;br /&gt;
  LDA GameEndDelayTimer&lt;br /&gt;
  BPL DecrementGameOverTimer&lt;br /&gt;
  LDA #$40                ; If timer underflowed, reset it&lt;br /&gt;
  STA GameEndDelayTimer&lt;br /&gt;
DecrementGameOverTimer&lt;br /&gt;
  JSR CheckResetSwitch    ; Allow player to reset during the game over sequence&lt;br /&gt;
  DEC GameEndDelayTimer   ; Countdown before transitioning to high score screen&lt;br /&gt;
  BNE GameIsActiveOrDemo  ; If timer still running, continue normal processing&lt;br /&gt;
&lt;br /&gt;
                          ; Game over timer has expired, transition to High Score screen&lt;br /&gt;
  JSR MuteAudio&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA CurrentPlayer        ; Set to Player 1 for first score entry&lt;br /&gt;
  JSR DoHscScoreEntry      ; Call High Score Cartridge for P1&lt;br /&gt;
  LDA PlayerCount&lt;br /&gt;
  BEQ GameOver_ScoresEntered&lt;br /&gt;
  LDA #$01                 ; If 2 players, set to Player 2&lt;br /&gt;
  STA CurrentPlayer&lt;br /&gt;
  JSR DoHscScoreEntry      ; Call High Score Cartridge for P2&lt;br /&gt;
GameOver_ScoresEntered&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  STA Temp62               ; Preserve difficulty setting&lt;br /&gt;
  JSR DoHscAttractMode     ; Show high score table&lt;br /&gt;
  JMP StartGameInDemoMode  ; After high scores, return to demo mode&lt;br /&gt;
&lt;br /&gt;
GameIsActiveOrDemo&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BEQ PacingLoop           ; If not in demo mode, skip to game pacing logic&lt;br /&gt;
  LDA TimerHi&lt;br /&gt;
  CMP DemoTimer            ; Check if the demo timer has expired&lt;br /&gt;
  BEQ StartGameInDemoMode  ; If so, restart the demo/attract sequence&lt;br /&gt;
&lt;br /&gt;
PacingLoop&lt;br /&gt;
; This loop ensures the main game logic runs at a consistent rate (every 2 frames).&lt;br /&gt;
                             ; It prevents the game speed from fluctuating based on processing load.&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GamePacingTimer&lt;br /&gt;
  CMP #$02                   ; Has the frame timer advanced by at least 2 ticks?&lt;br /&gt;
  BCC PacingLoop             ; If not, wait.&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  STA GamePacingTimer        ; Latch the new time for the next pace check&lt;br /&gt;
&lt;br /&gt;
  JSR HandleConsoleSwitches  ; Check for Pause, Reset, Select&lt;br /&gt;
  JSR UpdateAllGameObjects   ; Run all game object logic (players, enemies, eggs, etc.)&lt;br /&gt;
  JSR ESRoutineScheduler     ; Run any scheduled events (lava rising, platform dissolving, etc.)&lt;br /&gt;
  JSR ManageMessageTimers    ; Update the HUD string buffer with current scores/lives&lt;br /&gt;
&lt;br /&gt;
WaitForRender&lt;br /&gt;
; Wait here until the NMI has finished processing the previous frame's render list.&lt;br /&gt;
; This synchronizes the main logic thread with the VBlank/NMI thread.&lt;br /&gt;
  LDA RenderListDirty&lt;br /&gt;
  BNE WaitForRender&lt;br /&gt;
&lt;br /&gt;
  JSR DisplayRoutineInit       ; Prepare the render list for the upcoming frame&lt;br /&gt;
  JMP MainGameLoop_CheckState  ; Loop back to the start of the main logic&lt;br /&gt;
&lt;br /&gt;
RestartGameFromMenu&lt;br /&gt;
  LDX #$FF                  ; Reset the stack pointer&lt;br /&gt;
  TXS&lt;br /&gt;
  JMP StartNewGameFromMenu  ; Jump to start a new game&lt;br /&gt;
&lt;br /&gt;
ResetStackAndDisplayGameOptions&lt;br /&gt;
  LDX #$FF&lt;br /&gt;
  TXS&lt;br /&gt;
  JMP DisplayGameOptions&lt;br /&gt;
ResetStackAndStartGameInDemoMode&lt;br /&gt;
  LDX #$FF&lt;br /&gt;
  TXS&lt;br /&gt;
  JMP StartGameInDemoMode&lt;br /&gt;
InitializeNewGame&lt;br /&gt;
  SEI&lt;br /&gt;
  LDA #$60&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  JSR ClearRamMuteAudio&lt;br /&gt;
  JSR LoadGamePalette&lt;br /&gt;
  JSR SetColorRegisters&lt;br /&gt;
  JSR ResetMessageDisplayFlags&lt;br /&gt;
  JSR UpdateDLWithBackgroundSprites&lt;br /&gt;
WaitForVblankEnd&lt;br /&gt;
  BIT MSTAT&lt;br /&gt;
  BMI WaitForVblankEnd&lt;br /&gt;
WaitForVblankStart&lt;br /&gt;
  BIT MSTAT&lt;br /&gt;
  BPL WaitForVblankStart&lt;br /&gt;
&lt;br /&gt;
  LDA #$57&lt;br /&gt;
  STA DPPL&lt;br /&gt;
  LDA #$27&lt;br /&gt;
  STA DPPH&lt;br /&gt;
&lt;br /&gt;
  LDA #$40&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  JSR InitPlayerLivesAndBonus&lt;br /&gt;
  JSR SpawnInitialPlayerBirds&lt;br /&gt;
  JSR InitializeSpawnPlatformStates&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameEndDelayTimer&lt;br /&gt;
  LDA #$10&lt;br /&gt;
  STA BridgeBurningWidth&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA ESRoutineIndex+9&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA OldPlatformPresentBitmask&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA LevelBCD&lt;br /&gt;
  STA IsEggWave&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  JSR DisplayLevelStartMsg&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE DisplayGameStartMsg&lt;br /&gt;
  LDA #$01                        ; &amp;quot;prepare to joust&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  LDA #$12&lt;br /&gt;
  STA ESRoutineIndex+$0D&lt;br /&gt;
  LDA #SFX_GameStart&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  JSR ClearScores&lt;br /&gt;
DisplayGameStartMsg&lt;br /&gt;
  JSR UpdateScoreDisplay&lt;br /&gt;
  LDX #$01                        ; &amp;quot;prepare to joust&amp;quot;&lt;br /&gt;
  JSR UpdatePlayerLivesDisplayed&lt;br /&gt;
  DEX                             ; &amp;quot;Wave #&amp;quot;&lt;br /&gt;
  JMP UpdatePlayerLivesDisplayed&lt;br /&gt;
DisplayLevelStartMsg&lt;br /&gt;
  JSR UpdateAIParametersForLevel&lt;br /&gt;
  JSR DisplayGameStartMsg&lt;br /&gt;
  JSR SetAnyPterrysToLeaving&lt;br /&gt;
  LDA #$00                        ; &amp;quot;Wave #&amp;quot;&lt;br /&gt;
  JMP DisplayGameMessage&lt;br /&gt;
AwardEndOfWaveBonuses&lt;br /&gt;
  LDA GladiatorWaveFlag&lt;br /&gt;
  BEQ CheckForTeamWaveBonus&lt;br /&gt;
  LDA PlayerWasGladiator&lt;br /&gt;
  BNE DisplayNoGladiatorBonusMessage&lt;br /&gt;
  LDA #$0E                        ; &amp;quot;3000 gladiator&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP FinalizeGladiatorBonus&lt;br /&gt;
DisplayNoGladiatorBonusMessage&lt;br /&gt;
  LDA #$12                        ; &amp;quot;no gladiator&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
FinalizeGladiatorBonus&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlayerWasGladiator&lt;br /&gt;
  STA GladiatorWaveFlag&lt;br /&gt;
  JMP DisplayPointsAwardedMessage&lt;br /&gt;
CheckForTeamWaveBonus&lt;br /&gt;
  LDA TeamWaveFlag&lt;br /&gt;
  BEQ CheckForSurvivalWaveBonus&lt;br /&gt;
  LDA PlayersWereATeam&lt;br /&gt;
  BEQ DisplayNoTeamBonusMessage&lt;br /&gt;
  LDA #$10&lt;br /&gt;
  STA ESRoutineIndex+$0C&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  LDX #$00&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDX #$01&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDA #$0D                        ; &amp;quot;3000 team&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP DisplayPointsAwardedMessage&lt;br /&gt;
DisplayNoTeamBonusMessage&lt;br /&gt;
  LDA #$11                        ; &amp;quot;no team&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP DisplayPointsAwardedMessage&lt;br /&gt;
CheckForSurvivalWaveBonus&lt;br /&gt;
  LDA SurvivalWaveFlag&lt;br /&gt;
  BEQ ExitWaveBonusChecks&lt;br /&gt;
  LDA LevelWasSurvived&lt;br /&gt;
  BEQ DisplayNoSurvivalBonusMessage&lt;br /&gt;
  LDA #$10&lt;br /&gt;
  STA ESRoutineIndex+$0C&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  LDX #$00&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDA #$0C                        ; &amp;quot;3000 survival&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP DisplayPointsAwardedMessage&lt;br /&gt;
DisplayNoSurvivalBonusMessage&lt;br /&gt;
  LDA #$10                        ; &amp;quot;no survival&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
DisplayPointsAwardedMessage&lt;br /&gt;
  LDA #$0F                        ; &amp;quot;points awarded&amp;quot;&lt;br /&gt;
  JMP DisplayGameMessage&lt;br /&gt;
ExitWaveBonusChecks&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetupNextLevel&lt;br /&gt;
  LDA GameActiveFlag&lt;br /&gt;
  BNE ExitWaveBonusChecks&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  JSR SetAnyPterrysToLeaving&lt;br /&gt;
  JSR AwardEndOfWaveBonuses&lt;br /&gt;
  INC Level&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$28&lt;br /&gt;
  BMI SkipLevelRepeat&lt;br /&gt;
  LDA #$20      ; Levels greater than $28 repeat levels $20-$28&lt;br /&gt;
  STA Level&lt;br /&gt;
SkipLevelRepeat&lt;br /&gt;
  LDA LevelBCD  ; adjust the BCD level&lt;br /&gt;
  BEQ IncrementLevelBCD&lt;br /&gt;
  SED&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  CLD&lt;br /&gt;
  STA LevelBCD&lt;br /&gt;
IncrementLevelBCD&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE SetupNextLevelCheckWave2&lt;br /&gt;
  LDA #$0C&lt;br /&gt;
  STA ESRoutineIndex+$0A&lt;br /&gt;
  JMP FinalizeNextLevelSetup&lt;br /&gt;
SetupNextLevelCheckWave2&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE FinalizeNextLevelSetup&lt;br /&gt;
  LDA #$0E&lt;br /&gt;
  STA ESRoutineIndex+$0B&lt;br /&gt;
FinalizeNextLevelSetup&lt;br /&gt;
  LDA ESRoutineIndex+$0C&lt;br /&gt;
  BNE SkipResettingWaveEndTimer&lt;br /&gt;
  LDA #$10&lt;br /&gt;
  STA ESRoutineIndex+$0C&lt;br /&gt;
SkipResettingWaveEndTimer&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
UpdateAIParametersForLevel&lt;br /&gt;
  LDA #$AE&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC Level&lt;br /&gt;
  STA TrollMinimumGrabYCoord&lt;br /&gt;
  SBC #$18&lt;br /&gt;
  STA TrollMinimumTargetYCoord&lt;br /&gt;
&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Difficulty&lt;br /&gt;
  ADC Difficulty&lt;br /&gt;
  ASL&lt;br /&gt;
  ADC #$0A                          ; A = (2 * LEVEL) + (4 * Difficulty) + 10&lt;br /&gt;
  STA TrollPullingVelocity&lt;br /&gt;
&lt;br /&gt;
  ASL&lt;br /&gt;
  BCS AnimateTitleScreen&lt;br /&gt;
  ASL&lt;br /&gt;
AnimateTitleScreen&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  STA EnemyAITargetDelayBase&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  BNE SetAIParamsForNormalOrHarder&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$07&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA #$09&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  JMP StoreCalculatedAIPhysicsParameters&lt;br /&gt;
SetAIParamsForNormalOrHarder&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA #$09&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  LDA #$09&lt;br /&gt;
  STA Temp64&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA Temp65&lt;br /&gt;
StoreCalculatedAIPhysicsParameters&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BCS SetAIPhysicsForHigherLevels&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+1&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+2&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+3&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+4&lt;br /&gt;
&lt;br /&gt;
  LDA Temp60&lt;br /&gt;
  STA BirdPhysicsIndexMinByType&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+1&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+2&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+3&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+4&lt;br /&gt;
  JMP ResetWaveBonusFlags&lt;br /&gt;
SetAIPhysicsForHigherLevels&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+1&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+2&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+3&lt;br /&gt;
  LDA Temp63&lt;br /&gt;
  STA BirdPhysicsIndexMaxByType+4&lt;br /&gt;
  LDA Temp64&lt;br /&gt;
  STA BirdPhysicsIndexMinByType&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+1&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+2&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+3&lt;br /&gt;
  LDA Temp65&lt;br /&gt;
  STA BirdPhysicsIndexMinByType+4&lt;br /&gt;
ResetWaveBonusFlags&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA LevelWasSurvived&lt;br /&gt;
  STA PlayersWereATeam&lt;br /&gt;
  STA PlayerWasGladiator&lt;br /&gt;
  STA SurvivalWaveFlag&lt;br /&gt;
  STA TeamWaveFlag&lt;br /&gt;
  STA GladiatorWaveFlag&lt;br /&gt;
  STA PterryWave&lt;br /&gt;
  LDA Level&lt;br /&gt;
  AND #$03&lt;br /&gt;
  BNE ProcessNonEggWaveSetup&lt;br /&gt;
  LDA IsEggWave&lt;br /&gt;
  BNE ProcessNonEggWaveSetup&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA IsEggWave&lt;br /&gt;
  LDA #$03                         ; &amp;quot;Egg Wave&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  LDA #$0F&lt;br /&gt;
  STA PlatformsInLevel&lt;br /&gt;
  LDA Level                        ; Level (range from 0 to 40)&lt;br /&gt;
  LSR                              ; &lt;br /&gt;
  LSR                              ; &lt;br /&gt;
  TAX                              ; X=Level/4 (range from 0 to 10)&lt;br /&gt;
  LDA MaxEnemyBirdCountLUT,X&lt;br /&gt;
  STA MaxEnemyBirdCount&lt;br /&gt;
  LDA EggWaveEnemyTypeLUT,X&lt;br /&gt;
  STA EggWaveEnemyType&lt;br /&gt;
  DEC Level&lt;br /&gt;
  JMP FinalizeWaveSetupAndInitPlatforms&lt;br /&gt;
ProcessNonEggWaveSetup&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA IsEggWave&lt;br /&gt;
  LDX #$01&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BMI CheckForTeamWave&lt;br /&gt;
  AND #$03&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE CheckForTeamWave&lt;br /&gt;
  LDY Difficulty&lt;br /&gt;
  BEQ CheckForTeamWave&lt;br /&gt;
  STX PterryWave&lt;br /&gt;
  LDA #$05                     ; &amp;quot;Pterry Wave&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP MessageDisplayDone&lt;br /&gt;
CheckForTeamWave&lt;br /&gt;
  LDY P0Lives&lt;br /&gt;
  BMI CheckForSurvivalWave&lt;br /&gt;
  LDY P1Lives&lt;br /&gt;
  BMI CheckForSurvivalWave&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE CheckForGladiatorWave&lt;br /&gt;
  STX PlayersWereATeam&lt;br /&gt;
  STX TeamWaveFlag&lt;br /&gt;
  LDA #$07                     ; &amp;quot;Team Wave&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP MessageDisplayDone&lt;br /&gt;
CheckForGladiatorWave&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BNE MessageDisplayDone&lt;br /&gt;
  STX PlayerWasGladiator&lt;br /&gt;
  STX GladiatorWaveFlag&lt;br /&gt;
  LDA #$04                     ; &amp;quot;Gladiator Wave&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
  JMP MessageDisplayDone&lt;br /&gt;
CheckForSurvivalWave&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE MessageDisplayDone&lt;br /&gt;
  STX LevelWasSurvived&lt;br /&gt;
  STX SurvivalWaveFlag&lt;br /&gt;
  LDA #$06                     ; &amp;quot;Survival Wave&amp;quot;&lt;br /&gt;
  JSR DisplayGameMessage&lt;br /&gt;
&lt;br /&gt;
MessageDisplayDone&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  STA MaxEnemyBirdCount&lt;br /&gt;
  LDX Level&lt;br /&gt;
  LDA PlatformsInLevelLUT,X&lt;br /&gt;
  STA PlatformsInLevel&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Level&lt;br /&gt;
  TAX&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA EnemyWaveDataLUT_A,X&lt;br /&gt;
  JSR PopulateEnemyTypesForWave&lt;br /&gt;
  LDX Temp5E&lt;br /&gt;
  LDA EnemyWaveDataLUT_B,X&lt;br /&gt;
  JSR PopulateEnemyTypesForWave&lt;br /&gt;
FindNextValidEnemyTypeInWaveData&lt;br /&gt;
  DEY&lt;br /&gt;
  LDA EnemyBirdTypesForLevel,Y&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BEQ FindNextValidEnemyTypeInWaveData&lt;br /&gt;
  STY MaxActiveEnemyIndex&lt;br /&gt;
FinalizeWaveSetupAndInitPlatforms&lt;br /&gt;
  LDA #$14&lt;br /&gt;
  STA ESRoutineIndex+$11&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlatformPresentBitmask&lt;br /&gt;
  LDA PlatformsInLevel&lt;br /&gt;
  CLC&lt;br /&gt;
  AND #$08&lt;br /&gt;
  BEQ SetupPlatformsProcessTopWrapBit&lt;br /&gt;
  SEC&lt;br /&gt;
SetupPlatformsProcessTopWrapBit&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  SEC&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  SEC&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  SEC&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  CLC&lt;br /&gt;
  LDA PlatformsInLevel&lt;br /&gt;
  AND #$02&lt;br /&gt;
  STA SpawnPlatformDissolved3&lt;br /&gt;
  BEQ SetupPlatformsProcessTopCenterPlatform&lt;br /&gt;
  SEC&lt;br /&gt;
SetupPlatformsProcessTopCenterPlatform&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  CLC&lt;br /&gt;
  LDA PlatformsInLevel&lt;br /&gt;
  AND #$01&lt;br /&gt;
  BEQ SetupPlatformsProcessBottomLeftWrapBit&lt;br /&gt;
  SEC&lt;br /&gt;
SetupPlatformsProcessBottomLeftWrapBit&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  CLC&lt;br /&gt;
  LDA PlatformsInLevel&lt;br /&gt;
  AND #$01&lt;br /&gt;
  BEQ SetupPlatformsProcessBottomRightWrapBit&lt;br /&gt;
  SEC&lt;br /&gt;
SetupPlatformsProcessBottomRightWrapBit&lt;br /&gt;
  ROL PlatformPresentBitmask&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  AND #$40&lt;br /&gt;
  BEQ HandlePlatform0Removal&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$40&lt;br /&gt;
  BNE ContinuePlatformSetupCheckPlatform4&lt;br /&gt;
  LDA #$C0&lt;br /&gt;
  STA $1D45&lt;br /&gt;
  LDA #$37&lt;br /&gt;
  STA Platform0XCoordinate&lt;br /&gt;
  LDA #$17&lt;br /&gt;
  STA Platform0PaletteWidth&lt;br /&gt;
  LDA #$17&lt;br /&gt;
  STA Platform0GfxLo&lt;br /&gt;
  JMP ContinuePlatformSetupCheckPlatform4&lt;br /&gt;
HandlePlatform0Removal&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$40&lt;br /&gt;
  BEQ ContinuePlatformSetupCheckPlatform4&lt;br /&gt;
  LDA #SFX_PlatformDissolve&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$3E&lt;br /&gt;
  STA ESRoutineIndex+$10&lt;br /&gt;
ContinuePlatformSetupCheckPlatform4&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  AND #$04&lt;br /&gt;
  BEQ HandlePlatform4RemovalOrNoChange&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$04&lt;br /&gt;
  BNE SetupPlatformsContinueAfterPlatform4&lt;br /&gt;
  LDA #$A8&lt;br /&gt;
  STA $1A6F&lt;br /&gt;
  LDA #$2E&lt;br /&gt;
  STA Platform4XCoordinate&lt;br /&gt;
  LDA #$14&lt;br /&gt;
  STA Platform4PaletteWidth&lt;br /&gt;
  LDA #$AA&lt;br /&gt;
  STA Platform4GfxLo&lt;br /&gt;
  JMP SetupPlatformsContinueAfterPlatform4&lt;br /&gt;
HandlePlatform4RemovalOrNoChange&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$04&lt;br /&gt;
  BEQ SetupPlatformsContinueAfterPlatform4&lt;br /&gt;
  LDA #SFX_PlatformDissolve&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$1C&lt;br /&gt;
  STA ESRoutineIndex+$0E&lt;br /&gt;
SetupPlatformsContinueAfterPlatform4&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  AND #$02&lt;br /&gt;
  BEQ SetupPlatforms_HandleTopWrappedPlatformRemoval&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$02&lt;br /&gt;
  BNE FinalizeWavePlatformSetup&lt;br /&gt;
  LDA #$A0&lt;br /&gt;
  STA $1A15&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Platform5XCoordinate&lt;br /&gt;
  LDA #$1B&lt;br /&gt;
  STA Platform56PaletteWidth&lt;br /&gt;
  LDA #$FB&lt;br /&gt;
  STA Platform56GfxLo&lt;br /&gt;
  JMP FinalizeWavePlatformSetup&lt;br /&gt;
SetupPlatforms_HandleTopWrappedPlatformRemoval&lt;br /&gt;
  LDA OldPlatformPresentBitmask&lt;br /&gt;
  AND #$02&lt;br /&gt;
  BEQ FinalizeWavePlatformSetup&lt;br /&gt;
  LDA #SFX_PlatformDissolve&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$2D&lt;br /&gt;
  STA ESRoutineIndex+$0F&lt;br /&gt;
FinalizeWavePlatformSetup&lt;br /&gt;
  LDA PlatformPresentBitmask&lt;br /&gt;
  STA OldPlatformPresentBitmask&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PopulateEnemyTypesForWave&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDX #$03&lt;br /&gt;
UnpackEnemyTypeDataLoop&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  ASL Temp5F&lt;br /&gt;
  ROL&lt;br /&gt;
  ASL Temp5F&lt;br /&gt;
  ROL&lt;br /&gt;
  STA EnemyBirdTypesForLevel,Y&lt;br /&gt;
  INY&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL UnpackEnemyTypeDataLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ClearRamMuteAudio&lt;br /&gt;
; zero ZP $60 to $FF&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDX #$A0&lt;br /&gt;
ClearMoreZPRamLoop&lt;br /&gt;
  STA $5F,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE ClearMoreZPRamLoop&lt;br /&gt;
&lt;br /&gt;
; zero $140 to $1F7&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDX #$B8&lt;br /&gt;
ClearRamMuteAudioLoop1&lt;br /&gt;
  STA $013F,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE ClearRamMuteAudioLoop1&lt;br /&gt;
&lt;br /&gt;
  LDA #$18&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp5E  ; ($5E) = $1800&lt;br /&gt;
  LDA #$00    ; value to store in&lt;br /&gt;
  LDX #$08    ; 8 pages of ram.&lt;br /&gt;
  JSR MemSet  ; ie. zero ram from $1800 to $1FFF&lt;br /&gt;
&lt;br /&gt;
; zero $2000 to $203F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDX #$40&lt;br /&gt;
ClearRamMuteAudioLoop2&lt;br /&gt;
  STA $1FFF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE ClearRamMuteAudioLoop2&lt;br /&gt;
&lt;br /&gt;
; zero $2100 to $213F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDX #$40&lt;br /&gt;
ClearRamMuteAudioLoop3&lt;br /&gt;
  STA $20FF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE ClearRamMuteAudioLoop3&lt;br /&gt;
&lt;br /&gt;
  LDA #$22&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp5E  ; ($5E) = $2200&lt;br /&gt;
  LDA #$00    ; value to store in&lt;br /&gt;
  LDX #$05    ; 5 pages of ram.&lt;br /&gt;
  JSR MemSet  ; i.e. zero ram from $2200 to $26FF&lt;br /&gt;
&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA P0CurrentFire&lt;br /&gt;
  JSR MuteAudio&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SystemHardwareInit&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  LDX #$20  ; zero $40-$5F...&lt;br /&gt;
ClearSomeZPLoop&lt;br /&gt;
  STA $3F,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE ClearSomeZPLoop&lt;br /&gt;
&lt;br /&gt;
  LDA #$27&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp5E  ; ($5E) = $2700&lt;br /&gt;
  LDA #$00    ; value to store in&lt;br /&gt;
  LDX #$01    ; 1 page of ram.&lt;br /&gt;
  JSR MemSet  ; ie. zero ram from $1800 to $18FF&lt;br /&gt;
&lt;br /&gt;
  JSR ClearRamMuteAudio&lt;br /&gt;
  JSR InitializeFinalDisplayListPointers&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA SWACNT&lt;br /&gt;
  STA SWBCNT&lt;br /&gt;
  STA $0284&lt;br /&gt;
  LDA #$C8&lt;br /&gt;
  STA CHARBASE&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Difficulty&lt;br /&gt;
  STA INPTCTRL&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ResetMessageDisplayFlags&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  LDX #$07&lt;br /&gt;
ResetMessageFlagsLoop&lt;br /&gt;
  STA $2038,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ResetMessageFlagsLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
InitializeSpawnPlatformStates&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA SpawnPlatformDissolved0&lt;br /&gt;
  STA SpawnPlatformDissolved1&lt;br /&gt;
  STA SpawnPlatformDissolved2&lt;br /&gt;
  STA SpawnPlatformDissolved3&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
LoadGamePalette&lt;br /&gt;
  LDX #$17&lt;br /&gt;
LoadGamePaletteLoop&lt;br /&gt;
  LDA GamePalette,X&lt;br /&gt;
  STA PaletteInRam,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL LoadGamePaletteLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
LoadTitlePalette&lt;br /&gt;
  LDX #$17&lt;br /&gt;
LoadTitlePaletteLoop&lt;br /&gt;
  LDA TitlePalette,X&lt;br /&gt;
  STA PaletteInRam,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL LoadTitlePaletteLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ClearScores&lt;br /&gt;
  LDX #$02&lt;br /&gt;
  LDA #$00&lt;br /&gt;
ClearScoresLoop&lt;br /&gt;
  STA P0Score,X&lt;br /&gt;
  STA P1Score,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ClearScoresLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
MemSet&lt;br /&gt;
  LDY #$00&lt;br /&gt;
MemSetLoop&lt;br /&gt;
  STA (Temp5E),Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BNE MemSetLoop&lt;br /&gt;
  INC Temp5F&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE MemSetLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
InitializeWave&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA P0EggPointLevel&lt;br /&gt;
  STA P1EggPointLevel&lt;br /&gt;
  JSR UpdatePterryRespawnTimer&lt;br /&gt;
  LDX #$03&lt;br /&gt;
ClearPlayerWaveStartVariablesLoop&lt;br /&gt;
  STA UnusedPlayerStateArray,X&lt;br /&gt;
  STA TempSpawnUnsafeCounter,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ClearPlayerWaveStartVariablesLoop&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  LDX #$02&lt;br /&gt;
ResetPterryWaveAggressionFlagsLoop&lt;br /&gt;
  STA PterryAgressionFlag,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL ResetPterryWaveAggressionFlagsLoop&lt;br /&gt;
  LDA IsEggWave&lt;br /&gt;
  BEQ SetupStandardEnemyWave&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetupStandardEnemyWave&lt;br /&gt;
  LDX MaxActiveEnemyIndex&lt;br /&gt;
  STX EnemyBirdCount&lt;br /&gt;
  INC EnemyBirdCount&lt;br /&gt;
SpawnNextEnemyBirdLoop&lt;br /&gt;
  LDA EnemyBirdTypesForLevel,X&lt;br /&gt;
  INX&lt;br /&gt;
  INX&lt;br /&gt;
  STA ObjectBirdLevelAndType,X&lt;br /&gt;
  JSR SpawnNewBird&lt;br /&gt;
  DEX&lt;br /&gt;
  DEX&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SpawnNextEnemyBirdLoop&lt;br /&gt;
  LDA PterryWave&lt;br /&gt;
  BEQ FinalizeStandardWaveSetup&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA PterryCountdownLo&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA PterryAgressionFlag&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$0F&lt;br /&gt;
  BCC FinalizeStandardWaveSetup&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA PterryAgressionFlag+1&lt;br /&gt;
FinalizeStandardWaveSetup&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SpawnInitialPlayerBirds&lt;br /&gt;
  LDX PlayerCount&lt;br /&gt;
SpawnNextPlayerBirdLoop&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE SetInitialPlayerBirdTypeForDemo&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  JMP StoreInitialPlayerBirdType&lt;br /&gt;
SetInitialPlayerBirdTypeForDemo&lt;br /&gt;
  LDA #$01&lt;br /&gt;
StoreInitialPlayerBirdType&lt;br /&gt;
  STA ObjectBirdLevelAndType,X&lt;br /&gt;
  JSR SpawnNewBird&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BEQ SetPlayerSpawnPositionAndState&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameObjectAITimerHi,X&lt;br /&gt;
SetPlayerSpawnPositionAndState&lt;br /&gt;
  LDA PlayerStartXLUT,X&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  LDA #$A0                  ; Players start on the&lt;br /&gt;
  STA GameObjectYCoordHi,X  ; the bottom platform.&lt;br /&gt;
  LDA #$04                  ; Set alive state&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA P0FireDebounce,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SpawnNextPlayerBirdLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlayerStartXLUT&lt;br /&gt;
 .byte $46, $78&lt;br /&gt;
UpdatePterryRespawnTimer&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BEQ SetPterryRespawnTimerNormalPlay&lt;br /&gt;
  LDA #$B0&lt;br /&gt;
  STA PterryCountdownLo&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetPterryRespawnTimerNormalPlay&lt;br /&gt;
  JSR CalculateLevelDifficultyRandomTimer&lt;br /&gt;
  ROL Temp5E&lt;br /&gt;
  ROL Temp5F&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  ADC #$80&lt;br /&gt;
  STA PterryCountdownLo&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
UpdateAllGameObjects&lt;br /&gt;
  LDA P0SkidDirection&lt;br /&gt;
  ORA P1SkidDirection&lt;br /&gt;
  BNE ProcessGameObjectsMain&lt;br /&gt;
  LDA #$0F                ; skid sound effect&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
ProcessGameObjectsMain&lt;br /&gt;
  JSR RunPterryCountdown&lt;br /&gt;
&lt;br /&gt;
  LDX #$18  ; last egg object&lt;br /&gt;
EggProcessingLoop&lt;br /&gt;
  JSR RunEggObjectProcessing&lt;br /&gt;
  DEX&lt;br /&gt;
  CPX #$0D  ; first egg object&lt;br /&gt;
  BCS EggProcessingLoop&lt;br /&gt;
&lt;br /&gt;
  ; X is holding $0C, the last ptery object index&lt;br /&gt;
&lt;br /&gt;
PterryProcessingLoop&lt;br /&gt;
  JSR RunPterryProcessing&lt;br /&gt;
  DEX&lt;br /&gt;
  CPX #$0A  ; first ptero object&lt;br /&gt;
  BCS PterryProcessingLoop&lt;br /&gt;
&lt;br /&gt;
  LDX #$09&lt;br /&gt;
AllBirdsProcessingLoop        ; (player and enemy birds)&lt;br /&gt;
  JSR RunAllBirdsProcessing&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL AllBirdsProcessingLoop&lt;br /&gt;
  JSR TrollAiLogic&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SpawnNewBird&lt;br /&gt;
  LDA InitialBirdDirection,X&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
  STA GameObjectFootstepAnimTimer,X&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYCoordLo,X&lt;br /&gt;
  STA GameObjectXCoordLo,X&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  STA GameObjectInAir,X&lt;br /&gt;
  STA GameObjectPlatformSkipState,X&lt;br /&gt;
  STA GameObjectSkidDirection,X&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  STA GameObjectAITargetDelayTimer,X&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X           ; A = 0 to 2 (excluding pterry)&lt;br /&gt;
  ASL                                    ; A = 0 to 4&lt;br /&gt;
  ASL                                    ; A = 0 to 8&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Difficulty                         ; A = 0 to 11&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA AIModeByBirdTypeAndDifficultyLUT,Y&lt;br /&gt;
  CMP Level&lt;br /&gt;
  BCS StoreCalculatedAIMode&lt;br /&gt;
  LDA #$00&lt;br /&gt;
StoreCalculatedAIMode&lt;br /&gt;
  STA GameObjectAIMode,X&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  LDA #$03&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA #$03                               ; state=born1&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  LDA Level&lt;br /&gt;
  CMP #$40&lt;br /&gt;
  BCC ClampLevelTo64&lt;br /&gt;
  LDA #$40&lt;br /&gt;
ClampLevelTo64&lt;br /&gt;
  LSR&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Difficulty&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BCC ClampTurnTimerIndex&lt;br /&gt;
  LDA #$03&lt;br /&gt;
ClampTurnTimerIndex&lt;br /&gt;
  STA TempCollisionOverlap&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC TempCollisionOverlap&lt;br /&gt;
  STA GameObjectTurnTimerIndex,X&lt;br /&gt;
  TAY&lt;br /&gt;
  JSR ReturnRandInA&lt;br /&gt;
  AND #$7F&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC TurnCheckTimerValuesLoLUT,Y&lt;br /&gt;
  STA GameObjectTurnCheckTimerLo,X&lt;br /&gt;
  LDA TurnCheckTimerValuesHiLUT,Y&lt;br /&gt;
  ADC #$00&lt;br /&gt;
  STA GameObjectTurnCheckTimerHi,X&lt;br /&gt;
  LDA Temp66&lt;br /&gt;
  CMP #$08&lt;br /&gt;
  BCC StoreCalculatedAITimers&lt;br /&gt;
  LDA #$07&lt;br /&gt;
StoreCalculatedAITimers&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA AITimerByBirdTypeAndDifficultyLoLUT,Y&lt;br /&gt;
  STA GameObjectAITimerLo,X&lt;br /&gt;
  LDA AITimerByBirdTypeAndDifficultyHiLUT,Y&lt;br /&gt;
  STA GameObjectAITimerHi,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
RunAllBirdsProcessing&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  BNE BirdIsAlive&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdIsAlive&lt;br /&gt;
  CMP #$03                     ; ** 3 is the bird init first state &amp;quot;born1&amp;quot;&lt;br /&gt;
  BNE BirdIsPastInit&lt;br /&gt;
  DEC GameObjectCountdownLo,X  ; ** delay before next init state&lt;br /&gt;
  BPL ExitAllBirdsProcessing1&lt;br /&gt;
  LDA #$07                     ; ** 7 is the bird init second state &amp;quot;born2&amp;quot;&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
ExitAllBirdsProcessing1&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdIsPastInit&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BNE NOPBranch          ; pointless&lt;br /&gt;
NOPBranch&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$06               ; Is bird invincible?&lt;br /&gt;
  BNE BirdIsntInvincible&lt;br /&gt;
  JMP BirdBorn1Processing&lt;br /&gt;
BirdIsntInvincible&lt;br /&gt;
  CMP #$07               ; Is bird on second init stage?&lt;br /&gt;
  BNE BirdIsntInit2&lt;br /&gt;
  JMP BirdBorn2Processing&lt;br /&gt;
BirdIsntInit2&lt;br /&gt;
                         ; if we're here, the bird state must be regular(4) or riderless($14)&lt;br /&gt;
  CPX #$02               ; players are the first 2 objects&lt;br /&gt;
  BCC PlayerBirdLogic    ; If it's an Enemy Bird then fall-through&lt;br /&gt;
  JSR AutoPilotBirdLogic&lt;br /&gt;
  JMP ProcessCommonBirdPhysicsAndCollisions&lt;br /&gt;
PlayerBirdLogic&lt;br /&gt;
  JSR PlayerHitLogic&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BEQ ProcessBirdPhysicsCommon&lt;br /&gt;
  JSR HandlePlayerVsPterry&lt;br /&gt;
ProcessCommonBirdPhysicsAndCollisions&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BEQ ProcessBirdPhysicsCommon&lt;br /&gt;
  JSR ProcessBirdToBirdCollisionLoop&lt;br /&gt;
ProcessBirdPhysicsCommon&lt;br /&gt;
  JSR ProcessBirdPlatformInteraction&lt;br /&gt;
  JSR UpdateAirborneObjectPhysics&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BEQ ProcessOnPlatformBirdLogic&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessOnPlatformBirdLogic&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BEQ ProcessOnPlatformMovement&lt;br /&gt;
  JMP ProcessSkidDeceleration&lt;br /&gt;
ProcessOnPlatformMovement&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BNE ProcessFootstepAnimation&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessFootstepAnimation&lt;br /&gt;
  LDA GameObjectFootstepAnimTimer,X&lt;br /&gt;
  BEQ AdvanceFootstepAnimation&lt;br /&gt;
  DEC GameObjectFootstepAnimTimer,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AdvanceFootstepAnimation&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  CLC&lt;br /&gt;
  BMI CalculateFootstepTimerFromAbsXVel&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CalculateFootstepTimerFromAbsXVel&lt;br /&gt;
  ADC #$02&lt;br /&gt;
  BMI AdvanceFootstepAnimSlowestSpeed&lt;br /&gt;
  STA GameObjectFootstepAnimTimer,X&lt;br /&gt;
  INC GameObjectFootstepAnimIndex,X&lt;br /&gt;
  LDA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BCC FinishFootstepAnimationCycle&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
FinishFootstepAnimationCycle&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AdvanceFootstepAnimSlowestSpeed&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BNE FootstepAnim_Slow_DoubleFrameIncrement&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectFootstepAnimTimer,X&lt;br /&gt;
  INC GameObjectFootstepAnimIndex,X&lt;br /&gt;
  LDA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE FootstepAnim_Slowest_CheckCycleEnd&lt;br /&gt;
  INC GameObjectFootstepAnimIndex,X&lt;br /&gt;
  LDA GameObjectFootstepAnimIndex,X&lt;br /&gt;
FootstepAnim_Slowest_CheckCycleEnd&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BCC FootstepAnim_Slowest_FinishFrame&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
FootstepAnim_Slowest_FinishFrame&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
FootstepAnim_Slow_DoubleFrameIncrement&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectFootstepAnimTimer,X&lt;br /&gt;
  INC GameObjectFootstepAnimIndex,X&lt;br /&gt;
  INC GameObjectFootstepAnimIndex,X&lt;br /&gt;
  LDA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BCC FootstepAnim_Slow_FinishFrame&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
  LDA #SFX_PlayerFootstep&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
FootstepAnim_Slow_FinishFrame&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessSkidDeceleration&lt;br /&gt;
  LDA GameObjectChargingTimer,X&lt;br /&gt;
  BEQ ApplySkidDeceleration&lt;br /&gt;
  DEC GameObjectChargingTimer,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ApplySkidDeceleration&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BMI ApplyNegativeVelocitySkidDeceleration&lt;br /&gt;
  DEC GameObjectXVelocity,X&lt;br /&gt;
  JMP ContinueSkidDeceleration&lt;br /&gt;
ApplyNegativeVelocitySkidDeceleration&lt;br /&gt;
  INC GameObjectXVelocity,X&lt;br /&gt;
ContinueSkidDeceleration&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  BEQ FinalizeSkidBirdStopped&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
FinalizeSkidBirdStopped&lt;br /&gt;
  JSR ClearSkidStateAndSound&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdBorn1Processing&lt;br /&gt;
  DEC BirdInvulnerable,X&lt;br /&gt;
  BMI StartSpawnAnimationSequence&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
StartSpawnAnimationSequence&lt;br /&gt;
  LDY GameObjectHunterIndex,X&lt;br /&gt;
  LDA BirdSpawnInvulnAnimStateSequence_TypeA,Y&lt;br /&gt;
  CMP #$00&lt;br /&gt;
  BNE DispatchSpawnAnimationState&lt;br /&gt;
  DEC GameObjectYCoordHi,X&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
DispatchSpawnAnimationState&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE PlayerAirSteering&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS HandleEnemyBirdSpawnAnimationState       ; branch if non-player enemy bird&lt;br /&gt;
  LDA #SFX_Invulnerable&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
HandleEnemyBirdSpawnAnimationState&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA EnemyIsSpawning&lt;br /&gt;
  JMP SpawnAnim_FinalizeAndSetStateNormal&lt;br /&gt;
ProcessSpawnAnimationOrPlayerSteering&lt;br /&gt;
  JSR SpawnAnim_FinalizeAndSetStateNormal&lt;br /&gt;
  JMP PlayerBirdLogic&lt;br /&gt;
PlayerAirSteering&lt;br /&gt;
  LDA P0CurrentFire,X&lt;br /&gt;
  BPL ProcessSpawnAnimationOrPlayerSteering    ; Only when the player bird flaps &lt;br /&gt;
  LDA SWCHA&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BEQ SkipJoystickShift&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL                                          ; Shift the lower j1 nibble into&lt;br /&gt;
  ASL                                          ; the higher j0 nibble postition&lt;br /&gt;
  ASL&lt;br /&gt;
SkipJoystickShift&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC ProcessSpawnAnimationOrPlayerSteering    ; Right&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC ProcessSpawnAnimationOrPlayerSteering    ; Left&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC ProcessSpawnAnimationOrPlayerSteering    ; Down&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC ProcessSpawnAnimationOrPlayerSteering    ; Up&lt;br /&gt;
  LDA BirdSpawnInvulnAnimStateSequence_TypeA,Y&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BNE CheckSpawnAnimState3&lt;br /&gt;
  JSR SetPlayerSpawnInvulnerablePalette&lt;br /&gt;
  LDA #$9C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$BA&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA #$7E&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JSR UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
CheckSpawnAnimState3&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BNE SpawnAnimCheckState4&lt;br /&gt;
  JSR SetPlayerPaletteInRam&lt;br /&gt;
  LDA #$9C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$BA&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA RiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JSR UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
SpawnAnimCheckState4&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BNE SpawnAnim_CheckState5&lt;br /&gt;
  JSR SetPlayerSpawnInvulnerablePalette&lt;br /&gt;
  LDA #$7C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA SpawnRiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JSR UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
SpawnAnim_CheckState5&lt;br /&gt;
  CMP #$05&lt;br /&gt;
  BNE SpawnAnim_CheckState6&lt;br /&gt;
  JSR SetPlayersSpawnPalette&lt;br /&gt;
  LDA #$9C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$BA&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA RiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JSR UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
SpawnAnim_CheckState6&lt;br /&gt;
  CMP #$06&lt;br /&gt;
  BNE SpawnAnim_FinalizeAndSetStateNormal&lt;br /&gt;
  JSR SetPlayerSpawnInvulnerablePalette&lt;br /&gt;
  LDA #$5C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$BA&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JSR UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  JMP AdvanceSpawnAnimationState&lt;br /&gt;
SpawnAnim_FinalizeAndSetStateNormal&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS FinalizeBirdSpawnAndSetState        ; branch if non-player enemy bird&lt;br /&gt;
  LDA #$0A                                ; player invulnerable sound effect&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
FinalizeBirdSpawnAndSetState&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA P0CurrentFire,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  STA P0FireDebounce,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  JSR SetPlayersSpawnPalette&lt;br /&gt;
  LDA #$5C&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA #$BA&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA RiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDA BirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp63&lt;br /&gt;
  JMP UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
AdvanceSpawnAnimationState&lt;br /&gt;
  LDA BirdSpawnInvulnAnimStateSequence_TypeB,Y&lt;br /&gt;
  STA BirdInvulnerable,X&lt;br /&gt;
  INC GameObjectHunterIndex,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdBorn2Processing&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCC PlayerBorn2     ; branch if it's a player bird&lt;br /&gt;
  LDA EnemyIsSpawning&lt;br /&gt;
  BEQ CheckForPterryBeforeSpawning&lt;br /&gt;
DelaySpawnIfAnotherEnemySpawning&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlayerBorn2&lt;br /&gt;
  LDA P0Lives,X&lt;br /&gt;
  BPL ProceedWithSpawnSafetyCheck&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CheckForPterryBeforeSpawning&lt;br /&gt;
  LDA PterryState1&lt;br /&gt;
  ORA PterryState2&lt;br /&gt;
  ORA PterryState3&lt;br /&gt;
  BEQ ProceedWithSpawnSafetyCheck&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProceedWithSpawnSafetyCheck&lt;br /&gt;
  JSR SpawnPointSafetyCheck&lt;br /&gt;
  LDA Temp60&lt;br /&gt;
  BMI DelaySpawnIfAnotherEnemySpawning&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCC SpawnPlayerBird                 ; branch if it's a player bird&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA EnemyIsSpawning&lt;br /&gt;
SpawnPlayerBird&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  LDA $60&lt;br /&gt;
  STA GameObjectSpawnPlatformIndex,X&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA PlayerRespawnX,Y&lt;br /&gt;
  STA GameObjectXCoordHi,X&lt;br /&gt;
  LDA PlayerRespawnY,Y&lt;br /&gt;
  STA GameObjectYCoordHi,X&lt;br /&gt;
  LDA #$06&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectInAir,X&lt;br /&gt;
  STA GameObjectHunterIndex,X&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  STA BirdInvulnerable,X&lt;br /&gt;
  LDA BirdBornSFXType,X     ; different sounds for birds being born,&lt;br /&gt;
  JSR ScheduleSFX           ; depending on it being a player or enemy.&lt;br /&gt;
  JSR SetPlayerPaletteInRam&lt;br /&gt;
  LDA SpawnPlatformPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp60PaletteAndWidth&lt;br /&gt;
  LDA SpawnRiderPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  LDA SpawnBirdPaletteAndWidthLUT,X&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  STA Temp63&lt;br /&gt;
UpdatePlatformDLWithSpawnedBirdGfx&lt;br /&gt;
  LDY GameObjectSpawnPlatformIndex,X&lt;br /&gt;
  LDA SpawnPlatformDLObjectLoLUT,Y&lt;br /&gt;
  STA Temp5EGfxDataLo&lt;br /&gt;
  LDA SpawnPlatformDLObjectHiLUT,Y&lt;br /&gt;
  STA Temp5FGfxDataHi&lt;br /&gt;
  LDY #$01&lt;br /&gt;
  LDA Temp60PaletteAndWidth&lt;br /&gt;
  STA (Temp5E),Y&lt;br /&gt;
  DEY&lt;br /&gt;
  LDA Temp61&lt;br /&gt;
  STA (Temp5E),Y&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  STA RiderObjectPaletteAndWidth,X&lt;br /&gt;
  LDA Temp63&lt;br /&gt;
  STA BirdObjectPaletteAndWidth,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetPlayerPaletteInRam&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BNE SetPlayer1Palette&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA P5C1_Ram&lt;br /&gt;
  STA P5C2_Ram&lt;br /&gt;
  STA P5C3_Ram&lt;br /&gt;
  JMP UpdatePlayerLivesDisplayed&lt;br /&gt;
SetPlayer1Palette&lt;br /&gt;
  CPX #$01&lt;br /&gt;
  BNE SetPaletteHandleEnemyBird&lt;br /&gt;
  LDA #$BC&lt;br /&gt;
  STA P6C1_Ram&lt;br /&gt;
  STA P6C2_Ram&lt;br /&gt;
  STA P6C3_Ram&lt;br /&gt;
  JMP UpdatePlayerLivesDisplayed&lt;br /&gt;
SetPaletteHandleEnemyBird&lt;br /&gt;
  LDA #$0D&lt;br /&gt;
  STA P4C1_Ram&lt;br /&gt;
  STA P4C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetPlayerSpawnInvulnerablePalette&lt;br /&gt;
  LDA #$0D&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BNE SetSpawnInvulnPalette_HandlePlayer1&lt;br /&gt;
  STA P5C1_Ram&lt;br /&gt;
  STA P5C2_Ram&lt;br /&gt;
  STA P5C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetSpawnInvulnPalette_HandlePlayer1&lt;br /&gt;
  STA P6C1_Ram&lt;br /&gt;
  STA P6C2_Ram&lt;br /&gt;
  STA P6C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetPlayersSpawnPalette&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BNE SetPlayer1SpawnPalette&lt;br /&gt;
SetPlayer0SpawnPalette&lt;br /&gt;
  LDA #$15&lt;br /&gt;
  STA P5C1_Ram&lt;br /&gt;
  LDA #$A9&lt;br /&gt;
  STA P5C2_Ram&lt;br /&gt;
  LDA #$85&lt;br /&gt;
  STA P5C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetPlayer1SpawnPalette&lt;br /&gt;
  CPX #$01&lt;br /&gt;
  BNE SetEnemySpawnPalette&lt;br /&gt;
  LDA #$0D&lt;br /&gt;
  STA P6C1_Ram&lt;br /&gt;
  LDA #$1C&lt;br /&gt;
  STA P6C2_Ram&lt;br /&gt;
  LDA #$44&lt;br /&gt;
  STA P6C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetEnemySpawnPalette&lt;br /&gt;
  LDA #$39&lt;br /&gt;
  STA P4C1_Ram&lt;br /&gt;
  LDA #$33&lt;br /&gt;
  STA P4C3_Ram&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
PlayerHitLogic&lt;br /&gt;
  LDA P0Lives,X&lt;br /&gt;
  BPL ProcessActivePlayerLogic&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$05&lt;br /&gt;
  BEQ ProcessActivePlayerLogic&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ProcessActivePlayerLogic&lt;br /&gt;
  LDA GameObjectAlive,X&lt;br /&gt;
  BNE ProcessActivePlayerCollisionsAndInput&lt;br /&gt;
  JMP AutoPilotBirdLogic&lt;br /&gt;
ProcessActivePlayerCollisionsAndInput&lt;br /&gt;
  JSR CheckPlayerEggCollision&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BEQ ProcessPlayerInput&lt;br /&gt;
  JMP AutoPilotBirdLogic&lt;br /&gt;
ProcessPlayerInput&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA P0CurrentFire,X&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  CMP P0FireDebounce,X&lt;br /&gt;
  BEQ ProcessPlayerJoystickInput&lt;br /&gt;
  STA P0FireDebounce,X&lt;br /&gt;
  LDA Temp5F&lt;br /&gt;
  BMI PlayerNoFlapResetAnimation&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  JSR ApplyFlapPhysics&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BEQ ContinuePlayerInputAfterFlap&lt;br /&gt;
  JSR ClearSkidStateAndSound&lt;br /&gt;
ContinuePlayerInputAfterFlap&lt;br /&gt;
  JMP ProcessPlayerJoystickInput&lt;br /&gt;
PlayerNoFlapResetAnimation&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
ProcessPlayerJoystickInput&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BNE ProcessAirbornePlayerInput&lt;br /&gt;
  LDA P0JoyDelay,X&lt;br /&gt;
  BEQ ResetOnPlatformJoyDelay&lt;br /&gt;
  DEC P0JoyDelay,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ResetOnPlatformJoyDelay&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA P0JoyDelay,X&lt;br /&gt;
ProcessAirbornePlayerInput&lt;br /&gt;
  LDA SWCHA&lt;br /&gt;
  CPX #$00&lt;br /&gt;
  BEQ ProcessNormalizedJoystickInput&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
ProcessNormalizedJoystickInput&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC HandlePlayerJoyRight_PlatformOrAir&lt;br /&gt;
  ASL&lt;br /&gt;
  BCC HandlePlayerJoyLeft_PlatformOrAir&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; Player On-Platform Horizontal Movement &amp;amp; Airborne Steering Logic&lt;br /&gt;
;&lt;br /&gt;
; This section handles player joystick input (Left/Right). Its behavior differs&lt;br /&gt;
; based on whether the bird is on a platform or airborne.&lt;br /&gt;
;&lt;br /&gt;
; - Airborne: The joystick changes the bird's facing direction. If the fire&lt;br /&gt;
;   button is also pressed (flapping), it applies horizontal acceleration.&lt;br /&gt;
;&lt;br /&gt;
; - On-Platform: The joystick controls walking. If the player reverses direction&lt;br /&gt;
;   while moving above a certain speed, a &amp;quot;skid&amp;quot; is initiated. Pressing the&lt;br /&gt;
;   opposite direction again will cancel the skid.&lt;br /&gt;
;&lt;br /&gt;
; Input:&lt;br /&gt;
;   X = CurrentPlayer index (0 or 1)&lt;br /&gt;
;   Temp5E (from outer context): Holds 1 if fire button was pressed this frame&lt;br /&gt;
;                                (flapping), 0 otherwise.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandlePlayerJoyLeft_PlatformOrAir&lt;br /&gt;
    LDA GameObjectInAir,X&lt;br /&gt;
    BEQ PlayerOnPlatform_JoyLeft_CheckVelocity  ; If on platform, jump to on-platform logic.&lt;br /&gt;
                                                ; Bird is AIRBORNE with joystick LEFT&lt;br /&gt;
    LDA #Direction_Left                         ; Face left.&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
    LDY Temp5E                                  ; Temp5E holds 1 if flapping, 0 if not.&lt;br /&gt;
    BEQ PlatformMovementOrAirborne_RTS1         ; If not flapping, just steer and exit.&lt;br /&gt;
                                                ; Fall through to accelerate if flapping in air.&lt;br /&gt;
&lt;br /&gt;
AccelerateBirdLeft_PlatformOrAir  ; Shared target for airborne left flap &amp;amp; on-platform left acceleration.&lt;br /&gt;
    DEC GameObjectXVelocity,X     ; Decrease X-velocity (move more left or less right).&lt;br /&gt;
PlatformMovementOrAirborne_RTS1&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
PlayerOnPlatform_JoyLeft_CheckVelocity             ; On Platform, Joy Left: Check current X Velocity&lt;br /&gt;
    LDA GameObjectXVelocity,X&lt;br /&gt;
    BEQ BirdStopped_Platform_JoyLeft               ; If X-velocity is 0, bird is stopped.&lt;br /&gt;
    BPL BirdMovingRight_Platform_JoyLeft           ; If &amp;gt;0, bird moving/skidding right.&lt;br /&gt;
                                                   ; Bird is already moving/skidding left (X-velocity is negative).&lt;br /&gt;
    BNE BirdMovingOrSkiddingLeft_Platform_JoyLeft  ; Always taken if XVel &amp;lt; 0.&lt;br /&gt;
&lt;br /&gt;
BirdStopped_Platform_JoyLeft&lt;br /&gt;
    LDA GameObjectDirection,X             ; Bird was stationary. Get current facing direction.&lt;br /&gt;
    BMI AccelerateBirdLeft_PlatformOrAir  ; If already facing left ($FF), try to accelerate left.&lt;br /&gt;
                                          ; Else, was facing right ($01).&lt;br /&gt;
    LDA #Direction_Left                   ; Change direction to Left ($FF).&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
PlatformMovementOrAirborne_RTS2           ; Also used as common RTS for some skid conditions.&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
BirdMovingRight_Platform_JoyLeft                   ; Bird was moving/skidding right, joystick now left.&lt;br /&gt;
    CMP #SKID_VELOCITY_THRESHOLD_RIGHT             ; Compare current X-velocity with skid threshold.&lt;br /&gt;
    BCC BirdMovingOrSkiddingLeft_Platform_JoyLeft  ; If VelX &amp;lt; Threshold (moving slowly right), don't skid.&lt;br /&gt;
                                                   ; Attempt to move left (effectively braking then accelerating).&lt;br /&gt;
                                                   ; Bird is moving right quickly enough to skid if direction changes.&lt;br /&gt;
    LDA GameObjectSkidDirection,X                  ; Is bird already skidding?&lt;br /&gt;
    BNE PlatformMovementOrAirborne_RTS2            ; Yes, already skidding (likely right): let skid resolve. RTS.&lt;br /&gt;
                                                   ; Not skidding, but moving right quickly and joystick is left: Initiate SKID to the RIGHT.&lt;br /&gt;
    INC GameObjectYCoordHi,X                       ; Visual effect: bird hops up slightly when skidding starts.&lt;br /&gt;
    LDA #Direction_Right                           ; Set skid direction to RIGHT ($01) because we were moving right.&lt;br /&gt;
    STA GameObjectSkidDirection,X&lt;br /&gt;
    LDA #SKID_ANIMATION_FRAME                      ; Set animation to skid frame.&lt;br /&gt;
    STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
    LDA #SFX_Skid                                  ; Schedule skid sound effect.&lt;br /&gt;
    JMP ScheduleSFX&lt;br /&gt;
&lt;br /&gt;
BirdMovingOrSkiddingLeft_Platform_JoyLeft   ; Arrived here if: (XVel &amp;lt; 0) OR (XVel &amp;gt; 0 but &amp;lt; SKID_THRESHOLD_RIGHT)&lt;br /&gt;
    LDA GameObjectSkidDirection,X           ; Check if already skidding.&lt;br /&gt;
    BEQ AccelerateBirdLeft_PlatformOrAir    ; Not skidding: try to accelerate left.&lt;br /&gt;
                                            ; Already skidding.&lt;br /&gt;
    BPL PlatformMovementOrAirborne_RTS2     ; Skidding right ($01), joy left (anti-skid): RTS.&lt;br /&gt;
                                            ; Skidding left ($FF), joy left (reinforce skid).&lt;br /&gt;
    JSR ClearSkidStateAndSound              ; Clear the skid state (was skidding left, now actively moving left).&lt;br /&gt;
    JMP AccelerateBirdLeft_PlatformOrAir    ; And try to accelerate left.&lt;br /&gt;
&lt;br /&gt;
HandlePlayerJoyRight_PlatformOrAir&lt;br /&gt;
    LDA GameObjectInAir,X&lt;br /&gt;
    BEQ PlayerOnPlatform_JoyRight_CheckVelocity  ; If on platform, jump to on-platform logic.&lt;br /&gt;
                                                 ; Bird is AIRBORNE with joystick RIGHT&lt;br /&gt;
    LDA #Direction_Right                         ; Face right.&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
    LDY Temp5E                                   ; Temp5E has flap status (1 if flapping).&lt;br /&gt;
    BEQ PlatformMovementOrAirborne_RTS1          ; If not flapping, just steer and exit.&lt;br /&gt;
                                                 ; Fall through to accelerate if flapping in air.&lt;br /&gt;
&lt;br /&gt;
AccelerateBirdRight_PlatformOrAir   ; Shared target for airborne right flap &amp;amp; on-platform right acceleration.&lt;br /&gt;
    INC GameObjectXVelocity,X       ; Increase X-velocity (move more right or less left).&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
PlayerOnPlatform_JoyRight_CheckVelocity              ; On Platform, Joy Right: Check current X Velocity&lt;br /&gt;
    LDA GameObjectXVelocity,X&lt;br /&gt;
    BMI BirdMovingLeft_Platform_JoyRight             ; If &amp;lt;0, bird moving/skidding left.&lt;br /&gt;
    BNE BirdMovingOrSkiddingRight_Platform_JoyRight  ; If &amp;gt;0 (and non-zero), bird moving/skidding right.&lt;br /&gt;
                                                     ; Bird is stopped (X-velocity is 0).&lt;br /&gt;
BirdStopped_Platform_JoyRight&lt;br /&gt;
    LDA GameObjectDirection,X                        ; Get current facing direction.&lt;br /&gt;
    BPL AccelerateBirdRight_PlatformOrAir            ; If already facing right ($01), try to accelerate right.&lt;br /&gt;
                                                     ; Else, was facing left ($FF).&lt;br /&gt;
    LDA #Direction_Right                             ; Change direction to Right ($01).&lt;br /&gt;
    STA GameObjectDirection,X&lt;br /&gt;
PlatformMovementOrAirborne_RTS4                      ; Also used as common RTS for some skid conditions.&lt;br /&gt;
    RTS&lt;br /&gt;
&lt;br /&gt;
BirdMovingLeft_Platform_JoyRight                     ; Bird was moving/skidding left, joystick now right.&lt;br /&gt;
    CMP #SKID_VELOCITY_THRESHOLD_LEFT                ; Compare current X-velocity with skid threshold (-2).&lt;br /&gt;
    BCS BirdMovingOrSkiddingRight_Platform_JoyRight  ; If VelX &amp;gt;= Threshold (moving slowly left), don't skid.&lt;br /&gt;
                                                     ; Attempt to move right (effectively braking then accelerating).&lt;br /&gt;
                                                     ; Bird is moving left quickly enough to skid.&lt;br /&gt;
    LDA GameObjectSkidDirection,X                    ; Is bird already skidding?&lt;br /&gt;
    BNE PlatformMovementOrAirborne_RTS4              ; Yes, already skidding (likely left): let skid resolve. RTS.&lt;br /&gt;
                                                     ; Not skidding, but moving left quickly and joystick is right: Initiate SKID to the LEFT.&lt;br /&gt;
    INC GameObjectYCoordHi,X                         ; Visual hop.&lt;br /&gt;
    LDA #Direction_Left                              ; Set skid direction to LEFT ($FF) because we were moving left.&lt;br /&gt;
    STA GameObjectSkidDirection,X&lt;br /&gt;
    LDA #SKID_ANIMATION_FRAME&lt;br /&gt;
    STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
    LDA #SFX_Skid&lt;br /&gt;
    JMP ScheduleSFX&lt;br /&gt;
&lt;br /&gt;
BirdMovingOrSkiddingRight_Platform_JoyRight   ; Arrived here if: (XVel &amp;gt; 0) OR (XVel &amp;lt; 0 but &amp;gt; SKID_THRESHOLD_LEFT)&lt;br /&gt;
    LDA GameObjectSkidDirection,X             ; Check if already skidding.&lt;br /&gt;
    BEQ AccelerateBirdRight_PlatformOrAir     ; Not skidding: try to accelerate right.&lt;br /&gt;
                                              ; Already skidding.&lt;br /&gt;
    BMI PlatformMovementOrAirborne_RTS4       ; Skidding left ($FF), joy right (anti-skid): RTS.&lt;br /&gt;
                                              ; Skidding right ($01), joy right (reinforce skid).&lt;br /&gt;
    JSR ClearSkidStateAndSound                ; Clear skid state, now actively moving right.&lt;br /&gt;
    JMP AccelerateBirdRight_PlatformOrAir     ; And try to accelerate right.&lt;br /&gt;
&lt;br /&gt;
EnemyBirdIsSeekingRider&lt;br /&gt;
  LDY GameObjectPreyIndex,X&lt;br /&gt;
  CMP #$14&lt;br /&gt;
  BNE HunterBirdAICheckPrepareToSlideState&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  CMP GameObjectXVelocity,X&lt;br /&gt;
  BEQ HunterBirdAIContinueAfterVelocityUpdate&lt;br /&gt;
  ASL&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
HunterBirdAIContinueAfterVelocityUpdate&lt;br /&gt;
  JSR DetermineAIActionBasedOnProximity&lt;br /&gt;
  LDY GameObjectPreyIndex,X&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  BEQ UpdateHunterBirdYPosition&lt;br /&gt;
  BMI HunterBirdMoveUpward&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  JMP UpdateHunterBirdYPosition&lt;br /&gt;
HunterBirdMoveUpward&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  BMI UpdateHunterBirdYPosition&lt;br /&gt;
  LDA #$80&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
UpdateHunterBirdYPosition&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$06&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCC HunterBirdDescendTowardRider&lt;br /&gt;
  DEC GameObjectYCoordHi,X&lt;br /&gt;
HunterBirdDescendTowardRider&lt;br /&gt;
  LDY GameObjectPreyIndex,X&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GameObjectXCoordHi,X&lt;br /&gt;
  BPL HunterBirdCheckXProximityToRider&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
HunterBirdCheckXProximityToRider&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BCS HunterAIContinueSeekingRider&lt;br /&gt;
  LDA #$15&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
HunterAIContinueSeekingRider&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HunterBirdAICheckPrepareToSlideState&lt;br /&gt;
  CMP #$15&lt;br /&gt;
  BNE HunterBirdHandleSlidingState&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$06&lt;br /&gt;
  CMP GameObjectYCoordHi,X&lt;br /&gt;
  BCS HunterBirdInitiateSlide&lt;br /&gt;
HunterBirdRepositionAfterSlideFail&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA #$14&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HunterBirdInitiateSlide&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BNE SkipHunterBirdSlideInitiation&lt;br /&gt;
  LDA #$16&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  STA GameObjectSkidDirection,X&lt;br /&gt;
  INC GameObjectYCoordHi,X&lt;br /&gt;
  LDA #$04                      ; riderless bird time to slide toward rider&lt;br /&gt;
  STA GameObjectChargingTimer,X&lt;br /&gt;
SkipHunterBirdSlideInitiation&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HunterBirdHandleSlidingState&lt;br /&gt;
  CMP #$16&lt;br /&gt;
  BNE HunterBirdFinalApproach&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$06&lt;br /&gt;
  CMP GameObjectYCoordHi,X&lt;br /&gt;
  BCS HunterSlideVerticalAlignOK&lt;br /&gt;
  JMP HunterBirdRepositionAfterSlideFail&lt;br /&gt;
HunterSlideVerticalAlignOK&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  CMP GameObjectXCoordHi,X&lt;br /&gt;
  BNE HunterSlideContinueApproach&lt;br /&gt;
  JMP HunterBirdReachedRider&lt;br /&gt;
HunterSlideContinueApproach&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BNE HunterSlideMaintainSkidDirection&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  STA GameObjectDirection,X&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  LDA #$17&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
HunterSlideMaintainSkidDirection&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HunterBirdFinalApproach&lt;br /&gt;
  LDA GameObjectYCoordHi,Y&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$06&lt;br /&gt;
  CMP GameObjectYCoordHi,X&lt;br /&gt;
  BCS HunterBirdTargetStillValidContinueApproach&lt;br /&gt;
  JMP HunterBirdRepositionAfterSlideFail&lt;br /&gt;
HunterBirdTargetStillValidContinueApproach&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  LDA GameObjectXCoordHi,Y&lt;br /&gt;
  CMP GameObjectXCoordHi,X&lt;br /&gt;
  BNE HunterBirdFinishRiderPickup&lt;br /&gt;
HunterBirdReachedRider&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA GameObjectPreyIndex,X&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$0A&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
  STA GameObjectAITimerLo,X&lt;br /&gt;
  STA GameObjectAITimerHi,X&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
  DEC EggsPresentCount&lt;br /&gt;
HunterBirdFinishRiderPickup&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; AutoPilotBirdLogic&lt;br /&gt;
; Handles AI for non-player-controlled birds (enemy birds, demo mode player birds).&lt;br /&gt;
; This is the main entry point for their AI processing each game cycle relevant&lt;br /&gt;
; to this logic.&lt;br /&gt;
; Input: X = GameObject index (bird)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
AutoPilotBirdLogic&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #State_BirdSeekingRider          ; Is bird in State_BirdSeekingRider ($14)?&lt;br /&gt;
                                       ; This is a special state where an unridden enemy bird&lt;br /&gt;
                                       ; is actively seeking a hatched rider.&lt;br /&gt;
  BCC EnemyBirdHasRider_Or_IsNormalAI  ; If state &amp;lt; $14, proceed to general AI or rider-attached logic.&lt;br /&gt;
  JSR EnemyBirdIsSeekingRider          ; If state is $14 (or potentially higher, though unlikely),&lt;br /&gt;
                                       ; jump to its specialized AI handler.&lt;br /&gt;
EnemyBirdHasRider_Or_IsNormalAI&lt;br /&gt;
                                       ; This label implies the bird either has a rider (and thus uses general AI)&lt;br /&gt;
                                       ; or is an AI bird not in the special &amp;quot;seeking rider&amp;quot; state.&lt;br /&gt;
&lt;br /&gt;
                                       ; Check if the bird is on a platform and has stopped skidding or moving.&lt;br /&gt;
  LDA GameObjectInAir,X                ; Is the bird in the air?&lt;br /&gt;
  BNE BirdAI_FlightPathAltitudeCheck   ; - Yes, skip platform-specific idle movement.&lt;br /&gt;
&lt;br /&gt;
                                       ; Bird is ON a PLATFORM.&lt;br /&gt;
  LDA GameObjectXVelocity,X            ; Get current X velocity.&lt;br /&gt;
  BEQ BirdAI_OnPlatform_Stopped        ; - If X velocity is zero, bird is stopped.&lt;br /&gt;
  LDA GameObjectSkidDirection,X        ; Check if bird is skidding.&lt;br /&gt;
  BEQ BirdAI_FlightPathAltitudeCheck   ; - If not skidding (but moving), proceed to altitude checks.&lt;br /&gt;
                                       ; This implies moving non-skidding birds on platforms still use some airborne AI logic.&lt;br /&gt;
  RTS                                  ; - Bird is skidding on a platform, AI takes no further action this frame.&lt;br /&gt;
&lt;br /&gt;
BirdAI_OnPlatform_Stopped           ; Bird is on a platform and X-velocity is zero.&lt;br /&gt;
                                    ; Make it pace back and forth slightly if it's an AI bird.&lt;br /&gt;
  LDA GameObjectXVelocity,X         ; Re-load X-velocity (will be $00 here).&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC GameObjectDirection,X         ; Add current facing direction to X-velocity.&lt;br /&gt;
                                    ; (e.g., if facing right ($01), XVel becomes $01; if left ($FF), XVel becomes $FF)&lt;br /&gt;
  STA GameObjectXVelocity,X         ; Store new X-velocity to start slight movement.&lt;br /&gt;
&lt;br /&gt;
BirdAI_FlightPathAltitudeCheck&lt;br /&gt;
  LDA GameObjectYCoordHi,X          ; Get current Y position.&lt;br /&gt;
  CMP #$A2                          ; Is bird very low (near bottom of typical play area)?&lt;br /&gt;
  BCC BirdAI_CheckMidAltitudeRange  ; - If higher than $A2, check next range.&lt;br /&gt;
                                    ; Bird is very low (Y &amp;gt;= $A2).&lt;br /&gt;
  LDA #$00                          ; Set a fast timer value for GameObjectTimerResetValue.&lt;br /&gt;
  STA GameObjectEventTimer1,X       ; Force next event (flap) quickly to gain altitude.&lt;br /&gt;
  JMP BirdAI_CheckEventTimer        ; Proceed to main AI timer logic.&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckMidAltitudeRange&lt;br /&gt;
  CMP #$92                               ; Is bird in the lower-mid section of screen?&lt;br /&gt;
  BCC BirdAI_CheckUpperAltitudeRange     ; - If higher than $92, check upper range.&lt;br /&gt;
                                         ; Bird is in lower-mid range ($92 &amp;lt;= Y &amp;lt; $A2).&lt;br /&gt;
  LDA GameObjectYVelocityHi,X            ; Check Y velocity.&lt;br /&gt;
  BMI BirdAI_CheckUpperAltitudeRange     ; - If moving up, it might be correcting, check upper range logic.&lt;br /&gt;
  CMP #$01                               ; Is bird moving down (YVel &amp;gt;= $01)?&lt;br /&gt;
  BCC BirdAI_CheckUpperAltitudeRange     ; - If not moving down (YVel == $00), proceed to upper range logic.&lt;br /&gt;
                                         ; This means if stationary or moving slowly down in this zone, it's fine.&lt;br /&gt;
                                         ; Bird is in lower-mid range AND moving down significantly (YVel &amp;gt;= $01).&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X           ; Get bird type.&lt;br /&gt;
  LDA AITimerDistantAggressive_ByType,Y  ; Load a type-specific timer reset value (from &amp;quot;slow reaction&amp;quot; table).&lt;br /&gt;
                                         ; This likely makes the bird react/flap sooner to correct downward movement.&lt;br /&gt;
  STA GameObjectTimerResetValue,X        ; Store it to influence next flap time.&lt;br /&gt;
  JMP BirdAI_CheckEventTimer&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckUpperAltitudeRange&lt;br /&gt;
  CMP #$88                               ; Is bird in the mid-upper section of screen?&lt;br /&gt;
  BCC BirdAI_CheckEventTimer             ; - If higher than $88 (i.e. Y &amp;lt; $88, near top), go to standard event timer.&lt;br /&gt;
                                         ; Bird is in mid-upper range ($88 &amp;lt;= Y &amp;lt; $92).&lt;br /&gt;
  LDA GameObjectYVelocityHi,X            ; Check Y velocity.&lt;br /&gt;
  BMI BirdAI_CheckEventTimer             ; - If moving up, behavior is fine, go to standard event timer.&lt;br /&gt;
  CMP #$02                               ; Is bird moving down significantly (YVel &amp;gt;= $02)?&lt;br /&gt;
  BCC BirdAI_CheckEventTimer             ; - If not (YVel &amp;lt; $02), behavior is fine.&lt;br /&gt;
                                         ; Bird is in mid-upper range AND moving down significantly (YVel &amp;gt;= $02).&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X           ; Get bird type.&lt;br /&gt;
  LDA AITimerDistantAggressive_ByType,Y  ; Load a type-specific timer reset value (from &amp;quot;slow reaction&amp;quot; table).&lt;br /&gt;
  STA GameObjectTimerResetValue,X        ; Store it to influence next flap time.&lt;br /&gt;
                                         ; Fall through to BirdAI_CheckEventTimer&lt;br /&gt;
&lt;br /&gt;
; Bird Animation Frames:&lt;br /&gt;
; $00: Gliding / Standing on platform&lt;br /&gt;
; $01: Wings up (during flap)&lt;br /&gt;
; $02: Wings mid-stroke (specific flapping/landing animation phase)&lt;br /&gt;
; $03: Wings down (during flap)&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckEventTimer&lt;br /&gt;
  LDA GameObjectEventTimer1,X          ; Load the bird's short-term event timer.&lt;br /&gt;
  BEQ BirdAI_EventTimerExpired         ; If timer is zero, process the event.&lt;br /&gt;
  DEC GameObjectEventTimer1,X          ; Otherwise, decrement the timer.&lt;br /&gt;
  JMP BirdAI_CheckMainAIDecisionTimer  ; Proceed to check the longer-term AI decision timer.&lt;br /&gt;
&lt;br /&gt;
BirdAI_EventTimerExpired               ; Short-term event timer has expired.&lt;br /&gt;
  LDA GameObjectAnimationFrame,X       ; Get current animation frame.&lt;br /&gt;
                                       ; Frames $00 (glide/stand) and $02 (mid-flap/land)&lt;br /&gt;
                                       ; seem to be key decision points for initiating a flap.&lt;br /&gt;
  BEQ BirdAI_FlapOrTakeAction          ; If frame $00 (gliding/standing), time to flap/act.&lt;br /&gt;
  CMP #$02                             ; Is animation frame $02?&lt;br /&gt;
  BEQ BirdAI_FlapOrTakeAction          ; If frame $02, also time to flap/act.&lt;br /&gt;
&lt;br /&gt;
BirdAI_SetAnimationToGlideOrStand      ; Current animation is likely $01 (wings up) or $03 (wings down).&lt;br /&gt;
                                       ; Reset animation to the default non-flapping state.&lt;br /&gt;
  LDA #$00                             ; Set animation frame to $00 (gliding/standing).&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
  LDA GameObjectTimerResetValue,X      ; Reload short-term event timer from its dynamic reset value.&lt;br /&gt;
                                       ; This value is often set by altitude adjustment logic.&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  JMP BirdAI_CheckMainAIDecisionTimer  ; Proceed to check the longer-term AI decision timer.&lt;br /&gt;
&lt;br /&gt;
BirdAI_FlapOrTakeAction                ; Time to perform a primary action, usually flapping.&lt;br /&gt;
  LDA GameObjectTimerResetValue,X      ; Reload short-term event timer.&lt;br /&gt;
  STA GameObjectEventTimer1,X&lt;br /&gt;
  JSR BirdFlapOrAction                 ; Execute the flap: changes Y-velocity, updates animation frame.&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckMainAIDecisionTimer   ; Check the 16-bit main AI decision timer.&lt;br /&gt;
  LDA GameObjectState,X           ; Get current bird state.&lt;br /&gt;
  CMP #State_BirdSeekingRider     ; Is bird in &amp;quot;State_BirdSeekingRider&amp;quot; ($14)?&lt;br /&gt;
  BCS BirdAI_ExitThisAutopilot    ; If state is &amp;gt;= $14 (SeekingRider or unknown higher),&lt;br /&gt;
                                  ; this general autopilot logic does not apply. Exit.&lt;br /&gt;
                                  ; State_BirdSeekingRider has its own specialized AI routines.&lt;br /&gt;
&lt;br /&gt;
; Bird is in a state managed by this general autopilot (e.g., normal flight, attacking player).&lt;br /&gt;
; Decrement the 16-bit AI decision timer (GameObjectAITimerHi/Lo).&lt;br /&gt;
&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA GameObjectAITimerLo,X&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  STA GameObjectAITimerLo,X&lt;br /&gt;
  LDA GameObjectAITimerHi,X&lt;br /&gt;
  BMI BirdAI_DecisionTimerExpired_HandleTargeting  ; If Hi byte was already negative, timer had expired.&lt;br /&gt;
  SBC #$00                                         ; Subtract carry (if Lo underflowed).&lt;br /&gt;
  STA GameObjectAITimerHi,X&lt;br /&gt;
  BMI BirdAI_DecisionTimerExpired_HandleTargeting  ; If Hi byte is now negative, timer just expired.&lt;br /&gt;
&lt;br /&gt;
BirdAI_DecisionTimerStillActive                    ; Main AI decision timer has not expired yet.&lt;br /&gt;
                                                   ; Bird continues with its current general behavior.&lt;br /&gt;
  JSR AdjustBirdYBasedOnAltitude                   ; Make minor adjustments to Y velocity based on altitude zones.&lt;br /&gt;
                                                   ; The return value in A is used to set the next flap timer.&lt;br /&gt;
  STA GameObjectTimerResetValue,X                  ; Store the altitude-influenced value. This determines&lt;br /&gt;
                                                   ; how soon GameObjectEventTimer1 will expire for the next flap.&lt;br /&gt;
  RTS                                              ; Done with autopilot for this frame.&lt;br /&gt;
&lt;br /&gt;
BirdAI_DecisionTimerExpired_HandleTargeting        ; Main AI decision timer has expired.&lt;br /&gt;
                                                   ; Time for a more significant AI decision.&lt;br /&gt;
  LDA GameObjectAlive,X                            ; Is the bird currently considered &amp;quot;alive&amp;quot;?&lt;br /&gt;
  BNE BirdAI_Alive_MakeDecision                    ; If alive, proceed to make a decision (re-target, turn, etc.).&lt;br /&gt;
                                                   ; Bird is NOT alive (GameObjectAlive,X is $00), but its AI is still being processed.&lt;br /&gt;
                                                   ; This can happen for unridden enemy birds that are flying off-screen after their&lt;br /&gt;
                                                   ; rider has been defeated (they are in state $05 &amp;quot;hit&amp;quot; but Alive is $00).&lt;br /&gt;
  JMP AdjustBirdYBasedOnAltitudeAndResetEventTimer ; Adjust Y for its off-screen path and set event timer.&lt;br /&gt;
&lt;br /&gt;
BirdAI_Alive_MakeDecision                          ; Bird is alive, and its main AI timer has expired.&lt;br /&gt;
  JMP BirdAI_ReTargetOrYAdjust                     ; Jump to the core AI decision logic:&lt;br /&gt;
                                                   ; find a target, adjust Y-velocity towards it, or turn.&lt;br /&gt;
&lt;br /&gt;
BirdAI_ExitThisAutopilot   ; Bird is in a state (e.g. SeekingRider) not handled by this general autopilot.&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdFlapOrAction&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$08&lt;br /&gt;
  BEQ ExitFlapPhysics&lt;br /&gt;
  CLC&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  ADC GameObjectDirection,X&lt;br /&gt;
  STA GameObjectXVelocity,X&lt;br /&gt;
ApplyFlapPhysics&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  CMP #$08&lt;br /&gt;
  BEQ ExitFlapPhysics&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  SBC BirdFlapLiftFactorLoLUT,Y&lt;br /&gt;
  STA GameObjectYVelocityLo,X&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  SBC BirdFlapLiftFactorHiLUT,Y&lt;br /&gt;
  STA GameObjectYVelocityHi,X&lt;br /&gt;
  LDA GameObjectInAir,X&lt;br /&gt;
  BNE FinalizeFlapState&lt;br /&gt;
  DEC GameObjectYCoordHi,X&lt;br /&gt;
FinalizeFlapState&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectAnimationFrame,X&lt;br /&gt;
  STA GameObjectInAir,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectPlatformSkipState,X&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS ExitFlapPhysics               ; branch if non-player enemy bird&lt;br /&gt;
  LDA #SFX_PlayerBirdFlap&lt;br /&gt;
  JMP ScheduleSFX&lt;br /&gt;
ExitFlapPhysics&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ClearSkidStateAndSound&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BEQ BirdNotSkidding2&lt;br /&gt;
  DEC GameObjectYCoordHi,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectSkidDirection,X&lt;br /&gt;
  STA GameObjectFootstepAnimIndex,X&lt;br /&gt;
  LDA #$0F                          ; skid sound effect&lt;br /&gt;
  JMP SilenceSFXIfPlaying&lt;br /&gt;
BirdNotSkidding2&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AdjustBirdYBasedOnAltitudeAndResetEventTimer&lt;br /&gt;
  JSR AdjustBirdYBasedOnAltitude&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
; BirdAI_ReTargetOrYAdjust&lt;br /&gt;
; This routine is called when a bird's main AI decision timer has expired.&lt;br /&gt;
; It handles re-targeting, turn timers, and then determines the bird's next&lt;br /&gt;
; short-term event timer (GameObjectTimerResetValue,X) based on proximity to its&lt;br /&gt;
; target and its current AI mode. This timer controls flap/action frequency.&lt;br /&gt;
; Input: X = bird's GameObject index&lt;br /&gt;
&lt;br /&gt;
BirdAI_ReTargetOrYAdjust&lt;br /&gt;
  LDA GameObjectPreyIndex,X                  ; Check if bird already has a prey&lt;br /&gt;
  BPL TargetAcquired_Or_AITargetDelayActive  ; If prey index is valid (0 or positive), proceed&lt;br /&gt;
&lt;br /&gt;
  JSR FindBestTargetForGameObject       ; No valid prey, try to find one&lt;br /&gt;
  LDA GameObjectPreyIndex,X             ; Check again if a prey was found&lt;br /&gt;
  BPL PreyFound_ProceedToProximityCalc  ; If prey now valid, proceed&lt;br /&gt;
&lt;br /&gt;
                                   ; Still no prey after trying to find one&lt;br /&gt;
  JSR AdjustBirdYBasedOnAltitude   ; Adjust Y velocity based on current altitude&lt;br /&gt;
  STA GameObjectTimerResetValue,X  ; Set next event timer based on altitude adjustment&lt;br /&gt;
  RTS                              ; No target, no further complex AI decision&lt;br /&gt;
&lt;br /&gt;
TargetAcquired_Or_AITargetDelayActive&lt;br /&gt;
  LDA GameObjectAITargetDelayTimer,X      ; Check if AI target re-evaluation is on cooldown&lt;br /&gt;
  BEQ AITargetDelayExpired_ForceRetarget  ; If timer is zero, cooldown expired, force re-target&lt;br /&gt;
  DEC GameObjectAITargetDelayTimer,X      ; Otherwise, decrement cooldown timer&lt;br /&gt;
  JMP PreyFound_ProceedToProximityCalc    ; Proceed with current prey&lt;br /&gt;
&lt;br /&gt;
AITargetDelayExpired_ForceRetarget&lt;br /&gt;
  LDA EnemyAITargetDelayBase            ; Cooldown expired, load base delay value&lt;br /&gt;
  STA GameObjectAITargetDelayTimer,X    ; Reset the cooldown timer&lt;br /&gt;
  JSR FindBestTargetForGameObject       ; Force re-evaluation of the best target&lt;br /&gt;
&lt;br /&gt;
PreyFound_ProceedToProximityCalc        ; Bird has a prey (either existing or newly acquired)&lt;br /&gt;
  JSR DecrementAndProcessBirdTurnTimer  ; Handle turn timer (may cause bird to turn around)&lt;br /&gt;
&lt;br /&gt;
DetermineAIActionBasedOnProximity&lt;br /&gt;
  JSR CalculateProximityCategoryIndexForAI  ; A -&amp;gt; index based on Y dist/vel to prey. Y reg gets this index.&lt;br /&gt;
  TAY                                       ; Y = Proximity Category Index (0-2, 4-6, 8-A)&lt;br /&gt;
  LDA BirdAIActionCategoryByProximityLUT,Y  ; Get AI Action Category ($00-$04, $FF)&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X              ; Y = Bird Type (0:Bounder, 1:Hunter, 2:ShadowLord, 3:Player)&lt;br /&gt;
&lt;br /&gt;
  CMP #AIActionCat_CloseDefensive          ; Is category $00 (Close/Defensive)?&lt;br /&gt;
  BEQ SelectTimer_Cat00_Path               ; If so, branch&lt;br /&gt;
  CMP #AIActionCat_OptimalAttack           ; Is category $01 (Optimal Attack)?&lt;br /&gt;
  BEQ SelectTimer_Cat01_Path               ; If so, branch&lt;br /&gt;
  CMP #AIActionCat_ModerateEngage          ; Is category $02 (Moderate Engage)?&lt;br /&gt;
  BEQ SelectTimer_Cat02_Path               ; If so, branch&lt;br /&gt;
  CMP #AIActionCat_FarApproach             ; Is category $03 (Far Approach)?&lt;br /&gt;
  BEQ SelectTimer_Cat03_Path               ; If so, branch&lt;br /&gt;
&lt;br /&gt;
; Fall-through: Category is $04 (VeryFar) or $FF (NoTarget/Maintain current behavior)&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectAIMode,X                 ; Check AI Mode (0=Passive, NonZero=Aggressive)&lt;br /&gt;
  BEQ Branch_CatFF04_AIMode0             ; If Mode 0 (Passive)&lt;br /&gt;
                                         ; AIMode is 1 (Aggressive) for Cat $04/$FF&lt;br /&gt;
  LDA AITimerDistantAggressive_ByType,Y  ; Mode 1&lt;br /&gt;
                                         ; Fall-through to StoreCalculatedTimerAndExitAIAction&lt;br /&gt;
&lt;br /&gt;
StoreCalculatedTimerAndExitAIAction      ; Common exit point for storing timer and returning.&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
Branch_CatFF04_AIMode0                                      ; Category $04/$FF, AI Mode 0 (Passive)&lt;br /&gt;
  LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y  ; Use shared table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction                   ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
SelectTimer_Cat03_Path                                      ; Category $03 (Far Approach)&lt;br /&gt;
  LDA GameObjectAIMode,X&lt;br /&gt;
  BEQ Branch_Cat03_AIMode0                                  ; If Mode 0 (Passive)&lt;br /&gt;
                                                            ; AI Mode is 1 (Aggressive) for Cat $03&lt;br /&gt;
  LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y  ; Mode 1: Use shared table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction                   ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
Branch_Cat03_AIMode0                                        ; Category $03 (Far Approach), AI Mode 0 (Passive)&lt;br /&gt;
  LDA AITimerApproachPassive_ByType,Y                       ; Use Cat03_AIMode0 table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction                   ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
SelectTimer_Cat00_Path                                      ; Category $00 (Close/Defensive)&lt;br /&gt;
  LDA AITimerCloseDefensive_ByType,Y                        ; This category uses one table regardless of AI mode&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction                   ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
SelectTimer_Cat02_Path                                      ; Category $02 (Moderate Engage)&lt;br /&gt;
  LDA GameObjectAIMode,X&lt;br /&gt;
  BEQ Branch_Cat02_AIMode0                                  ; If Mode 0 (Passive)&lt;br /&gt;
                                                            ; AI Mode is 1 (Aggressive) for Cat $02&lt;br /&gt;
  LDA AITimerMixedEngageAttack_ByType,Y                     ; Mode 1: Use shared table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction                   ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
Branch_Cat02_AIMode0                       ; Category $02 (Moderate Engage), AI Mode 0 (Passive)&lt;br /&gt;
  LDA AITimerEngagePassive_ByType,Y        ; Use Cat02_AIMode0 table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction  ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
SelectTimer_Cat01_Path                     ; Category $01 (Optimal Attack)&lt;br /&gt;
  LDA GameObjectAIMode,X&lt;br /&gt;
  BEQ Branch_Cat01_AIMode0                 ; If Mode 0 (Passive)&lt;br /&gt;
                                           ; AI Mode is 1 (Aggressive) for Cat $01&lt;br /&gt;
  LDA AITimerAttackAggressive_ByType,Y     ; Mode 1: Use Cat01_AIMode1 table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction  ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
Branch_Cat01_AIMode0                       ; Category $01 (Optimal Attack), AI Mode 0 (Passive)&lt;br /&gt;
  LDA AITimerMixedEngageAttack_ByType,Y    ; Mode 0: Use shared table&lt;br /&gt;
  JMP StoreCalculatedTimerAndExitAIAction  ; Jump to common exit&lt;br /&gt;
&lt;br /&gt;
AdjustBirdYBasedOnAltitude&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$94&lt;br /&gt;
  BPL AltitudeCheckGotAbsYDistFromLowBoundary&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
AltitudeCheckGotAbsYDistFromLowBoundary&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BCS BirdAI_CheckDistanceFromMidAltitudeBoundary&lt;br /&gt;
SetFlapTimerForLowAltitude&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA AITimerCloseDefensive_ByType,Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckDistanceFromMidAltitudeBoundary&lt;br /&gt;
  STA Temp65&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$52&lt;br /&gt;
  BPL CheckDistanceFromMidAltitude&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CheckDistanceFromMidAltitude&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BCC SetFlapTimerForLowAltitude&lt;br /&gt;
  STA Temp66&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$15&lt;br /&gt;
  BPL CompareAltitudeDistancesAndSelectTimer&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CompareAltitudeDistancesAndSelectTimer&lt;br /&gt;
  CMP #$02&lt;br /&gt;
  BCC SetFlapTimerForLowAltitude&lt;br /&gt;
  CMP Temp66&lt;br /&gt;
  BCS BirdAI_CheckMidAltitudePosition&lt;br /&gt;
  CMP Temp65&lt;br /&gt;
  BCS BirdAI_CompareAltitudeDistances&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$15&lt;br /&gt;
  BCS SetFlapTimerForHighAltitude&lt;br /&gt;
SetFlapTimerForMidAltitudePassive&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA AITimerEngagePassive_ByType,Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdAI_CheckMidAltitudePosition&lt;br /&gt;
  LDA Temp66&lt;br /&gt;
  CMP Temp65&lt;br /&gt;
  BCS BirdAI_CompareAltitudeDistances&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$52&lt;br /&gt;
  BCS SetFlapTimerForHighAltitude&lt;br /&gt;
  JMP SetFlapTimerForMidAltitudePassive&lt;br /&gt;
BirdAI_CompareAltitudeDistances&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CMP #$94&lt;br /&gt;
  BCC SetFlapTimerForMidAltitudePassive&lt;br /&gt;
SetFlapTimerForHighAltitude&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA AITimerApproachPassive_ByType,Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CalculateProximityMetric&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp60&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GameObjectXCoordHi,Y&lt;br /&gt;
  BPL CalculateProximityMetricXDone&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
CalculateProximityMetricXDone&lt;br /&gt;
  LSR&lt;br /&gt;
  LSR&lt;br /&gt;
  STA Temp5F&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC GameObjectYCoordHi,Y&lt;br /&gt;
  BPL AddXDistanceToProximityMetric&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
AddXDistanceToProximityMetric&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC Temp5F&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
FindBestTargetForGameObject&lt;br /&gt;
  CPX #$02&lt;br /&gt;
  BCS FindTargetForEnemyBird  ; branch if non-player enemy bird&lt;br /&gt;
  LDA #$02&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDY #$18&lt;br /&gt;
  JMP FindTargetInitializeSearch&lt;br /&gt;
FindTargetForEnemyBird&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp62&lt;br /&gt;
  LDY #$01&lt;br /&gt;
FindTargetInitializeSearch&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  STA GameObjectPreyIndex,X&lt;br /&gt;
FindTargetCheckNextObjectLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ FindTargetCheckNextObject&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BEQ TargetStateIsValidCalculateDistance&lt;br /&gt;
  BCC TargetStateIsValidCalculateDistance&lt;br /&gt;
  CMP #$14&lt;br /&gt;
  BCS FindTargetCheckNextObject&lt;br /&gt;
  CMP #$0A&lt;br /&gt;
  BCC FindTargetCheckNextObject&lt;br /&gt;
TargetStateIsValidCalculateDistance&lt;br /&gt;
  JSR CalculateProximityMetric&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CMP Temp61&lt;br /&gt;
  BCS FindTargetCheckNextObject&lt;br /&gt;
  STA Temp61&lt;br /&gt;
  TYA&lt;br /&gt;
  STA GameObjectPreyIndex,X&lt;br /&gt;
FindTargetCheckNextObject&lt;br /&gt;
  DEY&lt;br /&gt;
  CPY Temp62&lt;br /&gt;
  BPL FindTargetCheckNextObjectLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CalculateProximityCategoryIndexForAI&lt;br /&gt;
  LDY GameObjectPreyIndex,X&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CPY #$0D&lt;br /&gt;
  BCS CalculateProximityForEggOrPterry&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$02&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCC SetProximityBaseIndexTargetIsBelow&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$06&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCS SetProximityCategoryToOptimalAttack&lt;br /&gt;
  JMP SetProximityCategoryFarApproach&lt;br /&gt;
CalculateProximityForEggOrPterry&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$F2&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCC SetProximityBaseIndexTargetIsBelow&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$02&lt;br /&gt;
  CMP GameObjectYCoordHi,Y&lt;br /&gt;
  BCS SetProximityCategoryToOptimalAttack&lt;br /&gt;
SetProximityCategoryFarApproach&lt;br /&gt;
  LDA #$04&lt;br /&gt;
  JMP StoreProximityBaseIndexAndAddVelocityBias&lt;br /&gt;
SetProximityBaseIndexTargetIsBelow&lt;br /&gt;
  LDA #$08&lt;br /&gt;
  JMP StoreProximityBaseIndexAndAddVelocityBias&lt;br /&gt;
SetProximityCategoryToOptimalAttack&lt;br /&gt;
  LDA #$00&lt;br /&gt;
StoreProximityBaseIndexAndAddVelocityBias&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  BEQ CalculateProximityIndex_BirdStationary&lt;br /&gt;
  BPL AddDownwardVelocityBiasToProximityIndex&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BEQ CalculateProximityIndex_BirdStationary&lt;br /&gt;
AddDownwardVelocityBiasToProximityIndex&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$02&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CalculateProximityIndex_BirdStationary&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$01&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
  LDA Temp5E&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ConvertKilledBirdToEgg&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BEQ PlayBirdDeathExplosionSFXTurnIntoEgg&lt;br /&gt;
  LDA #SFX_Skid&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
PlayBirdDeathExplosionSFXTurnIntoEgg&lt;br /&gt;
  LDA #SFX_BirdExplosion&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA AITimerCloseDefensive_ByType,Y&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  INC EggsPresentCount&lt;br /&gt;
  LDY #$0D&lt;br /&gt;
FindAvailableEggSlot&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ FoundAvailableEggSlotInitialize&lt;br /&gt;
  INY&lt;br /&gt;
  CPY #$19&lt;br /&gt;
  BNE FindAvailableEggSlot&lt;br /&gt;
FoundAvailableEggSlotInitialize&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA GameObjectInAir,Y&lt;br /&gt;
  STA GameObjectDirection,Y&lt;br /&gt;
  LDA GameObjectXVelocity,X&lt;br /&gt;
  STA GameObjectXVelocity,Y&lt;br /&gt;
  LDA GameObjectYVelocityLo,X&lt;br /&gt;
  STA GameObjectYVelocityLo,Y&lt;br /&gt;
  LDA GameObjectYVelocityHi,X&lt;br /&gt;
  STA GameObjectYVelocityHi,Y&lt;br /&gt;
  LDA GameObjectYCoordLo,X&lt;br /&gt;
  STA GameObjectYCoordLo,Y&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #$0B&lt;br /&gt;
  STA GameObjectYCoordHi,Y&lt;br /&gt;
  LDA GameObjectXCoordLo,X&lt;br /&gt;
  STA GameObjectXCoordLo,Y&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  STA GameObjectXCoordHi,Y&lt;br /&gt;
  LDA ObjectBirdLevelAndType,X&lt;br /&gt;
  STX Temp5E&lt;br /&gt;
  TAX&lt;br /&gt;
  LDA NextEnemyBirdLevel,X      ; check what the next upgraded enemy is&lt;br /&gt;
  LDX Temp5E&lt;br /&gt;
  STA ObjectBirdLevelAndType,Y&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA ObjectWiggleAnimation,Y&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
StartPlayerDeath&lt;br /&gt;
  LDA PterryCountdownHi&lt;br /&gt;
  BNE SkipPterryCountdown&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PterryCountdownHi&lt;br /&gt;
SkipPterryCountdown&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA LevelWasSurvived&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Temp61ScoreAdd&lt;br /&gt;
  LDA #$05&lt;br /&gt;
  STA Temp62ScoreAdd&lt;br /&gt;
  JSR UpdatePlayerScoreAndBonus&lt;br /&gt;
  LDA GameObjectSkidDirection,X&lt;br /&gt;
  BEQ PlayPlayerDeathExplosionSFX&lt;br /&gt;
  LDA #SFX_Skid&lt;br /&gt;
  JSR SilenceSFXIfPlaying&lt;br /&gt;
PlayPlayerDeathExplosionSFX&lt;br /&gt;
  LDA #SFX_BirdExplosion&lt;br /&gt;
  JSR ScheduleSFX&lt;br /&gt;
  JSR DeadPlayerChecks&lt;br /&gt;
&lt;br /&gt;
  LDA GameObjectState,X&lt;br /&gt;
  BEQ SetupPlayerRespawn  ; state = 0:dead&lt;br /&gt;
&lt;br /&gt;
  LDA #$05  ; state = 5:player was hit &lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
&lt;br /&gt;
  LDY ObjectBirdLevelAndType,X&lt;br /&gt;
  LDA AITimerCloseDefensive_ByType,Y&lt;br /&gt;
  STA GameObjectTimerResetValue,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA GameObjectAlive,X&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  JMP StorePlayerExplosionCoordinates&lt;br /&gt;
SetupPlayerRespawn&lt;br /&gt;
  LDA #$03                    ; state = 3:born1&lt;br /&gt;
  STA GameObjectState,X&lt;br /&gt;
  LDA #$1E&lt;br /&gt;
  STA GameObjectCountdownLo,X&lt;br /&gt;
  LDA GameObjectYCoordHi,X&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC #$08                    ; Explosion should be a bit higher than the bird&lt;br /&gt;
StorePlayerExplosionCoordinates&lt;br /&gt;
  STA PlayerExplosionYCoord,X&lt;br /&gt;
  LDA GameObjectXCoordHi,X&lt;br /&gt;
  STA PlayerExplosionXCoord,X&lt;br /&gt;
  LDA #$16&lt;br /&gt;
  STA ESRoutineIndex+5,X&lt;br /&gt;
  LDA #$00                    ; Clear the death state&lt;br /&gt;
  STA P0DeathState,X&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDY #$0A&lt;br /&gt;
SetPterrysToLeavingOnDeathLoop&lt;br /&gt;
  LDA.w GameObjectState,Y&lt;br /&gt;
  BEQ CheckNextPterryOnPlayerDeath&lt;br /&gt;
  CMP #$0D&lt;br /&gt;
  BEQ CheckNextPterryOnPlayerDeath&lt;br /&gt;
  LDA PterryDefeatedFlag,Y&lt;br /&gt;
  CMP #$01&lt;br /&gt;
  BNE CheckNextPterryOnPlayerDeath&lt;br /&gt;
  LDA #$0C&lt;br /&gt;
  STA.w GameObjectState,Y&lt;br /&gt;
  LDA GameObjectDirection,Y&lt;br /&gt;
  BPL SetPterryLeavingVelocityRight&lt;br /&gt;
  LDA #$FB&lt;br /&gt;
  JMP StorePterryLeavingVelocity&lt;br /&gt;
SetPterryLeavingVelocityRight&lt;br /&gt;
  LDA #$05&lt;br /&gt;
StorePterryLeavingVelocity&lt;br /&gt;
  STA GameObjectXVelocity,Y&lt;br /&gt;
CheckNextPterryOnPlayerDeath&lt;br /&gt;
  INY&lt;br /&gt;
  CPY #$0D&lt;br /&gt;
  BCC SetPterrysToLeavingOnDeathLoop&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DecrementAndProcessBirdTurnTimer&lt;br /&gt;
  SEC&lt;br /&gt;
  LDA GameObjectTurnCheckTimerLo,X&lt;br /&gt;
  SBC #$01&lt;br /&gt;
  STA GameObjectTurnCheckTimerLo,X&lt;br /&gt;
  LDA GameObjectTurnCheckTimerHi,X&lt;br /&gt;
  BMI BirdTurnTimerExpired&lt;br /&gt;
  SBC #$00&lt;br /&gt;
  STA GameObjectTurnCheckTimerHi,X&lt;br /&gt;
  BMI BirdTurnTimerExpired&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
BirdTurnTimerExpired&lt;br /&gt;
  LDA GameObjectDirection,X&lt;br /&gt;
  EOR #$FF&lt;br /&gt;
  CLC&lt;br /&gt;
  JMP SetBirdRandomTurnTimers&lt;br /&gt;
&lt;br /&gt;
; This rom is a bit weird in that the last 2 8k blocks are identical,&lt;br /&gt;
; including the cart vectors and encryption key.&lt;br /&gt;
;&lt;br /&gt;
; block 1: the graphics and code are live/used, except for the &lt;br /&gt;
; brief &amp;quot;jmp $B000&amp;quot; located at DF7A. The encryption key, BIOS bytes,&lt;br /&gt;
; and 6502 vectors are dead/unused.&lt;br /&gt;
;&lt;br /&gt;
; block 2: the graphics and code are dead/unused, except for the&lt;br /&gt;
; brief &amp;quot;jmp $B000&amp;quot; located at FF7A. The encryption key, BIOS bytes,&lt;br /&gt;
; and 6502 vectors are used.&lt;br /&gt;
;&lt;br /&gt;
; So... Joust has just under 8K unused in block 2, ready and waiting &lt;br /&gt;
; for rom hacks.&lt;br /&gt;
;&lt;br /&gt;
; This is block 1 of 2...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SpriteGFX2  ; C000-C7FF&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $2A, $A0, $2A, $80, $2A, $20, $AA, $00&lt;br /&gt;
 .byte $A8, $00, $AA, $00, $AA, $00, $AA, $80&lt;br /&gt;
 .byte $AA, $A0, $AA, $A0, $AA, $A0, $AA, $A0&lt;br /&gt;
 .byte $2A, $A0, $2A, $A0, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $11, $48, $22, $8C, $33, $C8, $AA, $AA&lt;br /&gt;
 .byte $EA, $54, $00, $10, $6A, $AA, $A8, $A0&lt;br /&gt;
 .byte $AA, $AA, $95, $56, $AB, $7A, $A9, $57&lt;br /&gt;
 .byte $00, $D0, $6A, $AA, $A5, $5A, $AA, $AA&lt;br /&gt;
 .byte $AA, $A0, $00, $00, $00, $15, $55, $56&lt;br /&gt;
 .byte $AA, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $03, $00, $33&lt;br /&gt;
 .byte $00, $C0, $33, $00, $C0, $0C, $C0, $CC&lt;br /&gt;
 .byte $30, $00, $00, $C0, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $0C, $00, $00, $00, $00, $0C, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $0A, $A0, $0A, $AA, $56&lt;br /&gt;
 .byte $9A, $90, $36, $A9, $6A, $AA, $80, $00&lt;br /&gt;
 .byte $55, $AA, $00, $09, $7A, $A6, $A5, $FE&lt;br /&gt;
 .byte $A5, $A9, $54, $D6, $A5, $AA, $BD, $66&lt;br /&gt;
 .byte $56, $AB, $70, $00, $00, $00, $A0, $00&lt;br /&gt;
 .byte $02, $A0, $00, $00, $A8, $02, $AA, $02&lt;br /&gt;
 .byte $A0, $00, $00, $AA, $00, $44, $F0, $81&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $FF, $EB, $CF, $FF, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $0F, $CF, $00, $00, $00&lt;br /&gt;
 .byte $00, $FF, $A0, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $2A, $80, $2A, $80, $2A, $00, $AA, $00&lt;br /&gt;
 .byte $AA, $00, $AA, $00, $AA, $00, $AA, $80&lt;br /&gt;
 .byte $AA, $80, $AA, $A0, $AA, $A0, $AA, $80&lt;br /&gt;
 .byte $AA, $A0, $2A, $A0, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $04, $48, $08, $8C, $0C, $C8, $2A, $AA&lt;br /&gt;
 .byte $AA, $94, $00, $10, $AA, $AA, $A8, $A0&lt;br /&gt;
 .byte $AA, $AA, $95, $56, $AB, $FE, $A9, $57&lt;br /&gt;
 .byte $00, $D0, $6A, $AA, $A5, $56, $AA, $AA&lt;br /&gt;
 .byte $AA, $A0, $00, $00, $00, $00, $55, $55&lt;br /&gt;
 .byte $AA, $80, $00, $00, $2A, $AB, $F4, $00&lt;br /&gt;
 .byte $00, $00, $00, $AA, $80, $00, $00, $00&lt;br /&gt;
 .byte $00, $2A, $AA, $A8, $00, $5A, $AA, $A0&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $0A&lt;br /&gt;
 .byte $AA, $A0, $00, $00, $00, $03, $30, $0C&lt;br /&gt;
 .byte $00, $C0, $0C, $00, $C0, $0F, $00, $CC&lt;br /&gt;
 .byte $30, $00, $00, $30, $00, $00, $00, $00&lt;br /&gt;
 .byte $03, $FF, $FF, $FF, $FF, $FF, $F0, $0F&lt;br /&gt;
 .byte $FC, $03, $F3, $C3, $CF, $00, $00, $FC&lt;br /&gt;
 .byte $03, $00, $F0, $28, $28, $02, $A9, $5A&lt;br /&gt;
 .byte $9E, $90, $36, $A9, $5A, $AA, $40, $00&lt;br /&gt;
 .byte $01, $5A, $A0, $0A, $FA, $A6, $A5, $FA&lt;br /&gt;
 .byte $A5, $6A, $54, $D6, $A6, $AA, $D7, $A6&lt;br /&gt;
 .byte $A5, $AB, $FA, $80, $00, $0A, $AB, $C0&lt;br /&gt;
 .byte $0A, $A9, $00, $02, $AA, $86, $AA, $0A&lt;br /&gt;
 .byte $A8, $00, $7A, $AA, $B0, $0C, $F0, $63&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $FA, $BF, $FF, $EA, $BE, $F3, $FF, $C0&lt;br /&gt;
 .byte $00, $00, $00, $EA, $FB, $EA, $FF, $00&lt;br /&gt;
 .byte $03, $FA, $BF, $FA, $80, $00, $00, $00&lt;br /&gt;
 .byte $0A, $80, $0A, $80, $2A, $80, $2A, $80&lt;br /&gt;
 .byte $2A, $80, $AA, $80, $AA, $80, $AA, $80&lt;br /&gt;
 .byte $2A, $80, $AA, $80, $2A, $80, $AA, $80&lt;br /&gt;
 .byte $AA, $80, $AA, $80, $AA, $A8, $AF, $A8&lt;br /&gt;
 .byte $AE, $A8, $AA, $A8, $2A, $A8, $2A, $A8&lt;br /&gt;
 .byte $2A, $A8, $2A, $A8, $AA, $A8, $AA, $A8&lt;br /&gt;
 .byte $AA, $A8, $2A, $A8, $2A, $A8, $2A, $A8&lt;br /&gt;
 .byte $04, $48, $08, $8C, $0C, $C8, $0A, $AA&lt;br /&gt;
 .byte $AA, $94, $00, $10, $AA, $AA, $A8, $20&lt;br /&gt;
 .byte $AA, $AA, $55, $4A, $AA, $7E, $A9, $57&lt;br /&gt;
 .byte $00, $D0, $6A, $AA, $A5, $56, $AA, $AA&lt;br /&gt;
 .byte $AA, $80, $00, $00, $00, $00, $05, $55&lt;br /&gt;
 .byte $6A, $A0, $00, $00, $AA, $AA, $BF, $D0&lt;br /&gt;
 .byte $00, $00, $A0, $AA, $AB, $40, $00, $00&lt;br /&gt;
 .byte $00, $AA, $AA, $AA, $30, $5A, $AA, $A0&lt;br /&gt;
 .byte $01, $56, $A8, $00, $00, $00, $70, $AA&lt;br /&gt;
 .byte $AA, $AA, $B0, $00, $00, $03, $0C, $00&lt;br /&gt;
 .byte $00, $C0, $00, $03, $00, $0C, $C0, $CF&lt;br /&gt;
 .byte $F0, $00, $00, $0F, $FC, $00, $00, $00&lt;br /&gt;
 .byte $00, $0C, $00, $00, $00, $00, $00, $30&lt;br /&gt;
 .byte $03, $0C, $0C, $3C, $30, $C0, $F3, $03&lt;br /&gt;
 .byte $03, $03, $0C, $80, $08, $00, $55, $4A&lt;br /&gt;
 .byte $AE, $90, $06, $AA, $16, $A9, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $0A, $BA, $A5, $A9, $DA&lt;br /&gt;
 .byte $A5, $6A, $54, $D6, $A6, $AA, $FD, $A6&lt;br /&gt;
 .byte $AA, $AA, $AA, $00, $00, $2A, $AA, $7F&lt;br /&gt;
 .byte $2A, $AA, $F0, $02, $AA, $A6, $AA, $6A&lt;br /&gt;
 .byte $AA, $3F, $6A, $AA, $A0, $00, $12, $91&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $FF, $AA, $AA, $BA, $AB, $FA, $EE, $A0&lt;br /&gt;
 .byte $00, $00, $02, $AA, $AB, $FF, $FF, $00&lt;br /&gt;
 .byte $3F, $EB, $FF, $AB, $FA, $C0, $00, $00&lt;br /&gt;
 .byte $0A, $80, $0A, $80, $0A, $80, $0A, $80&lt;br /&gt;
 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $80&lt;br /&gt;
 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $80&lt;br /&gt;
 .byte $2A, $80, $AA, $80, $BB, $A8, $BA, $A8&lt;br /&gt;
 .byte $AE, $E8, $BA, $AB, $BE, $A8, $BA, $A0&lt;br /&gt;
 .byte $3B, $A8, $3A, $A8, $BE, $A8, $3A, $A8&lt;br /&gt;
 .byte $BA, $A8, $3B, $E8, $3A, $E8, $3A, $A8&lt;br /&gt;
 .byte $45, $48, $8A, $8C, $CF, $C8, $02, $AA&lt;br /&gt;
 .byte $AA, $94, $00, $10, $AA, $A8, $00, $20&lt;br /&gt;
 .byte $AA, $A9, $54, $0A, $AA, $BE, $A9, $57&lt;br /&gt;
 .byte $00, $D0, $6A, $AA, $A8, $55, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $00, $00, $00, $00, $00, $05&lt;br /&gt;
 .byte $52, $A8, $00, $0A, $AA, $AA, $AF, $FD&lt;br /&gt;
 .byte $40, $00, $A0, $AA, $AA, $F4, $00, $00&lt;br /&gt;
 .byte $02, $AA, $AA, $AA, $90, $5A, $AA, $A0&lt;br /&gt;
 .byte $15, $AA, $AA, $A0, $00, $07, $E0, $AA&lt;br /&gt;
 .byte $AA, $AA, $A8, $00, $00, $00, $C3, $00&lt;br /&gt;
 .byte $00, $C0, $00, $0C, $00, $0C, $30, $00&lt;br /&gt;
 .byte $30, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $C0&lt;br /&gt;
 .byte $03, $0C, $0C, $0C, $C0, $33, $0F, $03&lt;br /&gt;
 .byte $03, $03, $03, $00, $00, $00, $00, $0A&lt;br /&gt;
 .byte $A6, $90, $06, $AA, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $0A, $AA, $A5, $A9, $5A&lt;br /&gt;
 .byte $95, $6A, $50, $D6, $A6, $AA, $76, $A6&lt;br /&gt;
 .byte $AA, $AA, $A8, $00, $00, $AA, $AA, $5D&lt;br /&gt;
 .byte $EA, $AA, $FF, $0A, $AA, $AA, $A9, $AA&lt;br /&gt;
 .byte $AA, $BF, $AA, $AA, $A8, $00, $12, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $FE, $FF, $FF, $FF, $FF, $EA, $BA, $A8&lt;br /&gt;
 .byte $00, $00, $0E, $EE, $AF, $FF, $FF, $00&lt;br /&gt;
 .byte $AF, $EF, $EE, $BF, $FA, $AF, $C0, $00&lt;br /&gt;
 .byte $0A, $80, $0A, $80, $0A, $80, $0A, $80&lt;br /&gt;
 .byte $0A, $80, $0A, $80, $2A, $00, $2A, $80&lt;br /&gt;
 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $00&lt;br /&gt;
 .byte $2A, $20, $2A, $80, $AE, $A8, $AE, $A0&lt;br /&gt;
 .byte $AA, $A0, $AB, $A0, $AF, $A0, $AF, $A0&lt;br /&gt;
 .byte $AF, $A0, $2E, $A8, $2F, $A8, $AB, $B8&lt;br /&gt;
 .byte $2B, $A8, $2F, $E8, $AE, $A8, $2B, $A8&lt;br /&gt;
 .byte $15, $48, $2A, $8C, $3F, $C8, $00, $2A&lt;br /&gt;
 .byte $AA, $A4, $00, $00, $AA, $00, $00, $00&lt;br /&gt;
 .byte $2A, $95, $00, $0A, $AA, $BF, $A9, $57&lt;br /&gt;
 .byte $00, $10, $6A, $AA, $A8, $05, $AA, $AA&lt;br /&gt;
 .byte $A8, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $2A, $AA, $AA, $A9, $5F&lt;br /&gt;
 .byte $FC, $02, $A0, $AA, $AA, $7F, $C0, $00&lt;br /&gt;
 .byte $02, $AA, $AA, $AA, $A0, $5A, $AA, $81&lt;br /&gt;
 .byte $5A, $AA, $AA, $AA, $0F, $FF, $60, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $80, $00, $30, $03, $00&lt;br /&gt;
 .byte $3F, $FF, $FF, $F0, $00, $0C, $00, $00&lt;br /&gt;
 .byte $30, $00, $00, $0F, $C0, $FC, $03, $C0&lt;br /&gt;
 .byte $FC, $00, $15, $55, $55, $54, $00, $C0&lt;br /&gt;
 .byte $FF, $0C, $0C, $0F, $00, $0C, $03, $03&lt;br /&gt;
 .byte $03, $03, $03, $00, $00, $00, $00, $02&lt;br /&gt;
 .byte $AB, $94, $06, $AA, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $AA, $A9, $AA, $AA&lt;br /&gt;
 .byte $95, $6A, $50, $D6, $AA, $AA, $BA, $A6&lt;br /&gt;
 .byte $AA, $AA, $A0, $00, $02, $AA, $AA, $97&lt;br /&gt;
 .byte $AA, $AA, $9D, $FA, $AA, $AA, $A9, $AA&lt;br /&gt;
 .byte $AA, $B5, $AA, $AA, $AA, $0B, $B0, $38&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $FE, $FD, $55, $55, $57, $AA, $EA, $AB&lt;br /&gt;
 .byte $C0, $00, $FF, $EF, $AB, $BF, $FF, $03&lt;br /&gt;
 .byte $EB, $FA, $BF, $FF, $EB, $FF, $FF, $A8&lt;br /&gt;
 .byte $2A, $00, $8A, $00, $0A, $00, $02, $80&lt;br /&gt;
 .byte $02, $A0, $0A, $A0, $0A, $80, $0A, $80&lt;br /&gt;
 .byte $2A, $00, $2A, $00, $2A, $00, $2A, $20&lt;br /&gt;
 .byte $2A, $00, $2A, $00, $BB, $A0, $AB, $A0&lt;br /&gt;
 .byte $AB, $A0, $AE, $80, $AE, $80, $AE, $80&lt;br /&gt;
 .byte $AB, $A0, $AE, $A0, $AF, $EB, $AF, $A8&lt;br /&gt;
 .byte $2F, $E8, $AB, $A8, $AB, $E8, $AB, $E8&lt;br /&gt;
 .byte $05, $50, $0A, $A0, $0F, $F0, $00, $0A&lt;br /&gt;
 .byte $AA, $A8, $00, $00, $80, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $2A, $AA, $AF, $AA, $57&lt;br /&gt;
 .byte $00, $10, $6A, $AA, $A8, $00, $02, $AA&lt;br /&gt;
 .byte $80, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $AA, $AA, $AA, $AA, $55&lt;br /&gt;
 .byte $FF, $CA, $A0, $AA, $AA, $97, $FD, $00&lt;br /&gt;
 .byte $0A, $AA, $AA, $AA, $A0, $5A, $AA, $85&lt;br /&gt;
 .byte $6A, $AA, $AA, $AA, $BF, $FD, $60, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $A0, $00, $30, $03, $00&lt;br /&gt;
 .byte $00, $C0, $00, $00, $00, $0C, $00, $C0&lt;br /&gt;
 .byte $30, $00, $00, $30, $33, $03, $0C, $33&lt;br /&gt;
 .byte $03, $00, $AA, $AA, $AA, $AA, $00, $C0&lt;br /&gt;
 .byte $00, $03, $F0, $0C, $00, $0C, $00, $FC&lt;br /&gt;
 .byte $FC, $FC, $03, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $2A, $A4, $0A, $AA, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $0A, $A9, $6A, $AA&lt;br /&gt;
 .byte $95, $DA, $50, $36, $A9, $AA, $AA, $A6&lt;br /&gt;
 .byte $AA, $AA, $80, $00, $02, $AA, $AA, $9F&lt;br /&gt;
 .byte $AA, $AA, $B7, $EA, $AA, $AA, $AD, $AA&lt;br /&gt;
 .byte $AA, $A6, $AA, $AA, $AA, $3D, $F2, $FE&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $55, $75, $55, $55, $55, $D5, $AF, $FF&lt;br /&gt;
 .byte $FC, $03, $FF, $FF, $EA, $BF, $FF, $FF&lt;br /&gt;
 .byte $FA, $FF, $FF, $FF, $BF, $FF, $FF, $AF&lt;br /&gt;
 .byte $28, $00, $28, $00, $08, $00, $02, $80&lt;br /&gt;
 .byte $02, $A0, $02, $A0, $02, $A0, $0A, $A0&lt;br /&gt;
 .byte $28, $A0, $28, $20, $AA, $00, $28, $20&lt;br /&gt;
 .byte $28, $28, $A8, $80, $AA, $A0, $AE, $A0&lt;br /&gt;
 .byte $AE, $80, $AA, $80, $AA, $00, $AA, $00&lt;br /&gt;
 .byte $AA, $80, $AB, $A0, $AF, $A0, $AA, $E0&lt;br /&gt;
 .byte $AB, $A0, $2B, $A0, $AB, $A0, $AE, $A0&lt;br /&gt;
 .byte $01, $08, $02, $0C, $03, $08, $00, $00&lt;br /&gt;
 .byte $AA, $A8, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $0A, $AA, $A7, $AA, $57&lt;br /&gt;
 .byte $00, $10, $6A, $AA, $A8, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $AA, $AA, $AA, $AA, $57&lt;br /&gt;
 .byte $F7, $EA, $A0, $AA, $AA, $AD, $FF, $F0&lt;br /&gt;
 .byte $0A, $AA, $AA, $AA, $A0, $9A, $AA, $B5&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AF, $FD, $A0, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $A8, $00, $0C, $0C, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $CC, $00, $00&lt;br /&gt;
 .byte $33, $00, $00, $C0, $0C, $00, $F0, $0C&lt;br /&gt;
 .byte $00, $C0, $00, $00, $00, $00, $00, $C0&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $0C, $00, $00&lt;br /&gt;
 .byte $00, $00, $03, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $0A, $A4, $0A, $80, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $02, $A9, $6A, $AA&lt;br /&gt;
 .byte $96, $DA, $50, $36, $A9, $AA, $AA, $A1&lt;br /&gt;
 .byte $5A, $AA, $A0, $00, $0A, $AA, $AA, $95&lt;br /&gt;
 .byte $AA, $AA, $95, $EA, $AA, $AA, $AD, $AA&lt;br /&gt;
 .byte $AA, $AE, $AA, $AA, $AA, $2A, $A0, $89&lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF&lt;br /&gt;
 .byte $55, $D5, $55, $55, $55, $75, $55, $55&lt;br /&gt;
 .byte $55, $15, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $55, $55, $55, $55&lt;br /&gt;
 .byte $88, $00, $08, $00, $08, $00, $00, $00&lt;br /&gt;
 .byte $00, $20, $00, $20, $00, $20, $00, $88&lt;br /&gt;
 .byte $02, $00, $28, $80, $A0, $00, $00, $00&lt;br /&gt;
 .byte $22, $08, $A0, $20, $AA, $A0, $AA, $A0&lt;br /&gt;
 .byte $AA, $80, $AE, $00, $AE, $00, $BA, $00&lt;br /&gt;
 .byte $AA, $00, $AA, $80, $AA, $A0, $AA, $A0&lt;br /&gt;
 .byte $AA, $80, $2A, $A0, $2A, $A0, $AA, $80&lt;br /&gt;
 .byte $05, $08, $0A, $0C, $0F, $08, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $02, $AA, $AB, $EA, $54&lt;br /&gt;
 .byte $00, $10, $6A, $AA, $A8, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $02, $AA, $AA, $AA, $AA, $95&lt;br /&gt;
 .byte $77, $EA, $A0, $AA, $AA, $A5, $DF, $FF&lt;br /&gt;
 .byte $2A, $AA, $AA, $AA, $A0, $AA, $AA, $95&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AF, $75, $A0, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $00, $03, $F0, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $03, $00, $00, $00&lt;br /&gt;
 .byte $00, $C0, $03, $00, $33, $00, $C0, $33&lt;br /&gt;
 .byte $00, $C0, $0C, $30, $CF, $F0, $00, $C0&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $0C, $00, $00&lt;br /&gt;
 .byte $00, $00, $03, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $A8, $08, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $2A, $2A, $AA&lt;br /&gt;
 .byte $56, $DA, $50, $36, $A9, $6A, $AA, $A0&lt;br /&gt;
 .byte $05, $56, $A8, $00, $2A, $AA, $AA, $A6&lt;br /&gt;
 .byte $AA, $6A, $AF, $EA, $AA, $AA, $AD, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $A5, $6A, $2E, $A1, $D0&lt;br /&gt;
&lt;br /&gt;
; C800&lt;br /&gt;
&lt;br /&gt;
CharacterSet&lt;br /&gt;
; comprised of...&lt;br /&gt;
; 000000000000000011111111111111112222222222222222&lt;br /&gt;
; 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF&lt;br /&gt;
; _0123456789@0123456789@ABCDEGHIJLMNPRSTUVWXYZK() **then the title border and logo chars&lt;br /&gt;
&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $AA, $AA, $6A, $5A, $96, $A5, $A9, $AA&lt;br /&gt;
 .byte $90, $A0, $A0, $A0, $A0, $A0, $60, $50&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00&lt;br /&gt;
 .byte $0A, $97, $7F, $EA, $AA, $AA, $A7, $5D&lt;br /&gt;
 .byte $7F, $EA, $95, $AA, $AF, $75, $AA, $AA&lt;br /&gt;
 .byte $AA, $02, $AA, $AA, $AA, $95, $AA, $AA&lt;br /&gt;
 .byte $55, $55, $AA, $95, $57, $0F, $50, $9A&lt;br /&gt;
 .byte $AA, $9D, $AA, $5A, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $A8, $00, $02, $95, $7F, $A9, $5A, $50&lt;br /&gt;
 .byte $7F, $FE, $95, $5A, $55, $5F, $3F, $56&lt;br /&gt;
 .byte $AA, $BF, $D7, $5A, $50, $56, $AA, $AF&lt;br /&gt;
 .byte $D5, $40, $00, $00, $00, $00, $6A, $A9&lt;br /&gt;
 .byte $70, $5D, $FF, $A5, $6A, $5F, $FD, $AB&lt;br /&gt;
 .byte $F5, $56, $AA, $A9, $5D, $55, $AA, $A8&lt;br /&gt;
 .byte $00, $00, $55, $A9, $50, $55, $57, $A5&lt;br /&gt;
 .byte $57, $5D, $50, $6A, $A9, $55, $DD, $55&lt;br /&gt;
 .byte $5A, $A9, $60, $A0, $02, $AA, $95, $55&lt;br /&gt;
 .byte $A5, $95, $55, $55, $A0, $AB, $55, $AA&lt;br /&gt;
 .byte $95, $D5, $6A, $AA, $96, $95, $55, $55&lt;br /&gt;
 .byte $56, $2A, $AA, $A5, $9A, $A0, $5A, $95&lt;br /&gt;
 .byte $FE, $AA, $AA, $AA, $AA, $D5, $6A, $AA&lt;br /&gt;
 .byte $AA, $AA, $9A, $A5, $AA, $05, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $A9, $55, $56, $A5, $F5&lt;br /&gt;
 .byte $6A, $A5, $6A, $80, $2A, $A9, $EA, $A6&lt;br /&gt;
 .byte $A9, $5A, $A7, $EA, $AA, $AA, $AD, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $95, $5A, $00, $E0, $85&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $10, $10&lt;br /&gt;
 .byte $AA, $6A, $5A, $96, $A5, $A9, $AA, $AA&lt;br /&gt;
 .byte $A0, $A0, $A0, $A0, $A0, $60, $50, $90&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00&lt;br /&gt;
 .byte $0A, $A5, $5F, $AA, $AA, $AA, $A9, $DD&lt;br /&gt;
 .byte $DF, $AA, $95, $AA, $A9, $D6, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $2A, $AA, $AA, $95, $AA, $A9&lt;br /&gt;
 .byte $55, $57, $AA, $95, $57, $03, $D0, $96&lt;br /&gt;
 .byte $AA, $AA, $AA, $5A, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $A8, $00, $02, $A7, $5F, $A9, $5A, $70&lt;br /&gt;
 .byte $FD, $DE, $95, $5A, $55, $5F, $3F, $5A&lt;br /&gt;
 .byte $AA, $75, $75, $6A, $A0, $55, $AA, $AB&lt;br /&gt;
 .byte $DD, $55, $40, $00, $00, $00, $6A, $A9&lt;br /&gt;
 .byte $70, $5D, $7F, $A5, $6A, $5F, $FD, $AB&lt;br /&gt;
 .byte $F7, $56, $AA, $A5, $D5, $D5, $AA, $A8&lt;br /&gt;
 .byte $00, $00, $00, $A9, $50, $D5, $75, $A5&lt;br /&gt;
 .byte $57, $FD, $50, $6A, $A9, $7D, $D7, $55&lt;br /&gt;
 .byte $6A, $A5, $60, $A0, $02, $AA, $95, $55&lt;br /&gt;
 .byte $A5, $95, $55, $55, $60, $AB, $55, $AA&lt;br /&gt;
 .byte $75, $55, $6A, $AA, $56, $95, $55, $40&lt;br /&gt;
 .byte $00, $AA, $AA, $55, $56, $90, $5A, $95&lt;br /&gt;
 .byte $7A, $AA, $AA, $AA, $AA, $D5, $6A, $AA&lt;br /&gt;
 .byte $AA, $AA, $9A, $A5, $6A, $00, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $A9, $55, $56, $AF, $55&lt;br /&gt;
 .byte $6A, $95, $6A, $80, $AA, $A5, $7A, $A6&lt;br /&gt;
 .byte $A9, $5A, $A5, $AA, $AA, $AA, $AD, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $95, $5A, $00, $B0, $01&lt;br /&gt;
 .byte $00, $54, $54, $54, $54, $04, $54, $54&lt;br /&gt;
 .byte $10, $54, $04, $00, $A8, $A8, $A8, $A8&lt;br /&gt;
 .byte $08, $A8, $A8, $20, $A8, $08, $00, $88&lt;br /&gt;
 .byte $A0, $28, $A0, $A8, $A8, $88, $A8, $20&lt;br /&gt;
 .byte $A8, $88, $88, $80, $88, $A8, $20, $A8&lt;br /&gt;
 .byte $20, $88, $88, $20, $A8, $88, $41, $04&lt;br /&gt;
 .byte $6A, $5A, $96, $A5, $A9, $AA, $AA, $AA&lt;br /&gt;
 .byte $A0, $A0, $A0, $A0, $60, $50, $90, $A0&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00&lt;br /&gt;
 .byte $2A, $A5, $DF, $AA, $AA, $AA, $A9, $D5&lt;br /&gt;
 .byte $DD, $AA, $D5, $AA, $AB, $56, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $02, $AA, $AA, $95, $6A, $A9&lt;br /&gt;
 .byte $55, $57, $6A, $A5, $57, $03, $D0, $96&lt;br /&gt;
 .byte $AA, $AA, $AA, $5A, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $A8, $00, $02, $A9, $DF, $AA, $5A, $50&lt;br /&gt;
 .byte $5F, $DA, $95, $56, $95, $5F, $3F, $5A&lt;br /&gt;
 .byte $AB, $D7, $5D, $AA, $A0, $95, $6A, $AB&lt;br /&gt;
 .byte $FF, $FD, $80, $00, $00, $01, $6A, $A9&lt;br /&gt;
 .byte $50, $7F, $7F, $A5, $5A, $7F, $CF, $AA&lt;br /&gt;
 .byte $D5, $5A, $AA, $AD, $55, $55, $AA, $AA&lt;br /&gt;
 .byte $40, $00, $00, $AB, $50, $57, $57, $A5&lt;br /&gt;
 .byte $DF, $FD, $50, $6A, $AB, $FF, $75, $55&lt;br /&gt;
 .byte $6A, $A7, $60, $A0, $00, $AA, $55, $55&lt;br /&gt;
 .byte $A5, $95, $55, $55, $60, $AB, $D5, $AA&lt;br /&gt;
 .byte $57, $55, $AA, $AA, $56, $95, $00, $00&lt;br /&gt;
 .byte $00, $AA, $A9, $55, $56, $90, $5A, $95&lt;br /&gt;
 .byte $7A, $AA, $AA, $AA, $AA, $D5, $6A, $AA&lt;br /&gt;
 .byte $AA, $AA, $9A, $A5, $6A, $00, $0A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $A9, $55, $56, $AF, $D5&lt;br /&gt;
 .byte $AA, $B5, $6A, $80, $2A, $95, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $AA, $AA, $AA, $A5, $AA&lt;br /&gt;
 .byte $5A, $AA, $AA, $55, $56, $80, $30, $EB&lt;br /&gt;
 .byte $00, $44, $10, $40, $04, $04, $04, $44&lt;br /&gt;
 .byte $10, $44, $04, $54, $88, $20, $80, $08&lt;br /&gt;
 .byte $08, $08, $88, $20, $88, $08, $A8, $A8&lt;br /&gt;
 .byte $88, $80, $88, $80, $88, $88, $20, $88&lt;br /&gt;
 .byte $80, $88, $A8, $80, $A0, $08, $20, $88&lt;br /&gt;
 .byte $20, $A8, $88, $20, $80, $88, $44, $04&lt;br /&gt;
 .byte $5A, $96, $A5, $A9, $AA, $AA, $AA, $6A&lt;br /&gt;
 .byte $A0, $A0, $A0, $60, $50, $90, $A0, $A0&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00&lt;br /&gt;
 .byte $AA, $A5, $57, $AA, $AA, $AA, $AA, $77&lt;br /&gt;
 .byte $5D, $AA, $D5, $AA, $AA, $DA, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $00, $AA, $AA, $95, $6A, $A9&lt;br /&gt;
 .byte $55, $77, $6A, $A5, $57, $03, $D0, $96&lt;br /&gt;
 .byte $AA, $AA, $AA, $55, $50, $AA, $AA, $5A&lt;br /&gt;
 .byte $AA, $00, $02, $AA, $77, $AA, $56, $90&lt;br /&gt;
 .byte $F5, $DA, $95, $56, $95, $5F, $3F, $5A&lt;br /&gt;
 .byte $AB, $75, $D5, $AA, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $FE, $AA, $80, $00, $00, $05, $6A, $AA&lt;br /&gt;
 .byte $50, $7F, $FE, $A5, $5A, $5F, $FD, $AA&lt;br /&gt;
 .byte $D5, $6A, $AA, $97, $5D, $55, $AA, $AA&lt;br /&gt;
 .byte $00, $00, $00, $A9, $50, $5D, $77, $A5&lt;br /&gt;
 .byte $5F, $FD, $D0, $6A, $AB, $FF, $57, $55&lt;br /&gt;
 .byte $AA, $95, $60, $A0, $00, $AA, $55, $55&lt;br /&gt;
 .byte $A5, $95, $55, $55, $60, $AB, $55, $A9&lt;br /&gt;
 .byte $D5, $55, $AA, $AA, $56, $90, $00, $00&lt;br /&gt;
 .byte $00, $AA, $A9, $55, $55, $90, $5A, $95&lt;br /&gt;
 .byte $5A, $AA, $AA, $AA, $AB, $D5, $6A, $AA&lt;br /&gt;
 .byte $A6, $AA, $9A, $95, $6A, $00, $0A, $A6&lt;br /&gt;
 .byte $A5, $5E, $A5, $A9, $55, $56, $AD, $D6&lt;br /&gt;
 .byte $AA, $55, $6A, $80, $2A, $95, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $AA, $95, $AA, $A5, $A9&lt;br /&gt;
 .byte $56, $AA, $AA, $55, $56, $80, $A2, $14&lt;br /&gt;
 .byte $00, $44, $10, $54, $14, $54, $54, $54&lt;br /&gt;
 .byte $10, $54, $54, $54, $88, $20, $A8, $28&lt;br /&gt;
 .byte $A8, $A8, $A8, $20, $A8, $A8, $A8, $88&lt;br /&gt;
 .byte $A0, $80, $88, $A0, $88, $A8, $20, $08&lt;br /&gt;
 .byte $80, $88, $A8, $A8, $A8, $20, $20, $88&lt;br /&gt;
 .byte $88, $88, $20, $20, $20, $A0, $44, $04&lt;br /&gt;
 .byte $96, $A5, $A9, $AA, $AA, $AA, $6A, $5A&lt;br /&gt;
 .byte $A0, $A0, $60, $50, $90, $A0, $A0, $A0&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $02&lt;br /&gt;
 .byte $AA, $A5, $76, $AA, $AA, $AA, $AA, $75&lt;br /&gt;
 .byte $7D, $AA, $D5, $6A, $AA, $DA, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $00, $0A, $AA, $A5, $6A, $A9&lt;br /&gt;
 .byte $55, $9F, $6A, $A5, $57, $03, $D0, $95&lt;br /&gt;
 .byte $AA, $AA, $AA, $03, $50, $55, $55, $56&lt;br /&gt;
 .byte $AA, $00, $02, $AA, $9E, $AA, $56, $90&lt;br /&gt;
 .byte $5F, $5A, $55, $56, $95, $5F, $0F, $5A&lt;br /&gt;
 .byte $AB, $DD, $D6, $AA, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $00, $00, $00, $57, $6A, $AA&lt;br /&gt;
 .byte $70, $77, $5E, $A5, $5A, $5C, $FD, $AA&lt;br /&gt;
 .byte $D5, $6A, $AA, $75, $55, $55, $6A, $AA&lt;br /&gt;
 .byte $40, $00, $00, $A9, $50, $D5, $F7, $A5&lt;br /&gt;
 .byte $5F, $CD, $50, $6A, $AB, $FF, $F5, $56&lt;br /&gt;
 .byte $AA, $9D, $60, $A0, $00, $2A, $55, $55&lt;br /&gt;
 .byte $A5, $55, $55, $D5, $50, $AB, $55, $A9&lt;br /&gt;
 .byte $75, $55, $AA, $A9, $56, $80, $00, $00&lt;br /&gt;
 .byte $00, $2A, $A5, $55, $55, $50, $56, $95&lt;br /&gt;
 .byte $5A, $AA, $AA, $AA, $AB, $55, $6A, $AA&lt;br /&gt;
 .byte $55, $AA, $9A, $95, $5A, $00, $0A, $A6&lt;br /&gt;
 .byte $A5, $7E, $A5, $A9, $55, $56, $AD, $5A&lt;br /&gt;
 .byte $AA, $75, $5A, $80, $0A, $95, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $AA, $55, $6A, $A5, $A9&lt;br /&gt;
 .byte $D6, $AA, $AA, $55, $56, $A8, $04, $06&lt;br /&gt;
 .byte $00, $44, $50, $04, $04, $44, $40, $40&lt;br /&gt;
 .byte $04, $44, $44, $F4, $88, $A0, $08, $08&lt;br /&gt;
 .byte $88, $80, $80, $08, $88, $88, $F8, $88&lt;br /&gt;
 .byte $88, $80, $88, $80, $80, $88, $20, $08&lt;br /&gt;
 .byte $80, $A8, $A8, $88, $88, $80, $20, $88&lt;br /&gt;
 .byte $88, $88, $88, $88, $08, $A0, $44, $04&lt;br /&gt;
 .byte $A5, $A9, $AA, $AA, $AA, $6A, $5A, $96&lt;br /&gt;
 .byte $A0, $60, $50, $90, $A0, $A0, $A0, $A0&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $0A&lt;br /&gt;
 .byte $AA, $A9, $56, $AA, $AA, $AA, $AA, $55&lt;br /&gt;
 .byte $DE, $AA, $D5, $6A, $AA, $DA, $AA, $95&lt;br /&gt;
 .byte $5A, $00, $00, $00, $AA, $A5, $4A, $A9&lt;br /&gt;
 .byte $56, $9F, $7A, $A5, $57, $00, $D0, $95&lt;br /&gt;
 .byte $AA, $AA, $AA, $00, $10, $55, $55, $55&lt;br /&gt;
 .byte $AA, $80, $02, $AA, $AA, $AA, $56, $A0&lt;br /&gt;
 .byte $77, $6A, $55, $56, $95, $5F, $0F, $FA&lt;br /&gt;
 .byte $AB, $77, $5A, $AA, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $A0, $00, $00, $05, $7F, $6A, $AA&lt;br /&gt;
 .byte $70, $75, $DE, $A5, $5A, $5F, $FD, $AA&lt;br /&gt;
 .byte $D5, $AA, $A9, $F7, $75, $55, $6A, $AA&lt;br /&gt;
 .byte $94, $00, $00, $A9, $50, $5D, $77, $A5&lt;br /&gt;
 .byte $5F, $FD, $50, $6A, $AB, $F7, $55, $5A&lt;br /&gt;
 .byte $AA, $95, $50, $A0, $00, $2A, $55, $55&lt;br /&gt;
 .byte $A5, $55, $55, $55, $50, $AB, $D5, $A7&lt;br /&gt;
 .byte $55, $56, $AA, $A9, $55, $80, $00, $00&lt;br /&gt;
 .byte $00, $2A, $A5, $55, $55, $50, $56, $A5&lt;br /&gt;
 .byte $5A, $AA, $96, $AA, $AB, $55, $6A, $A9&lt;br /&gt;
 .byte $D5, $6A, $9A, $95, $5A, $00, $0A, $A6&lt;br /&gt;
 .byte $A5, $7E, $A5, $A9, $55, $56, $AD, $6A&lt;br /&gt;
 .byte $AB, $55, $5A, $A0, $0A, $55, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $AA, $55, $5A, $AD, $A5&lt;br /&gt;
 .byte $5A, $A9, $AA, $55, $00, $80, $F9, $5F&lt;br /&gt;
 .byte $00, $54, $10, $54, $54, $44, $54, $54&lt;br /&gt;
 .byte $54, $54, $54, $54, $A8, $20, $A8, $A8&lt;br /&gt;
 .byte $88, $A8, $A8, $A8, $A8, $A8, $A8, $20&lt;br /&gt;
 .byte $A0, $28, $A0, $A8, $A8, $88, $A8, $08&lt;br /&gt;
 .byte $80, $88, $88, $A8, $A8, $A8, $A8, $88&lt;br /&gt;
 .byte $88, $88, $88, $88, $A8, $88, $41, $04&lt;br /&gt;
 .byte $A9, $AA, $AA, $AA, $6A, $5A, $96, $A5&lt;br /&gt;
 .byte $60, $50, $90, $A0, $A0, $A0, $A0, $A0&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $0A&lt;br /&gt;
 .byte $AA, $A9, $56, $AA, $95, $AA, $AA, $5D&lt;br /&gt;
 .byte $DE, $AA, $D5, $6A, $AA, $9A, $AA, $55&lt;br /&gt;
 .byte $56, $00, $00, $00, $0A, $A9, $0A, $A5&lt;br /&gt;
 .byte $56, $AF, $7A, $A5, $57, $00, $D0, $A5&lt;br /&gt;
 .byte $6A, $AA, $A8, $00, $00, $55, $55, $55&lt;br /&gt;
 .byte $6A, $A0, $02, $AA, $AA, $AA, $56, $A0&lt;br /&gt;
 .byte $77, $6A, $55, $55, $95, $57, $0F, $5A&lt;br /&gt;
 .byte $AB, $5F, $5A, $AA, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $80, $00, $00, $55, $5F, $5A, $AA&lt;br /&gt;
 .byte $70, $5F, $FE, $A5, $5A, $5F, $CD, $AA&lt;br /&gt;
 .byte $55, $AA, $A9, $F7, $D6, $55, $5A, $AA&lt;br /&gt;
 .byte $B5, $00, $00, $A9, $70, $55, $FF, $A5&lt;br /&gt;
 .byte $7C, $FF, $50, $5A, $AB, $F5, $D5, $6A&lt;br /&gt;
 .byte $AA, $75, $50, $AB, $00, $09, $55, $57&lt;br /&gt;
 .byte $A5, $55, $57, $55, $50, $AB, $55, $AD&lt;br /&gt;
 .byte $55, $56, $AA, $A9, $55, $80, $00, $00&lt;br /&gt;
 .byte $00, $0A, $95, $55, $55, $50, $56, $A5&lt;br /&gt;
 .byte $6A, $A9, $55, $5A, $AB, $55, $AA, $A5&lt;br /&gt;
 .byte $55, $6A, $9A, $95, $5A, $00, $5A, $A6&lt;br /&gt;
 .byte $A5, $FE, $A5, $A9, $55, $56, $AD, $6A&lt;br /&gt;
 .byte $A5, $55, $5A, $A0, $02, $55, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $A9, $55, $5A, $A5, $A5&lt;br /&gt;
 .byte $5A, $A5, $AA, $50, $00, $A8, $10, $90&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $00, $00, $00, $10, $10&lt;br /&gt;
 .byte $AA, $AA, $AA, $6A, $5A, $96, $A5, $A9&lt;br /&gt;
 .byte $50, $90, $A0, $A0, $A0, $A0, $A0, $60&lt;br /&gt;
 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $2A&lt;br /&gt;
 .byte $AA, $A9, $76, $AA, $55, $6A, $AA, $95&lt;br /&gt;
 .byte $7E, $AA, $D5, $6A, $AA, $9A, $A9, $55&lt;br /&gt;
 .byte $55, $00, $00, $00, $00, $A8, $02, $A5&lt;br /&gt;
 .byte $56, $AF, $7A, $A5, $57, $00, $D0, $A5&lt;br /&gt;
 .byte $6A, $AA, $A8, $00, $00, $05, $55, $55&lt;br /&gt;
 .byte $5A, $A8, $00, $2A, $AA, $AA, $55, $A0&lt;br /&gt;
 .byte $9D, $AA, $55, $55, $95, $57, $0F, $9A&lt;br /&gt;
 .byte $AA, $77, $6A, $AA, $A0, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $00, $00, $02, $55, $DF, $5A, $AA&lt;br /&gt;
 .byte $50, $F7, $7E, $95, $5A, $5F, $3F, $AA&lt;br /&gt;
 .byte $56, $AA, $AD, $DD, $DA, $59, $56, $AA&lt;br /&gt;
 .byte $AD, $50, $00, $A9, $50, $75, $DF, $A5&lt;br /&gt;
 .byte $5F, $FD, $50, $5A, $AB, $FD, $55, $AA&lt;br /&gt;
 .byte $AA, $55, $50, $A8, $00, $00, $00, $77&lt;br /&gt;
 .byte $A5, $55, $75, $75, $50, $AB, $D5, $95&lt;br /&gt;
 .byte $D5, $5A, $AA, $A9, $55, $80, $00, $00&lt;br /&gt;
 .byte $00, $0A, $95, $55, $55, $50, $56, $A5&lt;br /&gt;
 .byte $6A, $A5, $55, $55, $AB, $55, $AA, $9D&lt;br /&gt;
 .byte $55, $6A, $96, $95, $56, $05, $7A, $A6&lt;br /&gt;
 .byte $A5, $FE, $A5, $A9, $57, $D6, $A5, $AA&lt;br /&gt;
 .byte $AD, $D5, $56, $AD, $02, $55, $5A, $A6&lt;br /&gt;
 .byte $A5, $56, $A5, $A9, $55, $5A, $A5, $B5&lt;br /&gt;
 .byte $5A, $A5, $AA, $00, $00, $00, $D0, $28&lt;br /&gt;
&lt;br /&gt;
; ORG $D000&lt;br /&gt;
&lt;br /&gt;
MenuUpdateCounter&lt;br /&gt;
  LDA EasterEggJoyDownCount&lt;br /&gt;
; easter egg phase 2: if the first phase completed successfully&lt;br /&gt;
; the left press counter is allowed to increment.&lt;br /&gt;
  CMP #53&lt;br /&gt;
  BNE SkipCounting2ndEasterEggPhase&lt;br /&gt;
  INC EasterEggJoyLeftCount&lt;br /&gt;
SkipCounting2ndEasterEggPhase&lt;br /&gt;
  JMP MenuTextUpdate&lt;br /&gt;
MenuSelectTwoPlayers&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PlayerCount&lt;br /&gt;
  BNE SkipCounting1stEasterEggPhase&lt;br /&gt;
&lt;br /&gt;
MenuSelectOnePlayer                ; (the joystick was pressed down in the title menu)&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA PlayerCount&lt;br /&gt;
                                   ; easter egg phase 1: if the second phase isn't in progress the&lt;br /&gt;
                                   ; down press counter is allowed to increment.&lt;br /&gt;
  LDA EasterEggJoyLeftCount&lt;br /&gt;
  BNE SkipCounting1stEasterEggPhase&lt;br /&gt;
  INC EasterEggJoyDownCount&lt;br /&gt;
  JMP MenuTextUpdate&lt;br /&gt;
SkipCounting1stEasterEggPhase&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA EasterEggJoyDownCount&lt;br /&gt;
  STA EasterEggJoyLeftCount&lt;br /&gt;
  BEQ MenuTextUpdate&lt;br /&gt;
MenuHandlingAndUpdate&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #$02&lt;br /&gt;
  BEQ MenuSelectPressed&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA MenuSelectDebounceTimer&lt;br /&gt;
  BPL SkipMenuRedraw&lt;br /&gt;
MenuSelectPressed&lt;br /&gt;
  DEC MenuSelectDebounceTimer&lt;br /&gt;
  BPL SkipMenuRedraw&lt;br /&gt;
  JSR SetMenuSelectDebounceTimerTo20&lt;br /&gt;
  JSR ChangeDifficulty&lt;br /&gt;
MenuTextUpdate&lt;br /&gt;
  JSR SetMenuResetTimer&lt;br /&gt;
  JSR SetupGameOptionsText&lt;br /&gt;
SkipMenuRedraw&lt;br /&gt;
&lt;br /&gt;
; implement a ~18 minute timer that just resets the stack and demo mode.&lt;br /&gt;
; I'm thinking they had a slow stack leak during development.&lt;br /&gt;
  LDA TimerHi&lt;br /&gt;
  CMP MenuResetTimer&lt;br /&gt;
  BNE ContinueMenuLoop&lt;br /&gt;
  JMP ResetStackAndStartGameInDemoMode&lt;br /&gt;
ContinueMenuLoop&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
MenuWaitForNextFrame&lt;br /&gt;
  CMP TimerLo&lt;br /&gt;
  BEQ MenuWaitForNextFrame&lt;br /&gt;
  JMP GameOptionsMenuLoop&lt;br /&gt;
&lt;br /&gt;
SetMenuJoyDebounceTimerTo20&lt;br /&gt;
  LDA #$20&lt;br /&gt;
  STA MenuJoyDebounceTimer&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetMenuSelectDebounceTimerTo20&lt;br /&gt;
  LDA #$20&lt;br /&gt;
  STA MenuSelectDebounceTimer&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetMenuResetTimer&lt;br /&gt;
  LDX TimerHi&lt;br /&gt;
  DEX&lt;br /&gt;
  STX MenuResetTimer&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ChangeDifficulty&lt;br /&gt;
  INC Difficulty&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  CMP #$04&lt;br /&gt;
  BMI FinalizeDifficultyChange&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA Difficulty&lt;br /&gt;
&lt;br /&gt;
  LDA PlayerCount&lt;br /&gt;
  EOR #$01&lt;br /&gt;
  STA PlayerCount&lt;br /&gt;
FinalizeDifficultyChange&lt;br /&gt;
  JMP ClearScores&lt;br /&gt;
SetupGameOptionsText&lt;br /&gt;
  LDX PlayerCount&lt;br /&gt;
  LDA HideOrShowTwoPlayerText,X&lt;br /&gt;
  STA MenuTwoPlayerTextXCoord   ; set X coordinate of upper DL object = 160 or 48, to hide or display &amp;quot;two player&amp;quot;&lt;br /&gt;
  LDA HideOrShowOnePlayerText,X&lt;br /&gt;
  STA MenuOnePlayerTextXCoord   ; set X coordinate of lower DL object = 48 or 160, to display of hide &amp;quot;one player&amp;quot;&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  TAX&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL                    ; A = Difficulty * 16&lt;br /&gt;
  CLC&lt;br /&gt;
  ADC #&amp;lt;DifficultyText&lt;br /&gt;
  STA Temp5E&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  ADC ##&amp;gt;DifficultyText&lt;br /&gt;
  STA Temp5F             ; ($5E) = current difficulty name&lt;br /&gt;
&lt;br /&gt;
  LDY #$0F               ; copy over 16 characters&lt;br /&gt;
CopyDifficultyNameLoop&lt;br /&gt;
  LDA (Temp5E),Y&lt;br /&gt;
  STA DifficultyLevelCharBuffer,Y&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL CopyDifficultyNameLoop&lt;br /&gt;
&lt;br /&gt;
  LDA DifficultyTextXCoordinate,X  ; set X coordinate of mid DL object (difficulty level text)&lt;br /&gt;
  STA MenuDifficultyTextXCoord     ; differently, depending on the difficulty level.&lt;br /&gt;
&lt;br /&gt;
  LDA EasterEggJoyLeftCount&lt;br /&gt;
&lt;br /&gt;
; easter egg phase 3: check if phase 2 (left 41 times) is done. &lt;br /&gt;
; if so, set us up the egg!&lt;br /&gt;
  CMP #41&lt;br /&gt;
  BNE ExitMenuEasterEggCheck&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  AND #$03&lt;br /&gt;
  CMP #$03&lt;br /&gt;
  BNE ExitMenuEasterEggCheck&lt;br /&gt;
  DEC EasterEggXCoordinate1&lt;br /&gt;
  DEC EasterEggXCoordinate2&lt;br /&gt;
  DEC EasterEggXCoordinate3&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA DisplayEasterEggFlag&lt;br /&gt;
ExitMenuEasterEggCheck&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
CheckMenuFireButtonAndStartGame&lt;br /&gt;
  LDA P0CurrentFire&lt;br /&gt;
  BPL ResetStackAndStartGameInDemoMode_Short&lt;br /&gt;
  LDA PrevResetState&lt;br /&gt;
  BNE MenuUpdateResetButtonState&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  LSR&lt;br /&gt;
  BCS ExitMenuEasterEggCheck&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA PrevResetState&lt;br /&gt;
ResetStackAndStartGameInDemoMode_Short&lt;br /&gt;
  JMP RestartGameFromMenu&lt;br /&gt;
MenuUpdateResetButtonState&lt;br /&gt;
  JMP UpdatePrevResetStateFlag&lt;br /&gt;
&lt;br /&gt;
HandleDemoModeJoyInput&lt;br /&gt;
  LDA P0CurrentFire&lt;br /&gt;
CheckForAttractModeExit&lt;br /&gt;
  BPL ResetStackAndStartGameInDemoMode_Short&lt;br /&gt;
  LDA SWCHA&lt;br /&gt;
  CMP #$F0&lt;br /&gt;
  BCS CheckResetSwitch&lt;br /&gt;
  JMP ResetStackAndDisplayGameOptions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; HandleConsoleSwitches&lt;br /&gt;
; Checks the state of Pause, Reset, and Select console switches and acts accordingly.&lt;br /&gt;
; This routine is typically called during active gameplay.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
HandleConsoleSwitches&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE HandleDemoModeJoyInput  ; If in demo mode, only check for joystick/fire to exit demo&lt;br /&gt;
&lt;br /&gt;
                              ; Fall-through if not in Demo Mode&lt;br /&gt;
CheckPauseSwitch&lt;br /&gt;
  LDA PrevPausedState         ; Get previous state of Pause switch (was it already pressed?)&lt;br /&gt;
  BNE UpdatePauseSwitchState  ; If it was pressed, go update its current debounced state&lt;br /&gt;
&lt;br /&gt;
                          ; Pause switch was not previously pressed, check if it's pressed now&lt;br /&gt;
  LDA SWCHB               ; Read console switch register B&lt;br /&gt;
  AND #SWCHB_Pause_Mask   ; Isolate Pause switch bit (Bit 3)&lt;br /&gt;
  BNE CheckResetSwitch    ; If Pause bit is high (not pressed), check Reset switch&lt;br /&gt;
&lt;br /&gt;
                          ; Pause switch is now pressed (bit 3 is low)&lt;br /&gt;
  LDA #$01                ; Mark that Pause has been latched as pressed&lt;br /&gt;
  STA PrevPausedState&lt;br /&gt;
  BNE EnterPauseSequence  ; Branch always (Pause switch was just pressed, so enter pause logic)&lt;br /&gt;
&lt;br /&gt;
UpdatePauseSwitchState    ; Pause switch was previously latched as pressed&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #SWCHB_Pause_Mask   ; Isolate Pause bit&lt;br /&gt;
  EOR #SWCHB_Pause_Mask   ; Invert Pause bit (so $00=released this cycle, $08=still held)&lt;br /&gt;
  STA PrevPausedState     ; Update debounced state&lt;br /&gt;
&lt;br /&gt;
CheckResetSwitch&lt;br /&gt;
  LDA PrevResetState                  ; Get previous state of Reset switch&lt;br /&gt;
  BNE CheckResetSwitchAndCheckSelect  ; If it was pressed, go update its current debounced state&lt;br /&gt;
&lt;br /&gt;
; Reset switch was not previously pressed, check if it's pressed now&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  LSR                           ; Shift Reset bit (Bit 0) into Carry&lt;br /&gt;
  BCS CheckSelectSwitch_Direct  ; If Carry is set (Reset bit was high, not pressed), check Select&lt;br /&gt;
&lt;br /&gt;
                                              ; Reset switch is now pressed (Bit 0 was low)&lt;br /&gt;
  LDA #$01                                    ; Mark that Reset has been latched as pressed&lt;br /&gt;
  STA PrevResetState&lt;br /&gt;
  BNE ResetStackAndStartGameInDemoMode_Short  ; Branch always (Reset was just pressed)&lt;br /&gt;
&lt;br /&gt;
CheckResetSwitchAndCheckSelect&lt;br /&gt;
  JSR UpdatePrevResetStateFlag          ; Update PrevResetState based on current SWCHB_Reset_Mask state&lt;br /&gt;
                                        ; Falls through to CheckSelectSwitch_Direct&lt;br /&gt;
CheckSelectSwitch_Direct&lt;br /&gt;
  LDA PrevSelectState                   ; Get previous state of Select switch&lt;br /&gt;
  BNE UpdateSelectSwitchStateAndFinish  ; If it was pressed, go update its current debounced state&lt;br /&gt;
&lt;br /&gt;
; Select switch was not previously pressed, check if it's pressed now&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #SWCHB_Select_Mask    ; Isolate Select switch bit (Bit 1)&lt;br /&gt;
  BNE FinishSwitchHandling  ; If Select bit is high (not pressed), we're done&lt;br /&gt;
&lt;br /&gt;
; Select switch is now pressed (Bit 1 is low)&lt;br /&gt;
  LDA #$01                             ; Mark that Select has been latched as pressed&lt;br /&gt;
  STA PrevSelectState&lt;br /&gt;
  JMP ResetStackAndDisplayGameOptions  ; Go to game options screen&lt;br /&gt;
&lt;br /&gt;
UpdateSelectSwitchStateAndFinish&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #SWCHB_Select_Mask&lt;br /&gt;
  EOR #SWCHB_Select_Mask  ; Invert Select bit&lt;br /&gt;
  STA PrevSelectState     ; Update debounced state&lt;br /&gt;
                          ; Falls through to FinishSwitchHandling&lt;br /&gt;
FinishSwitchHandling&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; EnterPauseSequence / PauseGameAndWaitForInput&lt;br /&gt;
; Handles the game pause state. Waits for Pause to be released or other inputs.&lt;br /&gt;
; Mutes audio, saves timers, and monitors switches.&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
EnterPauseSequence&lt;br /&gt;
  LDA TimerHi&lt;br /&gt;
  PHA  ; Save current game timers&lt;br /&gt;
  LDA TimerLo&lt;br /&gt;
  PHA&lt;br /&gt;
  TXA  ; Save X register (usually current player index)&lt;br /&gt;
  PHA&lt;br /&gt;
&lt;br /&gt;
  LDX #$01&lt;br /&gt;
  STX DemoMode  ; Temporarily set DemoMode to 1 (likely to alter some behaviors)&lt;br /&gt;
  DEX           ; X is now 0&lt;br /&gt;
  STX AUDV0     ; Mute audio channel 0&lt;br /&gt;
  STX AUDV1     ; Mute audio channel 1&lt;br /&gt;
&lt;br /&gt;
  LDX TimerHi                     ; Use current TimerHi for a short timeout/loop mechanism&lt;br /&gt;
  DEX                             ; X = TimerHi - 1&lt;br /&gt;
PauseLoop&lt;br /&gt;
  JSR CheckResetSwitch            ; Allow Reset/Select to break out of pause. This will RTS if no action.&lt;br /&gt;
&lt;br /&gt;
  CPX TimerHi                     ; Compare saved TimerHi-1 with current TimerHi&lt;br /&gt;
  BNE PauseLoop_CheckPlayerInput  ; If TimerHi has incremented, skip DMA off&lt;br /&gt;
  LDA #CTRL_DMA_OFF&lt;br /&gt;
  STA CTRL&lt;br /&gt;
&lt;br /&gt;
PauseLoop_CheckPlayerInput&lt;br /&gt;
  LDA SWCHA                  ; Read Player 1 Joystick/Difficulty Switches&lt;br /&gt;
  CMP #$F0                   ; Check if all P1 joystick directions are high (neutral)&lt;br /&gt;
  BCS PauseLoop_CheckP1Fire  ; If neutral or invalid, check P1 fire&lt;br /&gt;
  JSR DisableDMAOnTimeout    ; If joystick active &amp;amp; timeout, potentially change CTRL&lt;br /&gt;
&lt;br /&gt;
PauseLoop_CheckP1Fire&lt;br /&gt;
  LDA P0CurrentFire                      ; Check Player 1 fire button state&lt;br /&gt;
  BMI PauseLoop_ProcessPauseButtonState  ; If fire pressed, proceed&lt;br /&gt;
  JSR DisableDMAOnTimeout                ; If fire not pressed &amp;amp; timeout, potentially change CTRL&lt;br /&gt;
&lt;br /&gt;
PauseLoop_ProcessPauseButtonState&lt;br /&gt;
  LDA PrevPausedState                             ; Get latched/debounced state of Pause&lt;br /&gt;
  BEQ PauseLoop_IfPreviouslyReleasedCheckCurrent  ; If PrevPausedState is 0 (was seen as released)&lt;br /&gt;
&lt;br /&gt;
; PrevPausedState is non-zero (was latched as pressed, or seen as still held)&lt;br /&gt;
  LDA SWCHB              ; Read current physical switch state&lt;br /&gt;
  AND #SWCHB_Pause_Mask  ; Isolate Pause bit&lt;br /&gt;
  EOR #SWCHB_Pause_Mask  ; Invert Pause bit (result $00 if physically RELEASED now, $08 if HELD)&lt;br /&gt;
  STA PrevPausedState    ; Update internal debounced state&lt;br /&gt;
  BPL PauseLoop          ; If $00 (just released) or $08 (still held), continue pause loop&lt;br /&gt;
&lt;br /&gt;
PauseLoop_IfPreviouslyReleasedCheckCurrent&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #SWCHB_Pause_Mask  ; Isolate current physical Pause bit&lt;br /&gt;
  BNE PauseLoop          ; If Pause button is high (physically RELEASED), continue pause loop.&lt;br /&gt;
                         ; Loop until Pause is physically PRESSED AGAIN.&lt;br /&gt;
&lt;br /&gt;
; Fall-through: Pause button is now physically PRESSED again (value is $00 after AND)&lt;br /&gt;
; This is the condition to EXIT the pause state.&lt;br /&gt;
&lt;br /&gt;
ResumeGameFromPause&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX          ; Restore X register&lt;br /&gt;
  PLA&lt;br /&gt;
  STA TimerLo  ; Restore game timers&lt;br /&gt;
  PLA&lt;br /&gt;
  STA TimerHi&lt;br /&gt;
&lt;br /&gt;
  LDA #$01      ; Set PrevPausedState to 1. This indicates the pause cycle is complete&lt;br /&gt;
               ; and the pause button is considered &amp;quot;up&amp;quot; for the next check in HandleConsoleSwitches.&lt;br /&gt;
  STA PrevPausedState&lt;br /&gt;
  LSR           ; A = 0 (from $01 LSR)&lt;br /&gt;
  STA DemoMode  ; Clear the temporary DemoMode set during pause&lt;br /&gt;
  LDA #CTRL_DMA_ON_160AB&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SetupTitleScrText&lt;br /&gt;
; The Titlescreen border in Joust has a bunch of slanty angle characters&lt;br /&gt;
; that scroll. The following code just sets up the initial slanty char&lt;br /&gt;
; indexes in each string.&lt;br /&gt;
&lt;br /&gt;
SetupTitleColumns&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA TitleBorderStr0&lt;br /&gt;
  LDA #$38&lt;br /&gt;
  STA TitleBorderStr1&lt;br /&gt;
  LDA #$36&lt;br /&gt;
  STA TitleBorderStr2&lt;br /&gt;
  LDA #$3E&lt;br /&gt;
  STA TitleBorderStr3&lt;br /&gt;
&lt;br /&gt;
  LDX #$1E&lt;br /&gt;
SetupTitleRowLoop&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA TitleBorderStr4,X&lt;br /&gt;
  LDA #$34&lt;br /&gt;
  STA TitleBorderStr5,X&lt;br /&gt;
  DEX&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL SetupTitleRowLoop&lt;br /&gt;
  LDX #$1C&lt;br /&gt;
  STX TitleColorIndex&lt;br /&gt;
  LDA TitleColors,X&lt;br /&gt;
  STA $0191&lt;br /&gt;
  LDA DelayBetweenTitleColorChanges,X&lt;br /&gt;
  STA TitleColorChangeCountdown&lt;br /&gt;
&lt;br /&gt;
  LDX #$1C&lt;br /&gt;
CopyrghtToBuffer&lt;br /&gt;
  LDA StringCopyright,X&lt;br /&gt;
  STA TitleCopyrightCharBuffer,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL CopyrghtToBuffer&lt;br /&gt;
&lt;br /&gt;
; Copy character set values that make up most of the JOUST logo.&lt;br /&gt;
; The very top and bottom of the logo aren't part of this.&lt;br /&gt;
  LDX #$E7&lt;br /&gt;
CopyMiddleTitleLogoDataToRamLoop&lt;br /&gt;
  LDA MiddleTitleLogoDataCharsLUT,X&lt;br /&gt;
  STA TitleScreenLogoCharBuffer,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyMiddleTitleLogoDataToRamLoop&lt;br /&gt;
&lt;br /&gt;
SetDemoPalette&lt;br /&gt;
  LDX #$0B&lt;br /&gt;
  STX EggsPresentCount&lt;br /&gt;
  LDA PaletteFadeInRed,X&lt;br /&gt;
  STA $01A5&lt;br /&gt;
  STA P7C1&lt;br /&gt;
  LDA PaletteFadeInYellow,X&lt;br /&gt;
  STA $01A6&lt;br /&gt;
  STA P7C2&lt;br /&gt;
  LDA PaletteFadeInBrown,X&lt;br /&gt;
  STA $01A7&lt;br /&gt;
  STA P7C3&lt;br /&gt;
  LDA TitleScreenColorChangeDelayLUT,X&lt;br /&gt;
  STA EnemyBirdCount&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AnimateTitleScreenFrame&lt;br /&gt;
  DEC TitleColorChangeCountdown&lt;br /&gt;
  BPL DoTitleFrameAnimation&lt;br /&gt;
  DEC TitleColorIndex&lt;br /&gt;
  BPL WrapTitleColorIndex&lt;br /&gt;
  LDA #$1C&lt;br /&gt;
  STA TitleColorIndex&lt;br /&gt;
WrapTitleColorIndex&lt;br /&gt;
  LDX TitleColorIndex&lt;br /&gt;
  LDA TitleColors,X&lt;br /&gt;
  STA $0191&lt;br /&gt;
  LDA DelayBetweenTitleColorChanges,X&lt;br /&gt;
  STA TitleColorChangeCountdown&lt;br /&gt;
DoTitleFrameAnimation&lt;br /&gt;
  INC TitleBorderStr0       ; left-most char in left column&lt;br /&gt;
  LDA TitleBorderStr0&lt;br /&gt;
  CMP #$38&lt;br /&gt;
  BCC SkipCharResetStr0&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA TitleBorderStr0&lt;br /&gt;
SkipCharResetStr0&lt;br /&gt;
  INC TitleBorderStr2       ; left-most char in right column&lt;br /&gt;
  LDA TitleBorderStr2&lt;br /&gt;
  CMP #$38&lt;br /&gt;
  BCC SkipCharResetStr2&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA TitleBorderStr2&lt;br /&gt;
SkipCharResetStr2&lt;br /&gt;
  INC TitleBorderStr1       ; right-most char in left column&lt;br /&gt;
  LDA TitleBorderStr1&lt;br /&gt;
  CMP #$40&lt;br /&gt;
  BCC SkipCharResetStr1&lt;br /&gt;
  LDA #$38&lt;br /&gt;
  STA TitleBorderStr1&lt;br /&gt;
SkipCharResetStr1&lt;br /&gt;
  INC TitleBorderStr3       ; right-most char in right column&lt;br /&gt;
  LDA TitleBorderStr3&lt;br /&gt;
  CMP #$40&lt;br /&gt;
  BCC SkipCharResetStr3&lt;br /&gt;
  LDA #$38&lt;br /&gt;
  STA TitleBorderStr3&lt;br /&gt;
SkipCharResetStr3&lt;br /&gt;
  LDX #$1F&lt;br /&gt;
AnimateTitleFrameColumnsLoop&lt;br /&gt;
  INC TitleBorderStr4,X     ; top row and bottom row of 32 characters&lt;br /&gt;
  LDA TitleBorderStr4,X&lt;br /&gt;
  CMP #$38&lt;br /&gt;
  BCC SkipCharResetStr4plus&lt;br /&gt;
  LDA #$30&lt;br /&gt;
  STA TitleBorderStr4,X&lt;br /&gt;
SkipCharResetStr4plus&lt;br /&gt;
  DEX&lt;br /&gt;
  BPL AnimateTitleFrameColumnsLoop&lt;br /&gt;
&lt;br /&gt;
CycleTitleScreenPaletteAndCounters&lt;br /&gt;
  LDA ColorChangeTimer&lt;br /&gt;
  BMI CycleColorExit&lt;br /&gt;
  DEC ColorChangeTimer&lt;br /&gt;
  BPL CycleColorExit&lt;br /&gt;
  DEC ColorCycleIndex&lt;br /&gt;
  BPL CycleIndexStillPositive&lt;br /&gt;
  LDA #$0B&lt;br /&gt;
  STA ColorCycleIndex&lt;br /&gt;
CycleIndexStillPositive&lt;br /&gt;
  LDX ColorCycleIndex&lt;br /&gt;
  LDA PaletteFadeInRed,X&lt;br /&gt;
  STA $01A5&lt;br /&gt;
  STA P7C1&lt;br /&gt;
  LDA PaletteFadeInYellow,X&lt;br /&gt;
  STA $01A6&lt;br /&gt;
  STA P7C2&lt;br /&gt;
  LDA PaletteFadeInBrown,X&lt;br /&gt;
  STA $01A7&lt;br /&gt;
  STA P7C3&lt;br /&gt;
  LDA TitleScreenColorChangeDelayLUT,X&lt;br /&gt;
  STA ColorChangeTimer&lt;br /&gt;
CycleColorExit&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
UpdatePrevResetStateFlag&lt;br /&gt;
  LDA SWCHB&lt;br /&gt;
  AND #$01&lt;br /&gt;
  EOR #$01&lt;br /&gt;
  STA PrevResetState&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DisableDMAOnTimeout&lt;br /&gt;
  LDA #$40&lt;br /&gt;
  STA CTRL&lt;br /&gt;
  LDX TimerHi&lt;br /&gt;
  DEX&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HideOrShowTwoPlayerText&lt;br /&gt;
 .byte 160                ; off-screen&lt;br /&gt;
HideOrShowOnePlayerText&lt;br /&gt;
 .byte 48                 ; on-screen&lt;br /&gt;
 .byte 160                ; off-screen&lt;br /&gt;
&lt;br /&gt;
; 000000000000000011111111111111112222222222222222&lt;br /&gt;
; 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF&lt;br /&gt;
; _0123456789@0123456789@ABCDEGHIJLMNPRSTUVWXYZK() **then the title border and logo chars&lt;br /&gt;
&lt;br /&gt;
DifficultyTextXCoordinate&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $20&lt;br /&gt;
 .byte $45&lt;br /&gt;
 .byte $62&lt;br /&gt;
&lt;br /&gt;
DifficultyText&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $18      ; 'B'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $1C      ; 'G'&lt;br /&gt;
 .byte $1E      ; 'I'&lt;br /&gt;
 .byte $22      ; 'N'&lt;br /&gt;
 .byte $22      ; 'N'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $24      ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1E      ; 'I'&lt;br /&gt;
 .byte $22      ; 'N'&lt;br /&gt;
 .byte $26      ; 'T'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $24      ; 'R'&lt;br /&gt;
 .byte $21      ; 'M'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $1A      ; 'D'&lt;br /&gt;
 .byte $1E      ; 'I'&lt;br /&gt;
 .byte $17      ; 'A'&lt;br /&gt;
 .byte $26      ; 'T'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $17      ; 'A'&lt;br /&gt;
 .byte $0C      ; '0'&lt;br /&gt;
 .byte $28      ; 'V'&lt;br /&gt;
 .byte $17      ; 'A'&lt;br /&gt;
 .byte $22      ; 'N'&lt;br /&gt;
 .byte $19      ; 'C'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $1A      ; 'D'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $2A      ; 'X'&lt;br /&gt;
 .byte $23      ; 'P'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $24      ; 'R'&lt;br /&gt;
 .byte $26      ; 'T'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
StringOnePlayer&lt;br /&gt;
 .byte $00      ; \ These 3 bytes are also &lt;br /&gt;
 .byte $00      ; &amp;gt; part of the &amp;quot;EXPERT&amp;quot; string&lt;br /&gt;
 .byte $00      ; / post-padding.&lt;br /&gt;
&lt;br /&gt;
 .byte $0C      ; '0'&lt;br /&gt;
 .byte $22      ; 'N'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $00      ; &lt;br /&gt;
 .byte $23      ; 'P'&lt;br /&gt;
 .byte $20      ; 'L'&lt;br /&gt;
 .byte $17      ; 'A'&lt;br /&gt;
 .byte $2B      ; 'Y'&lt;br /&gt;
 .byte $1B      ; 'E'&lt;br /&gt;
 .byte $24      ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
StringTwoPlayer&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $26  ; 'T'&lt;br /&gt;
 .byte $29  ; 'W'&lt;br /&gt;
 .byte $0C  ; '0'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $23  ; 'P'&lt;br /&gt;
 .byte $20  ; 'L'&lt;br /&gt;
 .byte $17  ; 'A'&lt;br /&gt;
 .byte $2B  ; 'Y'&lt;br /&gt;
 .byte $1B  ; 'E'&lt;br /&gt;
 .byte $24  ; 'R'&lt;br /&gt;
 .byte $00&lt;br /&gt;
 .byte $00&lt;br /&gt;
&lt;br /&gt;
MiddleTitleLogoDataCharsLUT&lt;br /&gt;
 .byte $00, $59, $5A, $5B, $5C, $5D, $5E, $41&lt;br /&gt;
 .byte $40, $40, $5F, $60, $61, $62, $63, $64&lt;br /&gt;
 .byte $65, $66, $43, $40, $67, $68, $40, $69&lt;br /&gt;
 .byte $40, $6A, $6B, $6C, $6D, $6E, $6F, $70&lt;br /&gt;
 .byte $71, $72, $73, $74, $40, $75, $76, $40&lt;br /&gt;
 .byte $77, $78, $79, $40, $7A, $7B, $40, $7C&lt;br /&gt;
 .byte $7D, $7E, $46, $43, $40, $7F, $40, $80&lt;br /&gt;
 .byte $81, $82, $83, $43, $84, $85, $86, $87&lt;br /&gt;
 .byte $88, $89, $8A, $8B, $8C, $8D, $40, $42&lt;br /&gt;
 .byte $8E, $8F, $90, $91, $92, $40, $93, $43&lt;br /&gt;
 .byte $40, $44, $95, $96, $46, $43, $97, $98&lt;br /&gt;
 .byte $99, $40, $9A, $9B, $9C, $9D, $46, $9E&lt;br /&gt;
 .byte $9F, $A0, $A1, $A2, $40, $42, $45, $A3&lt;br /&gt;
 .byte $A4, $A5, $A6, $40, $A7, $45, $40, $44&lt;br /&gt;
 .byte $A8, $A9, $AA, $AB, $AC, $AD, $AE, $AF&lt;br /&gt;
 .byte $B0, $40, $B1, $44, $B2, $40, $B3, $B4&lt;br /&gt;
 .byte $B5, $B6, $44, $44, $40, $42, $45, $42&lt;br /&gt;
 .byte $46, $44, $B7, $40, $B8, $45, $40, $B9&lt;br /&gt;
 .byte $BA, $BB, $BC, $40, $BD, $BE, $BF, $C0&lt;br /&gt;
 .byte $C1, $C2, $C3, $C4, $41, $40, $C5, $C6&lt;br /&gt;
 .byte $C7, $C8, $C9, $40, $CA, $CB, $CC, $40&lt;br /&gt;
 .byte $42, $43, $40, $CD, $44, $CE, $40, $CF&lt;br /&gt;
 .byte $D0, $40, $D1, $D2, $D3, $41, $40, $D4&lt;br /&gt;
 .byte $D5, $D6, $D7, $D8, $D9, $40, $DA, $41&lt;br /&gt;
 .byte $40, $DB, $44, $44, $DC, $47, $48, $40&lt;br /&gt;
 .byte $40, $40, $40, $49, $4A, $4B, $41, $4C&lt;br /&gt;
 .byte $4D, $4E, $4F, $50, $51, $40, $40, $40&lt;br /&gt;
 .byte $41, $40, $40, $52, $53, $40, $40, $40&lt;br /&gt;
 .byte $54, $55, $41, $40, $56, $57, $58, $40&lt;br /&gt;
&lt;br /&gt;
DelayBetweenTitleColorChanges&lt;br /&gt;
 .byte $3C, $03, $03, $3C, $03, $03, $03&lt;br /&gt;
 .byte $03, $03, $3C, $03, $03, $03, $03&lt;br /&gt;
 .byte $03, $03, $3C, $03, $03, $03, $3C&lt;br /&gt;
 .byte $03, $03, $03, $03, $03, $03, $03&lt;br /&gt;
 .byte $03&lt;br /&gt;
&lt;br /&gt;
TitleColors&lt;br /&gt;
 .byte $24, $15, $06, $F7, $D6, $C5, $B5&lt;br /&gt;
 .byte $A5, $95, $85, $76, $67, $58, $49&lt;br /&gt;
 .byte $3A, $2B, $1D, $1C, $1B, $0C, $0D&lt;br /&gt;
 .byte $0C, $0B, $1A, $19, $28, $27, $26 &lt;br /&gt;
 .byte $25&lt;br /&gt;
&lt;br /&gt;
PaletteFadeInRed&lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $33 &lt;br /&gt;
 .byte $32 &lt;br /&gt;
 .byte $22 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
&lt;br /&gt;
PaletteFadeInYellow&lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1D &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1B &lt;br /&gt;
 .byte $1A &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $22 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
&lt;br /&gt;
PaletteFadeInBrown&lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
&lt;br /&gt;
TitleScreenColorChangeDelayLUT&lt;br /&gt;
 .byte $FF &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
&lt;br /&gt;
MuteAudio&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA SFXChannel0Index&lt;br /&gt;
  STA SFXChannel1Index&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA AUDV0&lt;br /&gt;
  STA AUDV1&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SilenceSFXIfPlaying&lt;br /&gt;
; Check if this particular sound effect is playing on channel 0&lt;br /&gt;
  CMP SFXChannel0Index&lt;br /&gt;
  BNE SilenceSFXIfPlayingChannel1&lt;br /&gt;
; yes? then silence it and mark the channel index as available&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA AUDV0&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA SFXChannel0Index&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SilenceSFXIfPlayingChannel1&lt;br /&gt;
; Check if this particular sound effect is playing on channel 1&lt;br /&gt;
  SEC&lt;br /&gt;
  SBC SFXChannel1Index&lt;br /&gt;
  BNE EarlyReturn1&lt;br /&gt;
; yes? then silence it and mark the channel index as available&lt;br /&gt;
  STA AUDV1&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA SFXChannel1Index&lt;br /&gt;
EarlyReturn1&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ScheduleSFX&lt;br /&gt;
  STA Temp6ASFXIndex&lt;br /&gt;
  LDA GameActiveFlag&lt;br /&gt;
  BNE EarlyReturn1&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE EarlyReturn1&lt;br /&gt;
  TYA&lt;br /&gt;
  PHA&lt;br /&gt;
  TXA&lt;br /&gt;
  PHA&lt;br /&gt;
  LDY #$01&lt;br /&gt;
  LDX Temp6ASFXIndex&lt;br /&gt;
FindFreeSFXChannelLoop&lt;br /&gt;
  LDA.w SFXChannel0Index,Y&lt;br /&gt;
  CMP #$FF&lt;br /&gt;
  BEQ ScheduleSFXChannelY&lt;br /&gt;
  DEY&lt;br /&gt;
  BPL FindFreeSFXChannelLoop&lt;br /&gt;
; If we're here there was no free sound effect channel. Instead we'll&lt;br /&gt;
; look for a sound effect in the same &amp;quot;interrupt group&amp;quot; and interrupt&lt;br /&gt;
; it.&lt;br /&gt;
  LDA SFXChannel1Index&lt;br /&gt;
  AND #$7F&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA SFXInterruptGroups,X&lt;br /&gt;
  CMP SFXInterruptGroups,Y&lt;br /&gt;
  LDY #$01&lt;br /&gt;
  BCS ScheduleSFXChannelY&lt;br /&gt;
  LDA SFXChannel0Index&lt;br /&gt;
  AND #$7F&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA SFXInterruptGroups,X&lt;br /&gt;
  CMP SFXInterruptGroups,Y&lt;br /&gt;
  BCC SkipScheduleSFX&lt;br /&gt;
  LDY #$00&lt;br /&gt;
ScheduleSFXChannelY&lt;br /&gt;
  TXA&lt;br /&gt;
  ORA #$80&lt;br /&gt;
  STA.w SFXChannel0Index,Y&lt;br /&gt;
SkipScheduleSFX&lt;br /&gt;
  PLA&lt;br /&gt;
  TAX&lt;br /&gt;
  PLA&lt;br /&gt;
  TAY&lt;br /&gt;
EarlyReturn2&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
ServiceSFX&lt;br /&gt;
  LDA DemoMode&lt;br /&gt;
  BNE EarlyReturn2&lt;br /&gt;
  LDX #$01&lt;br /&gt;
ServiceSFXLoop&lt;br /&gt;
  LDY SFXChannel0Index,X&lt;br /&gt;
  INY                       ; FF is the voice not-in-use flag. FF+1=0&lt;br /&gt;
  BNE ServiceSFXDoVoice&lt;br /&gt;
GoServiceSFXVoiceDone&lt;br /&gt;
  JMP ServiceSFXVoiceDone&lt;br /&gt;
ServiceSFXDoVoice&lt;br /&gt;
  DEY                       ; undo the previous INY&lt;br /&gt;
  BPL PlaySoundSlice&lt;br /&gt;
                           ; If the SFX index top bit it set, the sound was just scheduled.&lt;br /&gt;
                           ; We need to do some init.&lt;br /&gt;
  TYA&lt;br /&gt;
  AND #$7F                  ; clear the &amp;quot;just scheduled&amp;quot; bit&lt;br /&gt;
  STA SFXChannel0Index,X&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA $2100,X&lt;br /&gt;
  LDA #$FF&lt;br /&gt;
  STA $2102,X&lt;br /&gt;
  STA $2104,X&lt;br /&gt;
  STA $2106,X&lt;br /&gt;
PlaySoundSlice&lt;br /&gt;
  LDA SFX_FreqAndControlDataPtrLoLUT,Y&lt;br /&gt;
  STA $5C&lt;br /&gt;
  LDA SFX_FreqAndControlDataPtrHiLUT,Y&lt;br /&gt;
  STA $5D&lt;br /&gt;
  DEC $2100,X&lt;br /&gt;
  BNE GoServiceSFXVoiceDone&lt;br /&gt;
  LDA SFX_SampleDurationLUT,Y&lt;br /&gt;
  STA $2100,X&lt;br /&gt;
  LDY $2102,X&lt;br /&gt;
  INC $2104,X&lt;br /&gt;
  INC $2106,X&lt;br /&gt;
  INY&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  CMP #$FF                  ; sound EOD marker&lt;br /&gt;
  BNE SFXIsStillPlaying&lt;br /&gt;
  STA SFXChannel0Index,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA AUDV0,X&lt;br /&gt;
  BEQ GoServiceSFXVoiceDone&lt;br /&gt;
SFXIsStillPlaying&lt;br /&gt;
  CMP #$FE&lt;br /&gt;
  BEQ SFX_HandleResetAndContinueCommand&lt;br /&gt;
  CMP #$FD&lt;br /&gt;
  BNE SFX_ProcessStandardPitchData&lt;br /&gt;
  INY&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  STA SFXChannel0Index,X&lt;br /&gt;
  TAY&lt;br /&gt;
  LDA SFX_FreqAndControlDataPtrLoLUT,Y&lt;br /&gt;
  STA $5C&lt;br /&gt;
  LDA SFX_FreqAndControlDataPtrHiLUT,Y&lt;br /&gt;
  STA $5D&lt;br /&gt;
SFX_HandleResetAndContinueCommand&lt;br /&gt;
  LDY #$00&lt;br /&gt;
  TYA&lt;br /&gt;
  STA $2104,X&lt;br /&gt;
  STA $2106,X&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
SFX_ProcessStandardPitchData&lt;br /&gt;
  BPL SFX_ProcessPitchDataFlags&lt;br /&gt;
  INY&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  STA $2100,X&lt;br /&gt;
  DEY&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  INY&lt;br /&gt;
  JMP SFX_SetChannelPitch&lt;br /&gt;
SFX_ProcessPitchDataFlags&lt;br /&gt;
  ASL&lt;br /&gt;
  BPL SFX_ProcessPitchNoiseFlag&lt;br /&gt;
  LSR&lt;br /&gt;
  AND #$BF&lt;br /&gt;
  STA $2100,X&lt;br /&gt;
  TYA&lt;br /&gt;
  STA $2102,X&lt;br /&gt;
  DEC $2106,X&lt;br /&gt;
  DEC $2104,X&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA AUDV0,X&lt;br /&gt;
  BEQ ServiceSFXVoiceDone&lt;br /&gt;
SFX_ProcessPitchNoiseFlag&lt;br /&gt;
  LSR&lt;br /&gt;
SFX_SetChannelPitch&lt;br /&gt;
  STA AUDF0,X&lt;br /&gt;
  TYA&lt;br /&gt;
  STA $2102,X&lt;br /&gt;
  LDY SFXChannel0Index,X&lt;br /&gt;
  LDA SFX_VolumeDataPtrLoLUT,Y&lt;br /&gt;
  STA $5C&lt;br /&gt;
  LDA SFX_VolumeDataPtrHiLUT,Y&lt;br /&gt;
  STA $5D&lt;br /&gt;
  LDY $2106,X&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  BPL SFX_SetChannelVolume&lt;br /&gt;
  DEY&lt;br /&gt;
SFX_SetChannelVolume&lt;br /&gt;
  STA AUDV0,X&lt;br /&gt;
  TYA&lt;br /&gt;
  STA $2106,X&lt;br /&gt;
  LDY SFXChannel0Index,X&lt;br /&gt;
  LDA SFX_DistortionDataPtrLoLUT,Y&lt;br /&gt;
  STA $5C&lt;br /&gt;
  LDA SFX_DistortionDataPtrHiLUT,Y&lt;br /&gt;
  STA $5D&lt;br /&gt;
  LDY $2104,X&lt;br /&gt;
  LDA ($5C),Y&lt;br /&gt;
  BPL SFX_SetChannelDistortion&lt;br /&gt;
  DEY&lt;br /&gt;
SFX_SetChannelDistortion&lt;br /&gt;
  STA AUDC0,X&lt;br /&gt;
  TYA&lt;br /&gt;
  STA $2104,X&lt;br /&gt;
ServiceSFXVoiceDone&lt;br /&gt;
  DEX&lt;br /&gt;
  BMI ExitSFXServiceLoop&lt;br /&gt;
  JMP ServiceSFXLoop&lt;br /&gt;
ExitSFXServiceLoop&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
SFX_FreqAndControlDataPtrLoLUT&lt;br /&gt;
 .byte &amp;lt;SFX_00_CoinDropAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_01_FreeBirdAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_02_PickupEggAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_03_GameStartAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_04_BirdPlatformBounceAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_05_BirdBirdBounceAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_06_PlayerFootstepAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_07_PterryDefeatedAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_08_PterryChargingAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_09_PlayerBornAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0A_InvulnerableAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0B_EggWigglingAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0C_EnemyBirdBornAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0D_TrollJumpingAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0E_PlatformDissolveAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_0F_SkidAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_10_BirdExplosionAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_11_CheepCheepAUDF&lt;br /&gt;
 .byte &amp;lt;SFX_12_PlayerBirdFlapAUDF&lt;br /&gt;
&lt;br /&gt;
SFX_VolumeDataPtrLoLUT&lt;br /&gt;
 .byte &amp;lt;SFX_00_CoinDropAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_01_FreeBirdAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_02_PickupEggAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_03_GameStartAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_04_BirdPlatformBounceAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_05_BirdBirdBounceAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_06_PlayerFootstepAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_07_PterryDefeatedAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_08_PterryChargingAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_09_PlayerBornAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0A_InvulnerableAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0B_EggWigglingAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0C_EnemyBirdBornAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0D_TrollJumpingAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0E_PlatformDissolveAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_0F_SkidAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_10_BirdExplosionAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_11_CheepCheepAUDV&lt;br /&gt;
 .byte &amp;lt;SFX_12_PlayerBirdFlapAUDV&lt;br /&gt;
&lt;br /&gt;
SFX_DistortionDataPtrLoLUT&lt;br /&gt;
 .byte &amp;lt;SFX_00_CoinDropAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_01_FreeBirdAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_02_PickupEggAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_03_GameStartAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_04_BirdPlatformBounceAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_05_BirdBirdBounceAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_06_PlayerFootstepAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_07_PterryDefeatedAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_08_PterryChargingAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_09_PlayerBornAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0A_InvulnerableAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0B_EggWigglingAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0C_EnemyBirdBornAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0D_TrollJumpingAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0E_PlatformDissolveAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_0F_SkidAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_10_BirdExplosionAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_11_CheepCheepAUDC&lt;br /&gt;
 .byte &amp;lt;SFX_12_PlayerBirdFlapAUDC&lt;br /&gt;
&lt;br /&gt;
SFX_DistortionDataPtrHiLUT&lt;br /&gt;
 .byte &amp;gt;SFX_00_CoinDropAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_01_FreeBirdAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_02_PickupEggAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_03_GameStartAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_04_BirdPlatformBounceAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_05_BirdBirdBounceAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_06_PlayerFootstepAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_07_PterryDefeatedAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_08_PterryChargingAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_09_PlayerBornAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0A_InvulnerableAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0B_EggWigglingAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0C_EnemyBirdBornAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0D_TrollJumpingAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0E_PlatformDissolveAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_0F_SkidAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_10_BirdExplosionAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_11_CheepCheepAUDC&lt;br /&gt;
 .byte &amp;gt;SFX_12_PlayerBirdFlapAUDC&lt;br /&gt;
&lt;br /&gt;
SFX_VolumeDataPtrHiLUT&lt;br /&gt;
 .byte &amp;gt;SFX_00_CoinDropAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_01_FreeBirdAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_02_PickupEggAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_03_GameStartAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_04_BirdPlatformBounceAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_05_BirdBirdBounceAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_06_PlayerFootstepAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_07_PterryDefeatedAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_08_PterryChargingAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_09_PlayerBornAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0A_InvulnerableAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0B_EggWigglingAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0C_EnemyBirdBornAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0D_TrollJumpingAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0E_PlatformDissolveAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_0F_SkidAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_10_BirdExplosionAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_11_CheepCheepAUDV&lt;br /&gt;
 .byte &amp;gt;SFX_12_PlayerBirdFlapAUDV&lt;br /&gt;
&lt;br /&gt;
SFX_FreqAndControlDataPtrHiLUT&lt;br /&gt;
 .byte &amp;gt;SFX_00_CoinDropAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_01_FreeBirdAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_02_PickupEggAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_03_GameStartAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_04_BirdPlatformBounceAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_05_BirdBirdBounceAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_06_PlayerFootstepAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_07_PterryDefeatedAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_08_PterryChargingAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_09_PlayerBornAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0A_InvulnerableAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0B_EggWigglingAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0C_EnemyBirdBornAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0D_TrollJumpingAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0E_PlatformDissolveAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_0F_SkidAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_10_BirdExplosionAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_11_CheepCheepAUDF&lt;br /&gt;
 .byte &amp;gt;SFX_12_PlayerBirdFlapAUDF&lt;br /&gt;
&lt;br /&gt;
SFX_SampleDurationLUT&lt;br /&gt;
 .byte $02, $01, $02, $01, $01, $01, $01, $04&lt;br /&gt;
 .byte $02, $04, $07, $02, $04, $02, $0E, $01&lt;br /&gt;
 .byte $02, $01, $01 &lt;br /&gt;
&lt;br /&gt;
SFXInterruptGroups&lt;br /&gt;
 .byte $00  ; 00:?coin drop sfx?&lt;br /&gt;
 .byte $09  ; 01:free bird notification sfx&lt;br /&gt;
 .byte $05  ; 02:pickup egg sfx&lt;br /&gt;
 .byte $09  ; 03:game start sfx&lt;br /&gt;
 .byte $02  ; 04:bird bounced off platform sfx&lt;br /&gt;
 .byte $04  ; 05:bird bounced off bird sfx&lt;br /&gt;
 .byte $02  ; 06:player footstep sfx&lt;br /&gt;
 .byte $08  ; 07:pterry defeated sfx&lt;br /&gt;
 .byte $04  ; 08:pterry charging sfx&lt;br /&gt;
 .byte $05  ; 09:player born on platform sfx&lt;br /&gt;
 .byte $05  ; 0A:player invulnerable sfx&lt;br /&gt;
 .byte $00  ; 0B:egg wiggling sfx&lt;br /&gt;
 .byte $03  ; 0C:enemy bird born sfx&lt;br /&gt;
 .byte $04  ; 0D:troll jumping sfx&lt;br /&gt;
 .byte $06  ; 0E:platform dissolve sfx&lt;br /&gt;
 .byte $03  ; 0F:skid sfx&lt;br /&gt;
 .byte $07  ; 10:bird died explosion sfx&lt;br /&gt;
 .byte $00  ; 11:cheep cheep sfx&lt;br /&gt;
 .byte $02  ; 12:player bird flap sfx&lt;br /&gt;
&lt;br /&gt;
SFX_00_CoinDropAUDF&lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_00_CoinDropAUDV&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
SFX_00_CoinDropAUDC&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $8D &lt;br /&gt;
&lt;br /&gt;
SFX_01_FreeBirdAUDF&lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_01_FreeBirdAUDV&lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
&lt;br /&gt;
SFX_02_PickupEggAUDF&lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_02_PickupEggAUDV&lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
&lt;br /&gt;
SFX_03_GameStartAUDF&lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_03_GameStartAUDV&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
&lt;br /&gt;
SFX_04_BirdPlatformBounceAUDF&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
SFX_05_BirdBirdBounceAUDF&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_05_BirdBirdBounceAUDV&lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
&lt;br /&gt;
SFX_06_PlayerFootstepAUDF&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
SFX_07_PterryDefeatedAUDF&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $1A &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
SFX_08_PterryChargingAUDF&lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_08_PterryChargingAUDV&lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
&lt;br /&gt;
SFX_09_PlayerBornAUDF&lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $1D &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_09_PlayerBornAUDV&lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
&lt;br /&gt;
SFX_0A_InvulnerableAUDF&lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1D &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1B &lt;br /&gt;
 .byte $1A &lt;br /&gt;
 .byte $19 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $13 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $10 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_0A_InvulnerableAUDV&lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
SFX_0B_EggWigglingAUDF&lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_0B_EggWigglingAUDV&lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
&lt;br /&gt;
SFX_0C_EnemyBirdBornAUDF&lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1D &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1B &lt;br /&gt;
 .byte $1A &lt;br /&gt;
 .byte $19 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $13 &lt;br /&gt;
 .byte $12 &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_0C_EnemyBirdBornAUDV&lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $88 &lt;br /&gt;
&lt;br /&gt;
SFX_0D_TrollJumpingAUDF&lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_0D_TrollJumpingAUDV&lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
&lt;br /&gt;
SFX_0E_PlatformDissolveAUDF&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_0E_PlatformDissolveAUDV&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
&lt;br /&gt;
SFX_0F_SkidAUDF&lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $16 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $14 &lt;br /&gt;
 .byte $FE &lt;br /&gt;
&lt;br /&gt;
SFX_10_BirdExplosionAUDF&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $11 &lt;br /&gt;
 .byte $13 &lt;br /&gt;
 .byte $15 &lt;br /&gt;
 .byte $17 &lt;br /&gt;
 .byte $19 &lt;br /&gt;
 .byte $1B &lt;br /&gt;
 .byte $1D &lt;br /&gt;
 .byte $1E &lt;br /&gt;
 .byte $1F &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_10_BirdExplosionAUDV&lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
&lt;br /&gt;
SFX_11_CheepCheepAUDF&lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $0D &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
SFX_12_PlayerBirdFlapAUDF&lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $18 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
SFX_12_PlayerBirdFlapAUDV&lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
SFX_07_PterryDefeatedAUDC&lt;br /&gt;
SFX_0B_EggWigglingAUDC&lt;br /&gt;
SFX_0D_TrollJumpingAUDC&lt;br /&gt;
SFX_0E_PlatformDissolveAUDC&lt;br /&gt;
SFX_10_BirdExplosionAUDC&lt;br /&gt;
SFX_12_PlayerBirdFlapAUDC&lt;br /&gt;
 .byte $88 &lt;br /&gt;
SFX_01_FreeBirdAUDC&lt;br /&gt;
SFX_03_GameStartAUDC&lt;br /&gt;
SFX_04_BirdPlatformBounceAUDC&lt;br /&gt;
SFX_05_BirdBirdBounceAUDC&lt;br /&gt;
SFX_0F_SkidAUDC&lt;br /&gt;
SFX_11_CheepCheepAUDC&lt;br /&gt;
 .byte $84 &lt;br /&gt;
SFX_08_PterryChargingAUDC&lt;br /&gt;
SFX_0A_InvulnerableAUDC&lt;br /&gt;
 .byte $87 &lt;br /&gt;
SFX_02_PickupEggAUDC&lt;br /&gt;
SFX_09_PlayerBornAUDC&lt;br /&gt;
 .byte $8D &lt;br /&gt;
SFX_06_PlayerFootstepAUDC&lt;br /&gt;
 .byte $86 &lt;br /&gt;
SFX_0C_EnemyBirdBornAUDC&lt;br /&gt;
 .byte $83 &lt;br /&gt;
SFX_06_PlayerFootstepAUDV&lt;br /&gt;
SFX_0F_SkidAUDV&lt;br /&gt;
 .byte $88 &lt;br /&gt;
SFX_04_BirdPlatformBounceAUDV&lt;br /&gt;
 .byte $84 &lt;br /&gt;
SFX_07_PterryDefeatedAUDV&lt;br /&gt;
 .byte $8A &lt;br /&gt;
SFX_11_CheepCheepAUDV&lt;br /&gt;
 .byte $82 &lt;br /&gt;
&lt;br /&gt;
DoHscStatusCheck&lt;br /&gt;
  JSR InitForHsc&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA $250E&lt;br /&gt;
  JSR $3FF7      ; HSCSTAT check status of HSC and some cart init&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DoHscAttractMode&lt;br /&gt;
  JSR InitForHsc&lt;br /&gt;
  JSR $3FFA      ; HSCATRCT - attract mode score display&lt;br /&gt;
&lt;br /&gt;
RestoreCharbaseAndExit&lt;br /&gt;
  LDA #$C8&lt;br /&gt;
  STA CHARBASE&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA NMIModeFlag&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
DoHscScoreEntry&lt;br /&gt;
  LDA Difficulty&lt;br /&gt;
  STA Temp62                 ; save difficulty&lt;br /&gt;
  JSR InitForHsc&lt;br /&gt;
  LDA PlayerCount&lt;br /&gt;
  BEQ HscScoreEntryHandlePlayer1&lt;br /&gt;
  LDA CurrentPlayer&lt;br /&gt;
  BNE HscScoreEntryHandlePlayer1&lt;br /&gt;
  STA $250E&lt;br /&gt;
HscScoreEntryHandlePlayer1&lt;br /&gt;
  JSR $3FFD                  ; HSC score entry routine&lt;br /&gt;
  JMP RestoreCharbaseAndExit&lt;br /&gt;
&lt;br /&gt;
InitForHsc&lt;br /&gt;
  LDA $3900                  ; Check two bytes of the HSC rom to ensure it's&lt;br /&gt;
  CMP #$C6                   ; plugged in.&lt;br /&gt;
  BNE AbortUsingHSC&lt;br /&gt;
  LDA $3904&lt;br /&gt;
  CMP #$FE&lt;br /&gt;
  BNE AbortUsingHSC&lt;br /&gt;
&lt;br /&gt;
  LDX #$0F&lt;br /&gt;
CopyArgsToRamLoop&lt;br /&gt;
  LDA HscLUTArgumentBlock-1,X&lt;br /&gt;
  STA $24FF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyArgsToRamLoop&lt;br /&gt;
&lt;br /&gt;
  LDX #$28&lt;br /&gt;
CopyLogoDls&lt;br /&gt;
  LDA HscGameLogoDisplayLists-1,X&lt;br /&gt;
  STA $18B3,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyLogoDls&lt;br /&gt;
&lt;br /&gt;
  LDA #$01&lt;br /&gt;
  STA NMIModeFlag&lt;br /&gt;
  JSR SetDemoPalette&lt;br /&gt;
&lt;br /&gt;
; update the DL text string for current player...&lt;br /&gt;
  LDA Temp62&lt;br /&gt;
  TAX&lt;br /&gt;
  ASL&lt;br /&gt;
  ASL&lt;br /&gt;
  ORA CurrentPlayer&lt;br /&gt;
  STA $2502&lt;br /&gt;
&lt;br /&gt;
; ...and update the DL text string for the difficulty name...&lt;br /&gt;
  LDA DifficultyTextLo,X&lt;br /&gt;
  STA $2506&lt;br /&gt;
  LDA DifficultyTextHi,X&lt;br /&gt;
  STA $2507&lt;br /&gt;
&lt;br /&gt;
  LDA CurrentPlayer&lt;br /&gt;
  BEQ CopyP0ScoreToHscRam&lt;br /&gt;
&lt;br /&gt;
CopyP1ScoreToHscRam&lt;br /&gt;
  LDA #$00&lt;br /&gt;
  STA $27AF&lt;br /&gt;
  LDX #$03&lt;br /&gt;
CopyP1ScoreLoop&lt;br /&gt;
  LDA P1Score-1,X&lt;br /&gt;
  STA $27AF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyP1ScoreLoop&lt;br /&gt;
  JMP ReturnFromHSCInit&lt;br /&gt;
&lt;br /&gt;
CopyP0ScoreToHscRam&lt;br /&gt;
  LDX #$03&lt;br /&gt;
CopyP0ScoreLoop&lt;br /&gt;
  LDA P0Score-1,X&lt;br /&gt;
  STA $27AF,X&lt;br /&gt;
  DEX&lt;br /&gt;
  BNE CopyP0ScoreLoop&lt;br /&gt;
ReturnFromHSCInit&lt;br /&gt;
  LDX #$00&lt;br /&gt;
  LDY #$25&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
AbortUsingHSC&lt;br /&gt;
  PLA&lt;br /&gt;
  PLA&lt;br /&gt;
  RTS&lt;br /&gt;
&lt;br /&gt;
HscLUTArgumentBlock  ; we copy this to ram for actual use&lt;br /&gt;
 .byte $8B,$23       ; Joust's HSC Game ID&lt;br /&gt;
 .byte $00           ; Game Difficulty&lt;br /&gt;
 .byte $00           ; Game Controller&lt;br /&gt;
 .byte $00,$00       ; Game Name (Lo,Hi)&lt;br /&gt;
 .byte $C0,$D9       ; Difficulty Name (Lo,Hi)&lt;br /&gt;
 .byte $AF,$27       ; Game Score (Lo,Hi)&lt;br /&gt;
 .byte &amp;lt;HscGameLogoDisplayListList, &amp;gt;HscGameLogoDisplayListList&lt;br /&gt;
 .byte $70,$D9       ; Sound Routine (Lo,Hi)&lt;br /&gt;
 .byte $04           ; HS Display Time&lt;br /&gt;
&lt;br /&gt;
HscGameLogoDisplayListList&lt;br /&gt;
 .byte $8F,$27,$CB&lt;br /&gt;
 .byte $08,$27,$CB&lt;br /&gt;
 .byte $07,$18,$B4&lt;br /&gt;
 .byte $07,$18,$BB&lt;br /&gt;
 .byte $07,$18,$C2&lt;br /&gt;
 .byte $07,$18,$C9&lt;br /&gt;
 .byte $07,$18,$D0&lt;br /&gt;
&lt;br /&gt;
HscGameLogoDisplayLists&lt;br /&gt;
&lt;br /&gt;
 .byte $CD,$40,$C0,$F2,$3C&lt;br /&gt;
 .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
 .byte $DB,$40,$C0,$EF,$30&lt;br /&gt;
 .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
 .byte $DD,$40,$C8,$F1,$30&lt;br /&gt;
 .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
 .byte $EC,$40,$C8,$EF,$2C&lt;br /&gt;
 .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
 .byte $EC,$40,$C0,$EF,$2C&lt;br /&gt;
 .byte $EC,$80,$C0,$FF,$A0&lt;br /&gt;
 .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
              ; &amp;quot;BEGINNER&amp;quot;&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C0&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C1&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C2&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C3&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C4&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C5&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C6&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C7&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9C8&lt;br /&gt;
  WATKINS &amp;quot;B&amp;quot;  ; $D9C9&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9CA&lt;br /&gt;
  WATKINS &amp;quot;G&amp;quot;  ; $D9CB&lt;br /&gt;
  WATKINS &amp;quot;I&amp;quot;  ; $D9CC&lt;br /&gt;
  WATKINS &amp;quot;N&amp;quot;  ; $D9CD&lt;br /&gt;
  WATKINS &amp;quot;N&amp;quot;  ; $D9CE&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9CF&lt;br /&gt;
  WATKINS &amp;quot;R&amp;quot;  ; $D9D0&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D1&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D2&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D3&lt;br /&gt;
&lt;br /&gt;
              ; &amp;quot;INTERMEDIATE&amp;quot;&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D4&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D5&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D6&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D7&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D8&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9D9&lt;br /&gt;
  WATKINS &amp;quot;I&amp;quot;  ; $D9DA&lt;br /&gt;
  WATKINS &amp;quot;N&amp;quot;  ; $D9DB&lt;br /&gt;
  WATKINS &amp;quot;T&amp;quot;  ; $D9DC&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9DD&lt;br /&gt;
  WATKINS &amp;quot;R&amp;quot;  ; $D9DE&lt;br /&gt;
  WATKINS &amp;quot;M&amp;quot;  ; $D9DF&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9E0&lt;br /&gt;
  WATKINS &amp;quot;D&amp;quot;  ; $D9E1&lt;br /&gt;
  WATKINS &amp;quot;I&amp;quot;  ; $D9E2&lt;br /&gt;
  WATKINS &amp;quot;A&amp;quot;  ; $D9E3&lt;br /&gt;
  WATKINS &amp;quot;T&amp;quot;  ; $D9E4&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9E5&lt;br /&gt;
&lt;br /&gt;
              ; &amp;quot;ADVANCED&amp;quot;&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9E6&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9E7&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9E8&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9E9&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9EA&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9EB&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9EC&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9ED&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9EE&lt;br /&gt;
  WATKINS &amp;quot;A&amp;quot;  ; $D9EF&lt;br /&gt;
  WATKINS &amp;quot;D&amp;quot;  ; $D9F0&lt;br /&gt;
  WATKINS &amp;quot;V&amp;quot;  ; $D9F1&lt;br /&gt;
  WATKINS &amp;quot;A&amp;quot;  ; $D9F2&lt;br /&gt;
  WATKINS &amp;quot;N&amp;quot;  ; $D9F3&lt;br /&gt;
  WATKINS &amp;quot;C&amp;quot;  ; $D9F4&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $D9F5&lt;br /&gt;
  WATKINS &amp;quot;D&amp;quot;  ; $D9F6&lt;br /&gt;
&lt;br /&gt;
              ; &amp;quot;EXPERT&amp;quot;&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9F7&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9F8&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9F9&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FA&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FB&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FC&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FD&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FE&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $D9FF&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA00&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $DA01&lt;br /&gt;
  WATKINS &amp;quot;X&amp;quot;  ; $DA02&lt;br /&gt;
  WATKINS &amp;quot;P&amp;quot;  ; $DA03&lt;br /&gt;
  WATKINS &amp;quot;E&amp;quot;  ; $DA04&lt;br /&gt;
  WATKINS &amp;quot;R&amp;quot;  ; $DA05&lt;br /&gt;
  WATKINS &amp;quot;T&amp;quot;  ; $DA06&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA07&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA08&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA09&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0A&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0B&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0C&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0D&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0E&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA0F&lt;br /&gt;
  WATKINS &amp;quot;^&amp;quot;  ; space $DA10&lt;br /&gt;
&lt;br /&gt;
; pointers to previous HSC/Watkins encoded text strings&lt;br /&gt;
&lt;br /&gt;
DifficultyTextLo&lt;br /&gt;
 .byte $C0  ; BEGINNER text pointer lo&lt;br /&gt;
 .byte $D4  ; INTERMEDIATE text pointer lo&lt;br /&gt;
 .byte $E6  ; ADVANCED text pointer lo&lt;br /&gt;
 .byte $F7  ; EXPERT text pointer lo&lt;br /&gt;
&lt;br /&gt;
DifficultyTextHi&lt;br /&gt;
 .byte $D9  ; BEGINNER text pointer hi&lt;br /&gt;
 .byte $D9  ; INTERMEDIATE text pointer hi&lt;br /&gt;
 .byte $D9  ; ADVANCED text pointer hi&lt;br /&gt;
 .byte $D9  ; EXPERT text pointer hi&lt;br /&gt;
&lt;br /&gt;
TitlePalette&lt;br /&gt;
 .byte $00  ; P0C1&lt;br /&gt;
 .byte $00  ; P0C2&lt;br /&gt;
 .byte $00  ; P0C3&lt;br /&gt;
&lt;br /&gt;
 .byte $FA  ; P1C1&lt;br /&gt;
 .byte $FF  ; P1C2&lt;br /&gt;
 .byte $CF  ; P1C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P2C1&lt;br /&gt;
 .byte $0D  ; P2C2&lt;br /&gt;
 .byte $0D  ; P2C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P3C1&lt;br /&gt;
 .byte $0D  ; P3C2&lt;br /&gt;
 .byte $0D  ; P3C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P4C1&lt;br /&gt;
 .byte $0D  ; P4C2&lt;br /&gt;
 .byte $0D  ; P4C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P5C1&lt;br /&gt;
 .byte $0D  ; P5C2&lt;br /&gt;
 .byte $0D  ; P5C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P6C1&lt;br /&gt;
 .byte $0D  ; P6C2&lt;br /&gt;
 .byte $0D  ; P6C3&lt;br /&gt;
&lt;br /&gt;
 .byte $00  ; P7C1&lt;br /&gt;
 .byte $00  ; P7C2&lt;br /&gt;
 .byte $00  ; P7C3&lt;br /&gt;
&lt;br /&gt;
GamePalette&lt;br /&gt;
 .byte $1A  ; P0C1&lt;br /&gt;
 .byte $10  ; P0C2&lt;br /&gt;
 .byte $14  ; P0C3&lt;br /&gt;
&lt;br /&gt;
 .byte $00  ; P1C1&lt;br /&gt;
 .byte $29  ; P1C2&lt;br /&gt;
 .byte $32  ; P1C3&lt;br /&gt;
&lt;br /&gt;
 .byte $46  ; P2C1&lt;br /&gt;
 .byte $09  ; P2C2&lt;br /&gt;
 .byte $84  ; P2C3&lt;br /&gt;
&lt;br /&gt;
 .byte $1E  ; P3C1&lt;br /&gt;
 .byte $BC  ; P3C2&lt;br /&gt;
 .byte $00  ; P3C3&lt;br /&gt;
&lt;br /&gt;
 .byte $39  ; P4C1&lt;br /&gt;
 .byte $0D  ; P4C2&lt;br /&gt;
 .byte $33  ; P4C3&lt;br /&gt;
&lt;br /&gt;
 .byte $15  ; P5C1&lt;br /&gt;
 .byte $A9  ; P5C2&lt;br /&gt;
 .byte $85  ; P5C3&lt;br /&gt;
&lt;br /&gt;
 .byte $0D  ; P6C1&lt;br /&gt;
 .byte $1C  ; P6C2&lt;br /&gt;
 .byte $44  ; P6C3&lt;br /&gt;
&lt;br /&gt;
 .byte $16  ; P7C1&lt;br /&gt;
 .byte $E3  ; P7C2&lt;br /&gt;
 .byte $E8  ; P7C3&lt;br /&gt;
&lt;br /&gt;
TitleScrCharacterObjectLoLUT&lt;br /&gt;
 .byte &amp;lt;$18FE&lt;br /&gt;
 .byte &amp;lt;$1958&lt;br /&gt;
 .byte &amp;lt;$1C2A&lt;br /&gt;
 .byte &amp;lt;$18FA&lt;br /&gt;
 .byte &amp;lt;$1954&lt;br /&gt;
 .byte &amp;lt;$1950 &lt;br /&gt;
 .byte &amp;lt;$194C &lt;br /&gt;
 .byte &amp;lt;$1C26 &lt;br /&gt;
 .byte &amp;lt;$1C22 &lt;br /&gt;
 .byte &amp;lt;$1C1E &lt;br /&gt;
 .byte &amp;lt;$1D93 &lt;br /&gt;
 .byte &amp;lt;$1DED &lt;br /&gt;
 .byte &amp;lt;$1E48 &lt;br /&gt;
&lt;br /&gt;
TitleScrCharacterObjectHiLUT&lt;br /&gt;
 .byte &amp;gt;$18FE &lt;br /&gt;
 .byte &amp;gt;$1958 &lt;br /&gt;
 .byte &amp;gt;$1C2A &lt;br /&gt;
 .byte &amp;gt;$18FA &lt;br /&gt;
 .byte &amp;gt;$1954 &lt;br /&gt;
 .byte &amp;gt;$1950 &lt;br /&gt;
 .byte &amp;gt;$194C &lt;br /&gt;
 .byte &amp;gt;$1C26 &lt;br /&gt;
 .byte &amp;gt;$1C22 &lt;br /&gt;
 .byte &amp;gt;$1C1E &lt;br /&gt;
 .byte &amp;gt;$1D93 &lt;br /&gt;
 .byte &amp;gt;$1DED &lt;br /&gt;
 .byte &amp;gt;$1E48 &lt;br /&gt;
&lt;br /&gt;
TitleScrSpriteObjectLoLUT&lt;br /&gt;
 .byte &amp;lt;$C05E &lt;br /&gt;
 .byte &amp;lt;$C067 &lt;br /&gt;
 .byte &amp;lt;$C082 &lt;br /&gt;
 .byte &amp;lt;$C064 &lt;br /&gt;
 .byte &amp;lt;$C068 &lt;br /&gt;
 .byte &amp;lt;$C072 &lt;br /&gt;
 .byte &amp;lt;$C07C &lt;br /&gt;
 .byte &amp;lt;$C08B &lt;br /&gt;
 .byte &amp;lt;$C095 &lt;br /&gt;
 .byte &amp;lt;$C09F &lt;br /&gt;
 .byte &amp;lt;$C0A5 &lt;br /&gt;
 .byte &amp;lt;$C0B2 &lt;br /&gt;
 .byte &amp;lt;$C0BF &lt;br /&gt;
&lt;br /&gt;
TitleScrSpriteObjectHiLUT&lt;br /&gt;
 .byte &amp;gt;$C05E &lt;br /&gt;
 .byte &amp;gt;$C067 &lt;br /&gt;
 .byte &amp;gt;$C082 &lt;br /&gt;
 .byte &amp;gt;$C064 &lt;br /&gt;
 .byte &amp;gt;$C068 &lt;br /&gt;
 .byte &amp;gt;$C072 &lt;br /&gt;
 .byte &amp;gt;$C07C &lt;br /&gt;
 .byte &amp;gt;$C08B &lt;br /&gt;
 .byte &amp;gt;$C095 &lt;br /&gt;
 .byte &amp;gt;$C09F &lt;br /&gt;
 .byte &amp;gt;$C0A5 &lt;br /&gt;
 .byte &amp;gt;$C0B2 &lt;br /&gt;
 .byte &amp;gt;$C0BF &lt;br /&gt;
&lt;br /&gt;
TitleScrDLAddrLoLUT&lt;br /&gt;
 .byte &amp;lt;$1EA1, &amp;lt;$1F55, &amp;lt;$1EFB, &amp;lt;$1FC1, &amp;lt;$1FC6, &amp;lt;$184E, &amp;lt;$1853, &amp;lt;$1FD7 &lt;br /&gt;
 .byte &amp;lt;$1FDC, &amp;lt;$18AD, &amp;lt;$18A8, &amp;lt;$1907, &amp;lt;$1902, &amp;lt;$1961, &amp;lt;$195C, &amp;lt;$19BB &lt;br /&gt;
 .byte &amp;lt;$19B6, &amp;lt;$1A16, &amp;lt;$1A11, &amp;lt;$1A70, &amp;lt;$1A6B, &amp;lt;$1ACA, &amp;lt;$1AC5, &amp;lt;$1B25&lt;br /&gt;
 .byte &amp;lt;$1B20, &amp;lt;$1B7F, &amp;lt;$1B7A, &amp;lt;$1BD9, &amp;lt;$1BD4, &amp;lt;$1C33, &amp;lt;$1C2E, &amp;lt;$1C8D&lt;br /&gt;
 .byte &amp;lt;$1C88, &amp;lt;$1CE7, &amp;lt;$1CE2, &amp;lt;$1D42, &amp;lt;$1D3D, &amp;lt;$1D9C, &amp;lt;$1D97, &amp;lt;$1DF6&lt;br /&gt;
 .byte &amp;lt;$1DF1, &amp;lt;$1E51, &amp;lt;$1E4C, &amp;lt;$1EAB, &amp;lt;$1EA6, &amp;lt;$1F05, &amp;lt;$1F00, &amp;lt;$1F5F&lt;br /&gt;
 .byte &amp;lt;$1F5A, &amp;lt;$1FBA, &amp;lt;$1FB5, &amp;lt;$1FCB, &amp;lt;$1FD0, &amp;lt;$19B1, &amp;lt;$19AC, &amp;lt;$19A7&lt;br /&gt;
 .byte &amp;lt;$19A2, &amp;lt;$1A0C, &amp;lt;$1A07, &amp;lt;$1A02, &amp;lt;$19FD, &amp;lt;$1A66, &amp;lt;$1A61, &amp;lt;$1A5C &lt;br /&gt;
 .byte &amp;lt;$1A57, &amp;lt;$1AC0, &amp;lt;$1ABB, &amp;lt;$1AB6, &amp;lt;$1AB1, &amp;lt;$1B1B, &amp;lt;$1B16, &amp;lt;$1B11&lt;br /&gt;
 .byte &amp;lt;$1B0C, &amp;lt;$1B75, &amp;lt;$1B70, &amp;lt;$1B6B, &amp;lt;$1B66, &amp;lt;$1BCF, &amp;lt;$1BCA, &amp;lt;$1BC5&lt;br /&gt;
 .byte &amp;lt;$1BC0 &lt;br /&gt;
&lt;br /&gt;
TitleScrDLAddrHiLUT&lt;br /&gt;
 .byte &amp;gt;$1EA1, &amp;gt;$1F55, &amp;gt;$1EFB, &amp;gt;$1FC1, &amp;gt;$1FC6, &amp;gt;$184E, &amp;gt;$1853, &amp;gt;$1FD7 &lt;br /&gt;
 .byte &amp;gt;$1FDC, &amp;gt;$18AD, &amp;gt;$18A8, &amp;gt;$1907, &amp;gt;$1902, &amp;gt;$1961, &amp;gt;$195C, &amp;gt;$19BB &lt;br /&gt;
 .byte &amp;gt;$19B6, &amp;gt;$1A16, &amp;gt;$1A11, &amp;gt;$1A70, &amp;gt;$1A6B, &amp;gt;$1ACA, &amp;gt;$1AC5, &amp;gt;$1B25&lt;br /&gt;
 .byte &amp;gt;$1B20, &amp;gt;$1B7F, &amp;gt;$1B7A, &amp;gt;$1BD9, &amp;gt;$1BD4, &amp;gt;$1C33, &amp;gt;$1C2E, &amp;gt;$1C8D&lt;br /&gt;
 .byte &amp;gt;$1C88, &amp;gt;$1CE7, &amp;gt;$1CE2, &amp;gt;$1D42, &amp;gt;$1D3D, &amp;gt;$1D9C, &amp;gt;$1D97, &amp;gt;$1DF6&lt;br /&gt;
 .byte &amp;gt;$1DF1, &amp;gt;$1E51, &amp;gt;$1E4C, &amp;gt;$1EAB, &amp;gt;$1EA6, &amp;gt;$1F05, &amp;gt;$1F00, &amp;gt;$1F5F&lt;br /&gt;
 .byte &amp;gt;$1F5A, &amp;gt;$1FBA, &amp;gt;$1FB5, &amp;gt;$1FCB, &amp;gt;$1FD0, &amp;gt;$19B1, &amp;gt;$19AC, &amp;gt;$19A7&lt;br /&gt;
 .byte &amp;gt;$19A2, &amp;gt;$1A0C, &amp;gt;$1A07, &amp;gt;$1A02, &amp;gt;$19FD, &amp;gt;$1A66, &amp;gt;$1A61, &amp;gt;$1A5C &lt;br /&gt;
 .byte &amp;gt;$1A57, &amp;gt;$1AC0, &amp;gt;$1ABB, &amp;gt;$1AB6, &amp;gt;$1AB1, &amp;gt;$1B1B, &amp;gt;$1B16, &amp;gt;$1B11&lt;br /&gt;
 .byte &amp;gt;$1B0C, &amp;gt;$1B75, &amp;gt;$1B70, &amp;gt;$1B6B, &amp;gt;$1B66, &amp;gt;$1BCF, &amp;gt;$1BCA, &amp;gt;$1BC5&lt;br /&gt;
 .byte &amp;gt;$1BC0 &lt;br /&gt;
&lt;br /&gt;
TitleScrCharObject_LoAddress&lt;br /&gt;
 .byte &amp;lt;$2685, &amp;lt;$2699, &amp;lt;$26AD, &amp;lt;$2244, &amp;lt;$2251, &amp;lt;$2204, &amp;lt;$2204, &amp;lt;$2204&lt;br /&gt;
 .byte &amp;lt;$2204, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200&lt;br /&gt;
 .byte &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200&lt;br /&gt;
 .byte &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200&lt;br /&gt;
 .byte &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200&lt;br /&gt;
 .byte &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200&lt;br /&gt;
 .byte &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2200, &amp;lt;$2202, &amp;lt;$2261, &amp;lt;$2268, &amp;lt;$2272&lt;br /&gt;
 .byte &amp;lt;$227C, &amp;lt;$2281, &amp;lt;$2289, &amp;lt;$2293, &amp;lt;$229D, &amp;lt;$22A3, &amp;lt;$22AB, &amp;lt;$22B5&lt;br /&gt;
 .byte &amp;lt;$22BF, &amp;lt;$22C3, &amp;lt;$22C9, &amp;lt;$22D3, &amp;lt;$22DD, &amp;lt;$22DF, &amp;lt;$22E9, &amp;lt;$22F3&lt;br /&gt;
 .byte &amp;lt;$22FD, &amp;lt;$2302, &amp;lt;$230C, &amp;lt;$2316, &amp;lt;$2320, &amp;lt;$2325, &amp;lt;$232F, &amp;lt;$2339&lt;br /&gt;
 .byte &amp;lt;$2343&lt;br /&gt;
&lt;br /&gt;
TitleScrCharObject_HiAddress&lt;br /&gt;
 .byte &amp;gt;$2685, &amp;gt;$2699, &amp;gt;$26AD, &amp;gt;$2244, &amp;gt;$2251, &amp;gt;$2204, &amp;gt;$2204, &amp;gt;$2204&lt;br /&gt;
 .byte &amp;gt;$2204, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200&lt;br /&gt;
 .byte &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200&lt;br /&gt;
 .byte &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200&lt;br /&gt;
 .byte &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200&lt;br /&gt;
 .byte &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200&lt;br /&gt;
 .byte &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2200, &amp;gt;$2202, &amp;gt;$2261, &amp;gt;$2268, &amp;gt;$2272&lt;br /&gt;
 .byte &amp;gt;$227C, &amp;gt;$2281, &amp;gt;$2289, &amp;gt;$2293, &amp;gt;$229D, &amp;gt;$22A3, &amp;gt;$22AB, &amp;gt;$22B5&lt;br /&gt;
 .byte &amp;gt;$22BF, &amp;gt;$22C3, &amp;gt;$22C9, &amp;gt;$22D3, &amp;gt;$22DD, &amp;gt;$22DF, &amp;gt;$22E9, &amp;gt;$22F3&lt;br /&gt;
 .byte &amp;gt;$22FD, &amp;gt;$2302, &amp;gt;$230C, &amp;gt;$2316, &amp;gt;$2320, &amp;gt;$2325, &amp;gt;$232F, &amp;gt;$2339&lt;br /&gt;
 .byte &amp;gt;$2343&lt;br /&gt;
&lt;br /&gt;
TitleScrCharObject_PalleteWidth&lt;br /&gt;
 .byte $90, $90, $90, $93, $90, $00, $08, $00&lt;br /&gt;
 .byte $08, $1E, $1E, $1E, $1E, $1E, $1E, $1E&lt;br /&gt;
 .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E&lt;br /&gt;
 .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E&lt;br /&gt;
 .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E&lt;br /&gt;
 .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E&lt;br /&gt;
 .byte $1E, $1E, $1E, $1E, $1E, $F9, $F6, $F6&lt;br /&gt;
 .byte $FB, $F8, $F6, $F6, $FA, $F8, $F6, $F6&lt;br /&gt;
 .byte $FC, $FA, $F6, $F6, $FE, $F6, $F6, $F6&lt;br /&gt;
 .byte $FB, $F6, $F6, $F6, $FB, $F6, $F6, $F6&lt;br /&gt;
 .byte $FB&lt;br /&gt;
&lt;br /&gt;
TitleScrCharObject_XCoordinate&lt;br /&gt;
 .byte $A0, $A0, $A0, $10, $50, $00, $80, $00&lt;br /&gt;
 .byte $80, $00, $9A, $00, $9A, $00, $9A, $00&lt;br /&gt;
 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00&lt;br /&gt;
 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00&lt;br /&gt;
 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00&lt;br /&gt;
 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00&lt;br /&gt;
 .byte $9A, $00, $9A, $00, $9A, $17, $31, $57&lt;br /&gt;
 .byte $7D, $13, $31, $57, $7D, $13, $31, $57&lt;br /&gt;
 .byte $7D, $1B, $31, $57, $7D, $0B, $31, $57&lt;br /&gt;
 .byte $7D, $0B, $31, $57, $7D, $0B, $31, $57&lt;br /&gt;
 .byte $7D&lt;br /&gt;
&lt;br /&gt;
DllLUT&lt;br /&gt;
 .byte $0F,$27,$CB&lt;br /&gt;
 .byte $08,$27,$CB&lt;br /&gt;
 .byte $47,$18,$4E&lt;br /&gt;
 .byte $47,$18,$A8&lt;br /&gt;
 .byte $47,$18,$A8&lt;br /&gt;
 .byte $47,$18,$A8&lt;br /&gt;
 .byte $47,$18,$FA&lt;br /&gt;
 .byte $47,$19,$4C&lt;br /&gt;
 .byte $47,$19,$A2&lt;br /&gt;
 .byte $47,$19,$FD&lt;br /&gt;
 .byte $47,$1A,$57&lt;br /&gt;
 .byte $47,$1A,$B1&lt;br /&gt;
 .byte $47,$1B,$0C&lt;br /&gt;
 .byte $47,$1B,$66&lt;br /&gt;
 .byte $47,$1B,$C0&lt;br /&gt;
 .byte $47,$1C,$1E&lt;br /&gt;
 .byte $47,$1D,$3D&lt;br /&gt;
 .byte $47,$1D,$93&lt;br /&gt;
 .byte $47,$1D,$ED&lt;br /&gt;
 .byte $47,$1E,$48&lt;br /&gt;
 .byte $47,$1E,$A1&lt;br /&gt;
 .byte $47,$1E,$FB&lt;br /&gt;
 .byte $47,$1F,$55&lt;br /&gt;
 .byte $47,$1F,$B5&lt;br /&gt;
 .byte $47,$1F,$C1&lt;br /&gt;
 .byte $47,$1F,$D7&lt;br /&gt;
 .byte $0F,$27,$CB&lt;br /&gt;
 .byte $06,$27,$CB&lt;br /&gt;
 .byte $8F,$27,$CB&lt;br /&gt;
&lt;br /&gt;
GameDLStartLutLo&lt;br /&gt;
 .byte &amp;lt;$1A17, &amp;lt;$1A13, &amp;lt;$1A6D, &amp;lt;$1A71, &amp;lt;$1C30, &amp;lt;$1C34, &amp;lt;$1C8E, &amp;lt;$1C82 &lt;br /&gt;
 .byte &amp;lt;$1C86, &amp;lt;$1C8A, &amp;lt;$1D43, &amp;lt;$1F58, &amp;lt;$1F54, &amp;lt;$1F5C, &amp;lt;$1F60, &amp;lt;$1F50&lt;br /&gt;
 .byte &amp;lt;$1F4C, &amp;lt;$1FAE, &amp;lt;$1FAA, &amp;lt;$1FB6, &amp;lt;$1FB2, &amp;lt;$1FA6, &amp;lt;$1FA2, &amp;lt;$1FC1&lt;br /&gt;
 .byte &amp;lt;$1FC5, &amp;lt;$1FD1, &amp;lt;$1FC9, &amp;lt;$1FCD, &amp;lt;$1FD7, &amp;lt;$1FDB, &amp;lt;$1FE7, &amp;lt;$1FDF&lt;br /&gt;
 .byte &amp;lt;$1FE3&lt;br /&gt;
&lt;br /&gt;
GameDLStartLutHi&lt;br /&gt;
 .byte &amp;gt;$1A17, &amp;gt;$1A13, &amp;gt;$1A6D, &amp;gt;$1A71, &amp;gt;$1C30, &amp;gt;$1C34, &amp;gt;$1C8E, &amp;gt;$1C82 &lt;br /&gt;
 .byte &amp;gt;$1C86, &amp;gt;$1C8A, &amp;gt;$1D43, &amp;gt;$1F58, &amp;gt;$1F54, &amp;gt;$1F5C, &amp;gt;$1F60, &amp;gt;$1F50&lt;br /&gt;
 .byte &amp;gt;$1F4C, &amp;gt;$1FAE, &amp;gt;$1FAA, &amp;gt;$1FB6, &amp;gt;$1FB2, &amp;gt;$1FA6, &amp;gt;$1FA2, &amp;gt;$1FC1&lt;br /&gt;
 .byte &amp;gt;$1FC5, &amp;gt;$1FD1, &amp;gt;$1FC9, &amp;gt;$1FCD, &amp;gt;$1FD7, &amp;gt;$1FDB, &amp;gt;$1FE7, &amp;gt;$1FDF&lt;br /&gt;
 .byte &amp;gt;$1FE3&lt;br /&gt;
&lt;br /&gt;
BackgroundSpriteGfxLoLUT&lt;br /&gt;
 .byte &amp;lt;$A8A4, &amp;lt;$A0FB, &amp;lt;$A8AA, &amp;lt;$A8BA, &amp;lt;$A897, &amp;lt;$A8BA, &amp;lt;$A8A0, &amp;lt;$C008 &lt;br /&gt;
 .byte &amp;lt;$C011, &amp;lt;$A8BA, &amp;lt;$C017, &amp;lt;$C000, &amp;lt;$C000, &amp;lt;$A08E, &amp;lt;$A8BA, &amp;lt;$C020 &lt;br /&gt;
 .byte &amp;lt;$C020, &amp;lt;$AF8E, &amp;lt;$AF8E, &amp;lt;$A0A9, &amp;lt;$A8BE, &amp;lt;$C03C, &amp;lt;$C03C, &amp;lt;$AF8E &lt;br /&gt;
 .byte &amp;lt;$AF8E, &amp;lt;$A0C4, &amp;lt;$A8C0, &amp;lt;$A8C2, &amp;lt;$AF8E, &amp;lt;$AF8E, &amp;lt;$A0DE, &amp;lt;$A8C0 &lt;br /&gt;
 .byte &amp;lt;$A8C2 &lt;br /&gt;
&lt;br /&gt;
BackgroundSpriteGfxHiLUT&lt;br /&gt;
 .byte &amp;gt;$A8A4, &amp;gt;$A0FB, &amp;gt;$A8AA, &amp;gt;$A8BA, &amp;gt;$A897, &amp;gt;$A8BA, &amp;gt;$A8A0, &amp;gt;$C008 &lt;br /&gt;
 .byte &amp;gt;$C011, &amp;gt;$A8BA, &amp;gt;$C017, &amp;gt;$C000, &amp;gt;$C000, &amp;gt;$A08E, &amp;gt;$A8BA, &amp;gt;$C020 &lt;br /&gt;
 .byte &amp;gt;$C020, &amp;gt;$AF8E, &amp;gt;$AF8E, &amp;gt;$A0A9, &amp;gt;$A8BE, &amp;gt;$C03C, &amp;gt;$C03C, &amp;gt;$AF8E &lt;br /&gt;
 .byte &amp;gt;$AF8E, &amp;gt;$A0C4, &amp;gt;$A8C0, &amp;gt;$A8C2, &amp;gt;$AF8E, &amp;gt;$AF8E, &amp;gt;$A0DE, &amp;gt;$A8C0 &lt;br /&gt;
 .byte &amp;gt;$A8C2 &lt;br /&gt;
&lt;br /&gt;
BackgroundSpritePaletteWidthLUT&lt;br /&gt;
 .byte $1A, $1B, $14, $5C, $17, $5C, $1C, $17 &lt;br /&gt;
 .byte $1A, $5C, $17, $18, $18, $05, $5C, $3E &lt;br /&gt;
 .byte $3E, $37, $37, $05, $3F, $3E, $3E, $37&lt;br /&gt;
 .byte $37, $06, $3F, $3F, $37, $37, $03, $3F&lt;br /&gt;
 .byte $3F &lt;br /&gt;
&lt;br /&gt;
BackgroundSpriteXCoordLUT&lt;br /&gt;
 .byte $88, $00, $2E, $38, $6D, $7A, $7C, $00&lt;br /&gt;
 .byte $8B, $05, $37, $FD, $82, $19, $3B, $F7&lt;br /&gt;
 .byte $A2, $A0, $A0, $1B, $B0, $F7, $A2, $A0&lt;br /&gt;
 .byte $A0, $1B, $B0, $B0, $F9, $84, $15, $B0&lt;br /&gt;
 .byte $B0&lt;br /&gt;
&lt;br /&gt;
HUDCharDLAddrLoLUT&lt;br /&gt;
 .byte &amp;lt;$19BB &lt;br /&gt;
 .byte &amp;lt;$1ACA &lt;br /&gt;
 .byte &amp;lt;$1B7F &lt;br /&gt;
 .byte &amp;lt;$1DF6 &lt;br /&gt;
 .byte &amp;lt;$1FBA &lt;br /&gt;
 .byte &amp;lt;$1FEB &lt;br /&gt;
&lt;br /&gt;
HUDCharDLAddrHiLUT&lt;br /&gt;
 .byte &amp;gt;$19BB &lt;br /&gt;
 .byte &amp;gt;$1ACA &lt;br /&gt;
 .byte &amp;gt;$1B7F &lt;br /&gt;
 .byte &amp;gt;$1DF6 &lt;br /&gt;
 .byte &amp;gt;$1FBA &lt;br /&gt;
 .byte &amp;gt;$1FEB &lt;br /&gt;
&lt;br /&gt;
MsgAndHUDCharObjectStringLoLUT&lt;br /&gt;
 .byte &amp;lt;$2671 &lt;br /&gt;
 .byte &amp;lt;$2685 &lt;br /&gt;
 .byte &amp;lt;$2699 &lt;br /&gt;
 .byte &amp;lt;$26AD &lt;br /&gt;
 .byte &amp;lt;$2659 &lt;br /&gt;
 .byte &amp;lt;$2200 &lt;br /&gt;
&lt;br /&gt;
MsgAndHUDCharObjectStringHiLUT&lt;br /&gt;
 .byte &amp;gt;$2671 &lt;br /&gt;
 .byte &amp;gt;$2685 &lt;br /&gt;
 .byte &amp;gt;$2699 &lt;br /&gt;
 .byte &amp;gt;$26AD &lt;br /&gt;
 .byte &amp;gt;$2659 &lt;br /&gt;
 .byte &amp;gt;$2200 &lt;br /&gt;
&lt;br /&gt;
MsgAndHUDCharObjectPaletteAndWidthLUT&lt;br /&gt;
 .byte $90 &lt;br /&gt;
 .byte $90 &lt;br /&gt;
 .byte $90 &lt;br /&gt;
 .byte $90 &lt;br /&gt;
 .byte $68 &lt;br /&gt;
 .byte $92 &lt;br /&gt;
&lt;br /&gt;
MsgAndHUDCharObjectXLUT&lt;br /&gt;
 .byte $2E &lt;br /&gt;
 .byte $2E &lt;br /&gt;
 .byte $2E &lt;br /&gt;
 .byte $2E &lt;br /&gt;
 .byte $20 &lt;br /&gt;
 .byte $A8 &lt;br /&gt;
&lt;br /&gt;
DisplayListLoLUT&lt;br /&gt;
 .byte &amp;lt;$1858, &amp;lt;$18B2, &amp;lt;$190C, &amp;lt;$1966, &amp;lt;$19BB, &amp;lt;$1A13, &amp;lt;$1A6D, &amp;lt;$1ACA&lt;br /&gt;
 .byte &amp;lt;$1B2A, &amp;lt;$1B7F, &amp;lt;$1BDE, &amp;lt;$1C30, &amp;lt;$1C82, &amp;lt;$1CEC, &amp;lt;$1D43, &amp;lt;$1DA1&lt;br /&gt;
 .byte &amp;lt;$1DF6, &amp;lt;$1E56, &amp;lt;$1EB0, &amp;lt;$1F0A, &amp;lt;$1F4C, &amp;lt;$1FA2, &amp;lt;$1FC1, &amp;lt;$1FD7 &lt;br /&gt;
DisplayListHiLUT&lt;br /&gt;
 .byte &amp;gt;$1858, &amp;gt;$18B2, &amp;gt;$190C, &amp;gt;$1966, &amp;gt;$19BB, &amp;gt;$1A13, &amp;gt;$1A6D, &amp;gt;$1ACA&lt;br /&gt;
 .byte &amp;gt;$1B2A, &amp;gt;$1B7F, &amp;gt;$1BDE, &amp;gt;$1C30, &amp;gt;$1C82, &amp;gt;$1CEC, &amp;gt;$1D43, &amp;gt;$1DA1&lt;br /&gt;
 .byte &amp;gt;$1DF6, &amp;gt;$1E56, &amp;gt;$1EB0, &amp;gt;$1F0A, &amp;gt;$1F4C, &amp;gt;$1FA2, &amp;gt;$1FC1, &amp;gt;$1FD7 &lt;br /&gt;
&lt;br /&gt;
ES_LavaSparkleAnimationPtrLoLUT&lt;br /&gt;
 .byte &amp;lt;$1FB2 &lt;br /&gt;
 .byte &amp;lt;$1FC9 &lt;br /&gt;
 .byte &amp;lt;$1FCD &lt;br /&gt;
 .byte &amp;lt;$1FDF &lt;br /&gt;
 .byte &amp;lt;$1FE3 &lt;br /&gt;
ES_LavaSparkleAnimationPtrHiLUT&lt;br /&gt;
 .byte &amp;gt;$1FB2 &lt;br /&gt;
 .byte &amp;gt;$1FC9 &lt;br /&gt;
 .byte &amp;gt;$1FCD &lt;br /&gt;
 .byte &amp;gt;$1FDF &lt;br /&gt;
 .byte &amp;gt;$1FE3 &lt;br /&gt;
&lt;br /&gt;
SpawnPlatformDLObjectLoLUT&lt;br /&gt;
 .byte &amp;lt;$1F60 &lt;br /&gt;
 .byte &amp;lt;$1C8A &lt;br /&gt;
 .byte &amp;lt;$1C34 &lt;br /&gt;
 .byte &amp;lt;$1A71 &lt;br /&gt;
SpawnPlatformDLObjectHiLUT&lt;br /&gt;
 .byte &amp;gt;$1F60 &lt;br /&gt;
 .byte &amp;gt;$1C8A &lt;br /&gt;
 .byte &amp;gt;$1C34&lt;br /&gt;
 .byte &amp;gt;$1A71&lt;br /&gt;
&lt;br /&gt;
SpawnRiderPaletteAndWidthLUT&lt;br /&gt;
 .byte $B6, $BA ; spawning player rider &lt;br /&gt;
 .byte $BA, $BA, $BA, $BA, $BA, $BA, $BA, $BA ; spawning enemy rider&lt;br /&gt;
&lt;br /&gt;
SpawnPlatformPaletteAndWidthLUT&lt;br /&gt;
 .byte $7C, $7C ; spawning platform with player bird on it&lt;br /&gt;
 .byte $9C, $9C, $9C, $9C, $9C, $9C, $9C, $9C ; spawinging platform with enemy birds&lt;br /&gt;
&lt;br /&gt;
SpawnBirdPaletteAndWidthLUT&lt;br /&gt;
 .byte $BE, $DE ; spawning player birds&lt;br /&gt;
 .byte $9E, $9E, $9E, $9E, $9E, $9E, $9E, $9E ; spawning enemy birds&lt;br /&gt;
&lt;br /&gt;
AITimerDistantAggressive_ByType&lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $01 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
AITimerDistantPassive_Or_ApproachAggressive_ByType&lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $02 &lt;br /&gt;
 .byte $03 &lt;br /&gt;
PterryYVelocitySlightUp&lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
AITimerApproachPassive_ByType&lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $04 &lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $FF &lt;br /&gt;
&lt;br /&gt;
AITimerCloseDefensive_ByType&lt;br /&gt;
 .byte $05 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $06 &lt;br /&gt;
 .byte $07 &lt;br /&gt;
PterryYVelocityZero&lt;br /&gt;
 .byte $00 &lt;br /&gt;
&lt;br /&gt;
AITimerEngagePassive_ByType&lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $09 &lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $01 &lt;br /&gt;
&lt;br /&gt;
AITimerMixedEngageAttack_ByType&lt;br /&gt;
 .byte $0A &lt;br /&gt;
 .byte $0B &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0B &lt;br /&gt;
PterryYVelocitySlightDown&lt;br /&gt;
 .byte $01 &lt;br /&gt;
&lt;br /&gt;
AITimerAttackAggressive_ByType&lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $0F &lt;br /&gt;
 .byte $0E &lt;br /&gt;
 .byte $01 &lt;br /&gt;
&lt;br /&gt;
; the below tables are largely involved in enemy vertical velocity calcs&lt;br /&gt;
BirdWeightByTypeLUT&lt;br /&gt;
 .byte $0C,$14,$1E,$26,$00&lt;br /&gt;
BirdFlapLiftFactorLoLUT&lt;br /&gt;
 .byte $80,$00,$5A,$DC,$00&lt;br /&gt;
BirdFlapLiftFactorHiLUT&lt;br /&gt;
 .byte $00,$01,$01,$01,$01&lt;br /&gt;
BirdMaxDownVelocityByTypeLUT&lt;br /&gt;
 .byte $04,$04,$04,$04,$02&lt;br /&gt;
BirdMaxUpVelocityByTypeLUT&lt;br /&gt;
 .byte $FC,$FC,$FC,$FC,$FD&lt;br /&gt;
&lt;br /&gt;
AITimerByBirdTypeAndDifficultyLoLUT&lt;br /&gt;
 .byte $00, $00, $00, $00, $C0, $A0, $80, $40 &lt;br /&gt;
AITimerByBirdTypeAndDifficultyHiLUT&lt;br /&gt;
 .byte $10, $04, $02, $01, $00, $00, $00, $00 &lt;br /&gt;
&lt;br /&gt;
AIModeByBirdTypeAndDifficultyLUT&lt;br /&gt;
 .byte $7F,$05,$04,$03,$7F,$04,$03,$02,$7F,$03,$02,$01&lt;br /&gt;
&lt;br /&gt;
TurnCheckTimerValuesLoLUT&lt;br /&gt;
 .byte $00,$00,$00,$40,$00,$E0,$C0,$A0,$80,$00,$80,$40&lt;br /&gt;
&lt;br /&gt;
TurnCheckTimerValuesHiLUT&lt;br /&gt;
 .byte $10,$03,$02,$01,$01,$00,$00,$00,$02,$02,$01,$01&lt;br /&gt;
&lt;br /&gt;
; 16-bit speed index tables.&lt;br /&gt;
; The fastest left-heading speed is the first value.&lt;br /&gt;
; The neutral non-moving speed is the middle value.&lt;br /&gt;
; The fastest right-heading speed is the last value.&lt;br /&gt;
; These apply to player and enemy birds.&lt;br /&gt;
XPositionIncrementTableLoLUT&lt;br /&gt;
 .byte $20,$D0,$60,$E0,$80,$00,$80,$20,$A0,$30,$E0&lt;br /&gt;
XPositionIncrementTableHiLUT&lt;br /&gt;
 .byte $FD,$FD,$FE,$FE,$FF,$00,$00,$01,$01,$02,$02&lt;br /&gt;
&lt;br /&gt;
BirdAIActionCategoryByProximityLUT&lt;br /&gt;
 .byte $03,$04,$04,$FF,$02,$00,$03,$FF,$01,$01,$02&lt;br /&gt;
&lt;br /&gt;
TrollGrabHeight  ; If a bird object is at this Y the troll will grab it (game level is index)&lt;br /&gt;
 .byte $B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B5,$B5,$B5&lt;br /&gt;
 .byte $BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA&lt;br /&gt;
&lt;br /&gt;
InitialBirdDirection&lt;br /&gt;
 .byte $01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01&lt;br /&gt;
&lt;br /&gt;
PlayerRespawnY&lt;br /&gt;
 .byte $A7,$67,$5F,$37&lt;br /&gt;
PlayerRespawnX&lt;br /&gt;
 .byte $5E,$29,$9D,$5B&lt;br /&gt;
&lt;br /&gt;
ObjectScreenWrapXRightEdgeLUT&lt;br /&gt;
 .byte $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE            ; Birds&lt;br /&gt;
 .byte $C2, $C2, $C2                                               ; Pterrys&lt;br /&gt;
 .byte $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB  ; Eggs&lt;br /&gt;
&lt;br /&gt;
ObjectScreenWrapXLeftEdgeLUT&lt;br /&gt;
 .byte $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A            ; Birds&lt;br /&gt;
 .byte $16, $16, $16                                               ; Pterrys&lt;br /&gt;
 .byte $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F  ; Eggs&lt;br /&gt;
&lt;br /&gt;
; enemy levels are 0:red-bounder, 1:gray-hunter, 2:blue-shadowlord&lt;br /&gt;
; this table says enemy upgrades are 0-&amp;gt;1, 1-&amp;gt;2, and 2-&amp;gt;2.&lt;br /&gt;
NextEnemyBirdLevel&lt;br /&gt;
 .byte $01, $02, $02&lt;br /&gt;
&lt;br /&gt;
PterrySpritePaletteAndWidthLUT&lt;br /&gt;
 .byte $9C &lt;br /&gt;
 .byte $9C &lt;br /&gt;
 .byte $9C &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1C &lt;br /&gt;
 .byte $1C &lt;br /&gt;
&lt;br /&gt;
UNUSED_TitleMenuTextAddrLoLUT&lt;br /&gt;
 .byte &amp;lt;$2671 &lt;br /&gt;
 .byte &amp;lt;$2685 &lt;br /&gt;
 .byte &amp;lt;$2699 &lt;br /&gt;
 .byte &amp;lt;$26AD &lt;br /&gt;
UNUSED_TitleMenuTextAddrHiLUT&lt;br /&gt;
 .byte &amp;gt;$2671 &lt;br /&gt;
 .byte &amp;gt;$2685 &lt;br /&gt;
 .byte &amp;gt;$2699 &lt;br /&gt;
 .byte &amp;gt;$26AD &lt;br /&gt;
UNUSED_TitleMenuDLZoneLUT&lt;br /&gt;
 .byte $03 &lt;br /&gt;
 .byte $08 &lt;br /&gt;
 .byte $0C &lt;br /&gt;
 .byte $10 &lt;br /&gt;
&lt;br /&gt;
; packed 2-bit enemy type data, first set of 4 enemies for each wave...&lt;br /&gt;
EnemyWaveDataLUT_A &lt;br /&gt;
 .byte $3F, $0F, $0F, $03, $03, $00, $00, $00&lt;br /&gt;
 .byte $00, $00, $00, $54, $54, $55, $55, $55&lt;br /&gt;
 .byte $55, $55, $55, $55, $95, $95, $95, $A5&lt;br /&gt;
 .byte $A9, $AA, $AA, $AA, $AA, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA&lt;br /&gt;
 .byte $AA, $AA, $AA, $AA &lt;br /&gt;
&lt;br /&gt;
; packed 2-bit enemy type data, second set of 4 enemies for each wave&lt;br /&gt;
EnemyWaveDataLUT_B &lt;br /&gt;
 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $3F&lt;br /&gt;
 .byte $3F, $0F, $0F, $0F, $0F, $0F, $5F, $5F&lt;br /&gt;
 .byte $03, $43, $57, $55, $5F, $5F, $5F, $5F&lt;br /&gt;
 .byte $5F, $5F, $5F, $5F, $95, $95, $5F, $95&lt;br /&gt;
 .byte $55, $A5, $5F, $A5, $A5, $AA, $AF, $AA&lt;br /&gt;
 .byte $AA, $AA, $AF, $AA, $AA, $AA, $AF, $AA&lt;br /&gt;
 .byte $AA, $AA, $AF, $AA&lt;br /&gt;
&lt;br /&gt;
 .byte &amp;quot;GCC(C)1984&amp;quot; ; not used by the game, just an embedded text&lt;br /&gt;
&lt;br /&gt;
 .byte $4C &lt;br /&gt;
 .byte $00 &lt;br /&gt;
 .byte $B0 &lt;br /&gt;
 .byte $3F &lt;br /&gt;
 .byte $39 &lt;br /&gt;
 .byte $34 &lt;br /&gt;
&lt;br /&gt;
CART_SIGNATURE_DUPE  ; DF80-DFF7&lt;br /&gt;
 .byte $04,$C4,$76,$30,$6A,$8C,$8A,$3A,$CA,$F5,$BC,$71,$CA,$76,$08,$AB&lt;br /&gt;
 .byte $75,$58,$CD,$19,$2A,$29,$2E,$F0,$DB,$7B,$84,$98,$A4,$0E,$0A,$7C&lt;br /&gt;
 .byte $3F,$D8,$93,$8D,$59,$98,$FA,$77,$03,$FF,$E9,$9B,$70,$A8,$B3,$A5&lt;br /&gt;
 .byte $AA,$E7,$7F,$82,$CF,$DD,$5F,$F4,$54,$79,$BA,$D7,$6D,$73,$26,$CE&lt;br /&gt;
 .byte $B3,$06,$39,$94,$BA,$74,$A1,$E7,$8F,$AF,$6C,$B2,$E2,$74,$70,$0B&lt;br /&gt;
 .byte $2E,$68,$F2,$4F,$27,$E2,$AA,$4D,$F7,$B0,$CD,$C6,$9D,$B1,$42,$59&lt;br /&gt;
 .byte $CE,$0D,$59,$14,$13,$8E,$71,$5C,$A0,$09,$4E,$00,$85,$99,$E7,$CA&lt;br /&gt;
 .byte $E4,$A5,$D9,$A1,$2B,$47,$A4,$CE&lt;br /&gt;
&lt;br /&gt;
 .byte $FF  ; region verification. $FF=all regions&lt;br /&gt;
 .byte $E7  ; encryption check starts at $E000 &lt;br /&gt;
&lt;br /&gt;
 .word NMI_ROUTINE&lt;br /&gt;
 .word START&lt;br /&gt;
 .word IRQ_ROUTINE&lt;br /&gt;
&lt;br /&gt;
; This rom is a bit weird, in that the last 2 8k blocks are identical&lt;br /&gt;
; including the cart vectors and encryption key.&lt;br /&gt;
;&lt;br /&gt;
; block 1: the graphics and code are live/used, except for the &lt;br /&gt;
; brief &amp;quot;jmp $B000&amp;quot; located at DF7A. The encryption key, BIOS bytes,&lt;br /&gt;
; and 6502 vectors are dead/unused.&lt;br /&gt;
;&lt;br /&gt;
; block 2: the graphics and code are dead/unused, except for the&lt;br /&gt;
; brief &amp;quot;jmp $B000&amp;quot; located at FF7A. The encryption key, BIOS bytes,&lt;br /&gt;
; and 6502 vectors are (of course) used.&lt;br /&gt;
;&lt;br /&gt;
; I've left the dead parts of block 2 as uninterpreted byte values,&lt;br /&gt;
; to avoid confusion with the active code in block 1.&lt;br /&gt;
;&lt;br /&gt;
; So... Joust has just under 8K unused in block 2, ready and waiting &lt;br /&gt;
; for rom hacks.&lt;br /&gt;
;&lt;br /&gt;
; This is block 2 of 2...&lt;br /&gt;
&lt;br /&gt;
; ORG $E000&lt;br /&gt;
&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $2a,$a0,$2a,$80,$2a,$20,$aa,$00,$a8,$00,$aa,$00,$aa,$00,$aa,$80&lt;br /&gt;
 .byte $aa,$a0,$aa,$a0,$aa,$a0,$aa,$a0,$2a,$a0,$2a,$a0,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$11,$48,$22,$8c,$33,$c8,$aa,$aa&lt;br /&gt;
 .byte $ea,$54,$00,$10,$6a,$aa,$a8,$a0,$aa,$aa,$95,$56,$ab,$7a,$a9,$57&lt;br /&gt;
 .byte $00,$d0,$6a,$aa,$a5,$5a,$aa,$aa,$aa,$a0,$00,$00,$00,$15,$55,$56&lt;br /&gt;
 .byte $aa,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$03,$00,$33,$00,$c0,$33,$00,$c0,$0c,$c0,$cc&lt;br /&gt;
 .byte $30,$00,$00,$c0,$00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$0c,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$a0,$0a,$aa,$56&lt;br /&gt;
 .byte $9a,$90,$36,$a9,$6a,$aa,$80,$00,$55,$aa,$00,$09,$7a,$a6,$a5,$fe&lt;br /&gt;
 .byte $a5,$a9,$54,$d6,$a5,$aa,$bd,$66,$56,$ab,$70,$00,$00,$00,$a0,$00&lt;br /&gt;
 .byte $02,$a0,$00,$00,$a8,$02,$aa,$02,$a0,$00,$00,$aa,$00,$44,$f0,$81&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$eb,$cf,$ff,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$0f,$cf,$00,$00,$00,$00,$ff,$a0,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $2a,$80,$2a,$80,$2a,$00,$aa,$00,$aa,$00,$aa,$00,$aa,$00,$aa,$80&lt;br /&gt;
 .byte $aa,$80,$aa,$a0,$aa,$a0,$aa,$80,$aa,$a0,$2a,$a0,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$04,$48,$08,$8c,$0c,$c8,$2a,$aa&lt;br /&gt;
 .byte $aa,$94,$00,$10,$aa,$aa,$a8,$a0,$aa,$aa,$95,$56,$ab,$fe,$a9,$57&lt;br /&gt;
 .byte $00,$d0,$6a,$aa,$a5,$56,$aa,$aa,$aa,$a0,$00,$00,$00,$00,$55,$55&lt;br /&gt;
 .byte $aa,$80,$00,$00,$2a,$ab,$f4,$00,$00,$00,$00,$aa,$80,$00,$00,$00&lt;br /&gt;
 .byte $00,$2a,$aa,$a8,$00,$5a,$aa,$a0,$00,$00,$00,$00,$00,$00,$00,$0a&lt;br /&gt;
 .byte $aa,$a0,$00,$00,$00,$03,$30,$0c,$00,$c0,$0c,$00,$c0,$0f,$00,$cc&lt;br /&gt;
 .byte $30,$00,$00,$30,$00,$00,$00,$00,$03,$ff,$ff,$ff,$ff,$ff,$f0,$0f&lt;br /&gt;
 .byte $fc,$03,$f3,$c3,$cf,$00,$00,$fc,$03,$00,$f0,$28,$28,$02,$a9,$5a&lt;br /&gt;
 .byte $9e,$90,$36,$a9,$5a,$aa,$40,$00,$01,$5a,$a0,$0a,$fa,$a6,$a5,$fa&lt;br /&gt;
 .byte $a5,$6a,$54,$d6,$a6,$aa,$d7,$a6,$a5,$ab,$fa,$80,$00,$0a,$ab,$c0&lt;br /&gt;
 .byte $0a,$a9,$00,$02,$aa,$86,$aa,$0a,$a8,$00,$7a,$aa,$b0,$0c,$f0,$63&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$fa,$bf,$ff,$ea,$be,$f3,$ff,$c0&lt;br /&gt;
 .byte $00,$00,$00,$ea,$fb,$ea,$ff,$00,$03,$fa,$bf,$fa,$80,$00,$00,$00&lt;br /&gt;
 .byte $0a,$80,$0a,$80,$2a,$80,$2a,$80,$2a,$80,$aa,$80,$aa,$80,$aa,$80&lt;br /&gt;
 .byte $2a,$80,$aa,$80,$2a,$80,$aa,$80,$aa,$80,$aa,$80,$aa,$a8,$af,$a8&lt;br /&gt;
 .byte $ae,$a8,$aa,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$aa,$a8,$aa,$a8&lt;br /&gt;
 .byte $aa,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$04,$48,$08,$8c,$0c,$c8,$0a,$aa&lt;br /&gt;
 .byte $aa,$94,$00,$10,$aa,$aa,$a8,$20,$aa,$aa,$55,$4a,$aa,$7e,$a9,$57&lt;br /&gt;
 .byte $00,$d0,$6a,$aa,$a5,$56,$aa,$aa,$aa,$80,$00,$00,$00,$00,$05,$55&lt;br /&gt;
 .byte $6a,$a0,$00,$00,$aa,$aa,$bf,$d0,$00,$00,$a0,$aa,$ab,$40,$00,$00&lt;br /&gt;
 .byte $00,$aa,$aa,$aa,$30,$5a,$aa,$a0,$01,$56,$a8,$00,$00,$00,$70,$aa&lt;br /&gt;
 .byte $aa,$aa,$b0,$00,$00,$03,$0c,$00,$00,$c0,$00,$03,$00,$0c,$c0,$cf&lt;br /&gt;
 .byte $f0,$00,$00,$0f,$fc,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$00,$30&lt;br /&gt;
 .byte $03,$0c,$0c,$3c,$30,$c0,$f3,$03,$03,$03,$0c,$80,$08,$00,$55,$4a&lt;br /&gt;
 .byte $ae,$90,$06,$aa,$16,$a9,$00,$00,$00,$00,$00,$0a,$ba,$a5,$a9,$da&lt;br /&gt;
 .byte $a5,$6a,$54,$d6,$a6,$aa,$fd,$a6,$aa,$aa,$aa,$00,$00,$2a,$aa,$7f&lt;br /&gt;
 .byte $2a,$aa,$f0,$02,$aa,$a6,$aa,$6a,$aa,$3f,$6a,$aa,$a0,$00,$12,$91&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$ff,$aa,$aa,$ba,$ab,$fa,$ee,$a0&lt;br /&gt;
 .byte $00,$00,$02,$aa,$ab,$ff,$ff,$00,$3f,$eb,$ff,$ab,$fa,$c0,$00,$00&lt;br /&gt;
 .byte $0a,$80,$0a,$80,$0a,$80,$0a,$80,$2a,$80,$2a,$80,$2a,$80,$2a,$80&lt;br /&gt;
 .byte $2a,$80,$2a,$80,$2a,$80,$2a,$80,$2a,$80,$aa,$80,$bb,$a8,$ba,$a8&lt;br /&gt;
 .byte $ae,$e8,$ba,$ab,$be,$a8,$ba,$a0,$3b,$a8,$3a,$a8,$be,$a8,$3a,$a8&lt;br /&gt;
 .byte $ba,$a8,$3b,$e8,$3a,$e8,$3a,$a8,$45,$48,$8a,$8c,$cf,$c8,$02,$aa&lt;br /&gt;
 .byte $aa,$94,$00,$10,$aa,$a8,$00,$20,$aa,$a9,$54,$0a,$aa,$be,$a9,$57&lt;br /&gt;
 .byte $00,$d0,$6a,$aa,$a8,$55,$aa,$aa,$aa,$00,$00,$00,$00,$00,$00,$05&lt;br /&gt;
 .byte $52,$a8,$00,$0a,$aa,$aa,$af,$fd,$40,$00,$a0,$aa,$aa,$f4,$00,$00&lt;br /&gt;
 .byte $02,$aa,$aa,$aa,$90,$5a,$aa,$a0,$15,$aa,$aa,$a0,$00,$07,$e0,$aa&lt;br /&gt;
 .byte $aa,$aa,$a8,$00,$00,$00,$c3,$00,$00,$c0,$00,$0c,$00,$0c,$30,$00&lt;br /&gt;
 .byte $30,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$c0&lt;br /&gt;
 .byte $03,$0c,$0c,$0c,$c0,$33,$0f,$03,$03,$03,$03,$00,$00,$00,$00,$0a&lt;br /&gt;
 .byte $a6,$90,$06,$aa,$00,$00,$00,$00,$00,$00,$00,$0a,$aa,$a5,$a9,$5a&lt;br /&gt;
 .byte $95,$6a,$50,$d6,$a6,$aa,$76,$a6,$aa,$aa,$a8,$00,$00,$aa,$aa,$5d&lt;br /&gt;
 .byte $ea,$aa,$ff,$0a,$aa,$aa,$a9,$aa,$aa,$bf,$aa,$aa,$a8,$00,$12,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$fe,$ff,$ff,$ff,$ff,$ea,$ba,$a8&lt;br /&gt;
 .byte $00,$00,$0e,$ee,$af,$ff,$ff,$00,$af,$ef,$ee,$bf,$fa,$af,$c0,$00&lt;br /&gt;
 .byte $0a,$80,$0a,$80,$0a,$80,$0a,$80,$0a,$80,$0a,$80,$2a,$00,$2a,$80&lt;br /&gt;
 .byte $2a,$80,$2a,$80,$2a,$80,$2a,$00,$2a,$20,$2a,$80,$ae,$a8,$ae,$a0&lt;br /&gt;
 .byte $aa,$a0,$ab,$a0,$af,$a0,$af,$a0,$af,$a0,$2e,$a8,$2f,$a8,$ab,$b8&lt;br /&gt;
 .byte $2b,$a8,$2f,$e8,$ae,$a8,$2b,$a8,$15,$48,$2a,$8c,$3f,$c8,$00,$2a&lt;br /&gt;
 .byte $aa,$a4,$00,$00,$aa,$00,$00,$00,$2a,$95,$00,$0a,$aa,$bf,$a9,$57&lt;br /&gt;
 .byte $00,$10,$6a,$aa,$a8,$05,$aa,$aa,$a8,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$2a,$aa,$aa,$a9,$5f,$fc,$02,$a0,$aa,$aa,$7f,$c0,$00&lt;br /&gt;
 .byte $02,$aa,$aa,$aa,$a0,$5a,$aa,$81,$5a,$aa,$aa,$aa,$0f,$ff,$60,$aa&lt;br /&gt;
 .byte $aa,$aa,$aa,$80,$00,$30,$03,$00,$3f,$ff,$ff,$f0,$00,$0c,$00,$00&lt;br /&gt;
 .byte $30,$00,$00,$0f,$c0,$fc,$03,$c0,$fc,$00,$15,$55,$55,$54,$00,$c0&lt;br /&gt;
 .byte $ff,$0c,$0c,$0f,$00,$0c,$03,$03,$03,$03,$03,$00,$00,$00,$00,$02&lt;br /&gt;
 .byte $ab,$94,$06,$aa,$00,$00,$00,$00,$00,$00,$00,$00,$aa,$a9,$aa,$aa&lt;br /&gt;
 .byte $95,$6a,$50,$d6,$aa,$aa,$ba,$a6,$aa,$aa,$a0,$00,$02,$aa,$aa,$97&lt;br /&gt;
 .byte $aa,$aa,$9d,$fa,$aa,$aa,$a9,$aa,$aa,$b5,$aa,$aa,$aa,$0b,$b0,$38&lt;br /&gt;
 .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$fd,$55,$55,$57,$aa,$ea,$ab&lt;br /&gt;
 .byte $c0,$00,$ff,$ef,$ab,$bf,$ff,$03,$eb,$fa,$bf,$ff,$eb,$ff,$ff,$a8&lt;br /&gt;
 .byte $2a,$00,$8a,$00,$0a,$00,$02,$80,$02,$a0,$0a,$a0,$0a,$80,$0a,$80&lt;br /&gt;
 .byte $2a,$00,$2a,$00,$2a,$00,$2a,$20,$2a,$00,$2a,$00,$bb,$a0,$ab,$a0&lt;br /&gt;
 .byte $ab,$a0,$ae,$80,$ae,$80,$ae,$80,$ab,$a0,$ae,$a0,$af,$eb,$af,$a8&lt;br /&gt;
 .byte $2f,$e8,$ab,$a8,$ab,$e8,$ab,$e8,$05,$50,$0a,$a0,$0f,$f0,$00,$0a&lt;br /&gt;
 .byte $aa,$a8,$00,$00,$80,$00,$00,$00,$00,$00,$00,$2a,$aa,$af,$aa,$57&lt;br /&gt;
 .byte $00,$10,$6a,$aa,$a8,$00,$02,$aa,$80,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$aa,$aa,$aa,$aa,$55,$ff,$ca,$a0,$aa,$aa,$97,$fd,$00&lt;br /&gt;
 .byte $0a,$aa,$aa,$aa,$a0,$5a,$aa,$85,$6a,$aa,$aa,$aa,$bf,$fd,$60,$aa&lt;br /&gt;
 .byte $aa,$aa,$aa,$a0,$00,$30,$03,$00,$00,$c0,$00,$00,$00,$0c,$00,$c0&lt;br /&gt;
 .byte $30,$00,$00,$30,$33,$03,$0c,$33,$03,$00,$aa,$aa,$aa,$aa,$00,$c0&lt;br /&gt;
 .byte $00,$03,$f0,$0c,$00,$0c,$00,$fc,$fc,$fc,$03,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $2a,$a4,$0a,$aa,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$a9,$6a,$aa&lt;br /&gt;
 .byte $95,$da,$50,$36,$a9,$aa,$aa,$a6,$aa,$aa,$80,$00,$02,$aa,$aa,$9f&lt;br /&gt;
 .byte $aa,$aa,$b7,$ea,$aa,$aa,$ad,$aa,$aa,$a6,$aa,$aa,$aa,$3d,$f2,$fe&lt;br /&gt;
 .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$55,$75,$55,$55,$55,$d5,$af,$ff&lt;br /&gt;
 .byte $fc,$03,$ff,$ff,$ea,$bf,$ff,$ff,$fa,$ff,$ff,$ff,$bf,$ff,$ff,$af&lt;br /&gt;
 .byte $28,$00,$28,$00,$08,$00,$02,$80,$02,$a0,$02,$a0,$02,$a0,$0a,$a0&lt;br /&gt;
 .byte $28,$a0,$28,$20,$aa,$00,$28,$20,$28,$28,$a8,$80,$aa,$a0,$ae,$a0&lt;br /&gt;
 .byte $ae,$80,$aa,$80,$aa,$00,$aa,$00,$aa,$80,$ab,$a0,$af,$a0,$aa,$e0&lt;br /&gt;
 .byte $ab,$a0,$2b,$a0,$ab,$a0,$ae,$a0,$01,$08,$02,$0c,$03,$08,$00,$00&lt;br /&gt;
 .byte $aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$aa,$a7,$aa,$57&lt;br /&gt;
 .byte $00,$10,$6a,$aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$aa,$aa,$aa,$aa,$57,$f7,$ea,$a0,$aa,$aa,$ad,$ff,$f0&lt;br /&gt;
 .byte $0a,$aa,$aa,$aa,$a0,$9a,$aa,$b5,$aa,$aa,$aa,$aa,$af,$fd,$a0,$aa&lt;br /&gt;
 .byte $aa,$aa,$aa,$a8,$00,$0c,$0c,$00,$00,$00,$00,$00,$00,$cc,$00,$00&lt;br /&gt;
 .byte $33,$00,$00,$c0,$0c,$00,$f0,$0c,$00,$c0,$00,$00,$00,$00,$00,$c0&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$03,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $0a,$a4,$0a,$80,$00,$00,$00,$00,$00,$00,$00,$00,$02,$a9,$6a,$aa&lt;br /&gt;
 .byte $96,$da,$50,$36,$a9,$aa,$aa,$a1,$5a,$aa,$a0,$00,$0a,$aa,$aa,$95&lt;br /&gt;
 .byte $aa,$aa,$95,$ea,$aa,$aa,$ad,$aa,$aa,$ae,$aa,$aa,$aa,$2a,$a0,$89&lt;br /&gt;
 .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$55,$d5,$55,$55,$55,$75,$55,$55&lt;br /&gt;
 .byte $55,$15,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55&lt;br /&gt;
 .byte $88,$00,$08,$00,$08,$00,$00,$00,$00,$20,$00,$20,$00,$20,$00,$88&lt;br /&gt;
 .byte $02,$00,$28,$80,$a0,$00,$00,$00,$22,$08,$a0,$20,$aa,$a0,$aa,$a0&lt;br /&gt;
 .byte $aa,$80,$ae,$00,$ae,$00,$ba,$00,$aa,$00,$aa,$80,$aa,$a0,$aa,$a0&lt;br /&gt;
 .byte $aa,$80,$2a,$a0,$2a,$a0,$aa,$80,$05,$08,$0a,$0c,$0f,$08,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$aa,$ab,$ea,$54&lt;br /&gt;
 .byte $00,$10,$6a,$aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$02,$aa,$aa,$aa,$aa,$95,$77,$ea,$a0,$aa,$aa,$a5,$df,$ff&lt;br /&gt;
 .byte $2a,$aa,$aa,$aa,$a0,$aa,$aa,$95,$aa,$aa,$aa,$aa,$af,$75,$a0,$aa&lt;br /&gt;
 .byte $aa,$aa,$aa,$aa,$00,$03,$f0,$00,$00,$00,$00,$00,$03,$00,$00,$00&lt;br /&gt;
 .byte $00,$c0,$03,$00,$33,$00,$c0,$33,$00,$c0,$0c,$30,$cf,$f0,$00,$c0&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$03,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$a8,$08,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$2a,$2a,$aa&lt;br /&gt;
 .byte $56,$da,$50,$36,$a9,$6a,$aa,$a0,$05,$56,$a8,$00,$2a,$aa,$aa,$a6&lt;br /&gt;
 .byte $aa,$6a,$af,$ea,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$a5,$6a,$2e,$a1,$d0&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $aa,$aa,$6a,$5a,$96,$a5,$a9,$aa,$90,$a0,$a0,$a0,$a0,$a0,$60,$50&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$0a,$97,$7f,$ea,$aa,$aa,$a7,$5d&lt;br /&gt;
 .byte $7f,$ea,$95,$aa,$af,$75,$aa,$aa,$aa,$02,$aa,$aa,$aa,$95,$aa,$aa&lt;br /&gt;
 .byte $55,$55,$aa,$95,$57,$0f,$50,$9a,$aa,$9d,$aa,$5a,$a0,$aa,$aa,$aa&lt;br /&gt;
 .byte $a8,$00,$02,$95,$7f,$a9,$5a,$50,$7f,$fe,$95,$5a,$55,$5f,$3f,$56&lt;br /&gt;
 .byte $aa,$bf,$d7,$5a,$50,$56,$aa,$af,$d5,$40,$00,$00,$00,$00,$6a,$a9&lt;br /&gt;
 .byte $70,$5d,$ff,$a5,$6a,$5f,$fd,$ab,$f5,$56,$aa,$a9,$5d,$55,$aa,$a8&lt;br /&gt;
 .byte $00,$00,$55,$a9,$50,$55,$57,$a5,$57,$5d,$50,$6a,$a9,$55,$dd,$55&lt;br /&gt;
 .byte $5a,$a9,$60,$a0,$02,$aa,$95,$55,$a5,$95,$55,$55,$a0,$ab,$55,$aa&lt;br /&gt;
 .byte $95,$d5,$6a,$aa,$96,$95,$55,$55,$56,$2a,$aa,$a5,$9a,$a0,$5a,$95&lt;br /&gt;
 .byte $fe,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$aa,$05,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$a9,$55,$56,$a5,$f5,$6a,$a5,$6a,$80,$2a,$a9,$ea,$a6&lt;br /&gt;
 .byte $a9,$5a,$a7,$ea,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$95,$5a,$00,$e0,$85&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$10&lt;br /&gt;
 .byte $aa,$6a,$5a,$96,$a5,$a9,$aa,$aa,$a0,$a0,$a0,$a0,$a0,$60,$50,$90&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$0a,$a5,$5f,$aa,$aa,$aa,$a9,$dd&lt;br /&gt;
 .byte $df,$aa,$95,$aa,$a9,$d6,$aa,$aa,$aa,$00,$2a,$aa,$aa,$95,$aa,$a9&lt;br /&gt;
 .byte $55,$57,$aa,$95,$57,$03,$d0,$96,$aa,$aa,$aa,$5a,$a0,$aa,$aa,$aa&lt;br /&gt;
 .byte $a8,$00,$02,$a7,$5f,$a9,$5a,$70,$fd,$de,$95,$5a,$55,$5f,$3f,$5a&lt;br /&gt;
 .byte $aa,$75,$75,$6a,$a0,$55,$aa,$ab,$dd,$55,$40,$00,$00,$00,$6a,$a9&lt;br /&gt;
 .byte $70,$5d,$7f,$a5,$6a,$5f,$fd,$ab,$f7,$56,$aa,$a5,$d5,$d5,$aa,$a8&lt;br /&gt;
 .byte $00,$00,$00,$a9,$50,$d5,$75,$a5,$57,$fd,$50,$6a,$a9,$7d,$d7,$55&lt;br /&gt;
 .byte $6a,$a5,$60,$a0,$02,$aa,$95,$55,$a5,$95,$55,$55,$60,$ab,$55,$aa&lt;br /&gt;
 .byte $75,$55,$6a,$aa,$56,$95,$55,$40,$00,$aa,$aa,$55,$56,$90,$5a,$95&lt;br /&gt;
 .byte $7a,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$6a,$00,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$a9,$55,$56,$af,$55,$6a,$95,$6a,$80,$aa,$a5,$7a,$a6&lt;br /&gt;
 .byte $a9,$5a,$a5,$aa,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$95,$5a,$00,$b0,$01&lt;br /&gt;
 .byte $00,$54,$54,$54,$54,$04,$54,$54,$10,$54,$04,$00,$a8,$a8,$a8,$a8&lt;br /&gt;
 .byte $08,$a8,$a8,$20,$a8,$08,$00,$88,$a0,$28,$a0,$a8,$a8,$88,$a8,$20&lt;br /&gt;
 .byte $a8,$88,$88,$80,$88,$a8,$20,$a8,$20,$88,$88,$20,$a8,$88,$41,$04&lt;br /&gt;
 .byte $6a,$5a,$96,$a5,$a9,$aa,$aa,$aa,$a0,$a0,$a0,$a0,$60,$50,$90,$a0&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$2a,$a5,$df,$aa,$aa,$aa,$a9,$d5&lt;br /&gt;
 .byte $dd,$aa,$d5,$aa,$ab,$56,$aa,$aa,$aa,$00,$02,$aa,$aa,$95,$6a,$a9&lt;br /&gt;
 .byte $55,$57,$6a,$a5,$57,$03,$d0,$96,$aa,$aa,$aa,$5a,$a0,$aa,$aa,$aa&lt;br /&gt;
 .byte $a8,$00,$02,$a9,$df,$aa,$5a,$50,$5f,$da,$95,$56,$95,$5f,$3f,$5a&lt;br /&gt;
 .byte $ab,$d7,$5d,$aa,$a0,$95,$6a,$ab,$ff,$fd,$80,$00,$00,$01,$6a,$a9&lt;br /&gt;
 .byte $50,$7f,$7f,$a5,$5a,$7f,$cf,$aa,$d5,$5a,$aa,$ad,$55,$55,$aa,$aa&lt;br /&gt;
 .byte $40,$00,$00,$ab,$50,$57,$57,$a5,$df,$fd,$50,$6a,$ab,$ff,$75,$55&lt;br /&gt;
 .byte $6a,$a7,$60,$a0,$00,$aa,$55,$55,$a5,$95,$55,$55,$60,$ab,$d5,$aa&lt;br /&gt;
 .byte $57,$55,$aa,$aa,$56,$95,$00,$00,$00,$aa,$a9,$55,$56,$90,$5a,$95&lt;br /&gt;
 .byte $7a,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$6a,$00,$0a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$a9,$55,$56,$af,$d5,$aa,$b5,$6a,$80,$2a,$95,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$aa,$aa,$aa,$a5,$aa,$5a,$aa,$aa,$55,$56,$80,$30,$eb&lt;br /&gt;
 .byte $00,$44,$10,$40,$04,$04,$04,$44,$10,$44,$04,$54,$88,$20,$80,$08&lt;br /&gt;
 .byte $08,$08,$88,$20,$88,$08,$a8,$a8,$88,$80,$88,$80,$88,$88,$20,$88&lt;br /&gt;
 .byte $80,$88,$a8,$80,$a0,$08,$20,$88,$20,$a8,$88,$20,$80,$88,$44,$04&lt;br /&gt;
 .byte $5a,$96,$a5,$a9,$aa,$aa,$aa,$6a,$a0,$a0,$a0,$60,$50,$90,$a0,$a0&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$aa,$a5,$57,$aa,$aa,$aa,$aa,$77&lt;br /&gt;
 .byte $5d,$aa,$d5,$aa,$aa,$da,$aa,$aa,$aa,$00,$00,$aa,$aa,$95,$6a,$a9&lt;br /&gt;
 .byte $55,$77,$6a,$a5,$57,$03,$d0,$96,$aa,$aa,$aa,$55,$50,$aa,$aa,$5a&lt;br /&gt;
 .byte $aa,$00,$02,$aa,$77,$aa,$56,$90,$f5,$da,$95,$56,$95,$5f,$3f,$5a&lt;br /&gt;
 .byte $ab,$75,$d5,$aa,$a0,$aa,$aa,$aa,$fe,$aa,$80,$00,$00,$05,$6a,$aa&lt;br /&gt;
 .byte $50,$7f,$fe,$a5,$5a,$5f,$fd,$aa,$d5,$6a,$aa,$97,$5d,$55,$aa,$aa&lt;br /&gt;
 .byte $00,$00,$00,$a9,$50,$5d,$77,$a5,$5f,$fd,$d0,$6a,$ab,$ff,$57,$55&lt;br /&gt;
 .byte $aa,$95,$60,$a0,$00,$aa,$55,$55,$a5,$95,$55,$55,$60,$ab,$55,$a9&lt;br /&gt;
 .byte $d5,$55,$aa,$aa,$56,$90,$00,$00,$00,$aa,$a9,$55,$55,$90,$5a,$95&lt;br /&gt;
 .byte $5a,$aa,$aa,$aa,$ab,$d5,$6a,$aa,$a6,$aa,$9a,$95,$6a,$00,$0a,$a6&lt;br /&gt;
 .byte $a5,$5e,$a5,$a9,$55,$56,$ad,$d6,$aa,$55,$6a,$80,$2a,$95,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$aa,$95,$aa,$a5,$a9,$56,$aa,$aa,$55,$56,$80,$a2,$14&lt;br /&gt;
 .byte $00,$44,$10,$54,$14,$54,$54,$54,$10,$54,$54,$54,$88,$20,$a8,$28&lt;br /&gt;
 .byte $a8,$a8,$a8,$20,$a8,$a8,$a8,$88,$a0,$80,$88,$a0,$88,$a8,$20,$08&lt;br /&gt;
 .byte $80,$88,$a8,$a8,$a8,$20,$20,$88,$88,$88,$20,$20,$20,$a0,$44,$04&lt;br /&gt;
 .byte $96,$a5,$a9,$aa,$aa,$aa,$6a,$5a,$a0,$a0,$60,$50,$90,$a0,$a0,$a0&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$02,$aa,$a5,$76,$aa,$aa,$aa,$aa,$75&lt;br /&gt;
 .byte $7d,$aa,$d5,$6a,$aa,$da,$aa,$aa,$aa,$00,$00,$0a,$aa,$a5,$6a,$a9&lt;br /&gt;
 .byte $55,$9f,$6a,$a5,$57,$03,$d0,$95,$aa,$aa,$aa,$03,$50,$55,$55,$56&lt;br /&gt;
 .byte $aa,$00,$02,$aa,$9e,$aa,$56,$90,$5f,$5a,$55,$56,$95,$5f,$0f,$5a&lt;br /&gt;
 .byte $ab,$dd,$d6,$aa,$a0,$aa,$aa,$aa,$aa,$aa,$00,$00,$00,$57,$6a,$aa&lt;br /&gt;
 .byte $70,$77,$5e,$a5,$5a,$5c,$fd,$aa,$d5,$6a,$aa,$75,$55,$55,$6a,$aa&lt;br /&gt;
 .byte $40,$00,$00,$a9,$50,$d5,$f7,$a5,$5f,$cd,$50,$6a,$ab,$ff,$f5,$56&lt;br /&gt;
 .byte $aa,$9d,$60,$a0,$00,$2a,$55,$55,$a5,$55,$55,$d5,$50,$ab,$55,$a9&lt;br /&gt;
 .byte $75,$55,$aa,$a9,$56,$80,$00,$00,$00,$2a,$a5,$55,$55,$50,$56,$95&lt;br /&gt;
 .byte $5a,$aa,$aa,$aa,$ab,$55,$6a,$aa,$55,$aa,$9a,$95,$5a,$00,$0a,$a6&lt;br /&gt;
 .byte $a5,$7e,$a5,$a9,$55,$56,$ad,$5a,$aa,$75,$5a,$80,$0a,$95,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$aa,$55,$6a,$a5,$a9,$d6,$aa,$aa,$55,$56,$a8,$04,$06&lt;br /&gt;
 .byte $00,$44,$50,$04,$04,$44,$40,$40,$04,$44,$44,$f4,$88,$a0,$08,$08&lt;br /&gt;
 .byte $88,$80,$80,$08,$88,$88,$f8,$88,$88,$80,$88,$80,$80,$88,$20,$08&lt;br /&gt;
 .byte $80,$a8,$a8,$88,$88,$80,$20,$88,$88,$88,$88,$88,$08,$a0,$44,$04&lt;br /&gt;
 .byte $a5,$a9,$aa,$aa,$aa,$6a,$5a,$96,$a0,$60,$50,$90,$a0,$a0,$a0,$a0&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$0a,$aa,$a9,$56,$aa,$aa,$aa,$aa,$55&lt;br /&gt;
 .byte $de,$aa,$d5,$6a,$aa,$da,$aa,$95,$5a,$00,$00,$00,$aa,$a5,$4a,$a9&lt;br /&gt;
 .byte $56,$9f,$7a,$a5,$57,$00,$d0,$95,$aa,$aa,$aa,$00,$10,$55,$55,$55&lt;br /&gt;
 .byte $aa,$80,$02,$aa,$aa,$aa,$56,$a0,$77,$6a,$55,$56,$95,$5f,$0f,$fa&lt;br /&gt;
 .byte $ab,$77,$5a,$aa,$a0,$aa,$aa,$aa,$aa,$a0,$00,$00,$05,$7f,$6a,$aa&lt;br /&gt;
 .byte $70,$75,$de,$a5,$5a,$5f,$fd,$aa,$d5,$aa,$a9,$f7,$75,$55,$6a,$aa&lt;br /&gt;
 .byte $94,$00,$00,$a9,$50,$5d,$77,$a5,$5f,$fd,$50,$6a,$ab,$f7,$55,$5a&lt;br /&gt;
 .byte $aa,$95,$50,$a0,$00,$2a,$55,$55,$a5,$55,$55,$55,$50,$ab,$d5,$a7&lt;br /&gt;
 .byte $55,$56,$aa,$a9,$55,$80,$00,$00,$00,$2a,$a5,$55,$55,$50,$56,$a5&lt;br /&gt;
 .byte $5a,$aa,$96,$aa,$ab,$55,$6a,$a9,$d5,$6a,$9a,$95,$5a,$00,$0a,$a6&lt;br /&gt;
 .byte $a5,$7e,$a5,$a9,$55,$56,$ad,$6a,$ab,$55,$5a,$a0,$0a,$55,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$aa,$55,$5a,$ad,$a5,$5a,$a9,$aa,$55,$00,$80,$f9,$5f&lt;br /&gt;
 .byte $00,$54,$10,$54,$54,$44,$54,$54,$54,$54,$54,$54,$a8,$20,$a8,$a8&lt;br /&gt;
 .byte $88,$a8,$a8,$a8,$a8,$a8,$a8,$20,$a0,$28,$a0,$a8,$a8,$88,$a8,$08&lt;br /&gt;
 .byte $80,$88,$88,$a8,$a8,$a8,$a8,$88,$88,$88,$88,$88,$a8,$88,$41,$04&lt;br /&gt;
 .byte $a9,$aa,$aa,$aa,$6a,$5a,$96,$a5,$60,$50,$90,$a0,$a0,$a0,$a0,$a0&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$0a,$aa,$a9,$56,$aa,$95,$aa,$aa,$5d&lt;br /&gt;
 .byte $de,$aa,$d5,$6a,$aa,$9a,$aa,$55,$56,$00,$00,$00,$0a,$a9,$0a,$a5&lt;br /&gt;
 .byte $56,$af,$7a,$a5,$57,$00,$d0,$a5,$6a,$aa,$a8,$00,$00,$55,$55,$55&lt;br /&gt;
 .byte $6a,$a0,$02,$aa,$aa,$aa,$56,$a0,$77,$6a,$55,$55,$95,$57,$0f,$5a&lt;br /&gt;
 .byte $ab,$5f,$5a,$aa,$a0,$aa,$aa,$aa,$aa,$80,$00,$00,$55,$5f,$5a,$aa&lt;br /&gt;
 .byte $70,$5f,$fe,$a5,$5a,$5f,$cd,$aa,$55,$aa,$a9,$f7,$d6,$55,$5a,$aa&lt;br /&gt;
 .byte $b5,$00,$00,$a9,$70,$55,$ff,$a5,$7c,$ff,$50,$5a,$ab,$f5,$d5,$6a&lt;br /&gt;
 .byte $aa,$75,$50,$ab,$00,$09,$55,$57,$a5,$55,$57,$55,$50,$ab,$55,$ad&lt;br /&gt;
 .byte $55,$56,$aa,$a9,$55,$80,$00,$00,$00,$0a,$95,$55,$55,$50,$56,$a5&lt;br /&gt;
 .byte $6a,$a9,$55,$5a,$ab,$55,$aa,$a5,$55,$6a,$9a,$95,$5a,$00,$5a,$a6&lt;br /&gt;
 .byte $a5,$fe,$a5,$a9,$55,$56,$ad,$6a,$a5,$55,$5a,$a0,$02,$55,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$a9,$55,$5a,$a5,$a5,$5a,$a5,$aa,$50,$00,$a8,$10,$90&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$10&lt;br /&gt;
 .byte $aa,$aa,$aa,$6a,$5a,$96,$a5,$a9,$50,$90,$a0,$a0,$a0,$a0,$a0,$60&lt;br /&gt;
 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$2a,$aa,$a9,$76,$aa,$55,$6a,$aa,$95&lt;br /&gt;
 .byte $7e,$aa,$d5,$6a,$aa,$9a,$a9,$55,$55,$00,$00,$00,$00,$a8,$02,$a5&lt;br /&gt;
 .byte $56,$af,$7a,$a5,$57,$00,$d0,$a5,$6a,$aa,$a8,$00,$00,$05,$55,$55&lt;br /&gt;
 .byte $5a,$a8,$00,$2a,$aa,$aa,$55,$a0,$9d,$aa,$55,$55,$95,$57,$0f,$9a&lt;br /&gt;
 .byte $aa,$77,$6a,$aa,$a0,$aa,$aa,$aa,$aa,$00,$00,$02,$55,$df,$5a,$aa&lt;br /&gt;
 .byte $50,$f7,$7e,$95,$5a,$5f,$3f,$aa,$56,$aa,$ad,$dd,$da,$59,$56,$aa&lt;br /&gt;
 .byte $ad,$50,$00,$a9,$50,$75,$df,$a5,$5f,$fd,$50,$5a,$ab,$fd,$55,$aa&lt;br /&gt;
 .byte $aa,$55,$50,$a8,$00,$00,$00,$77,$a5,$55,$75,$75,$50,$ab,$d5,$95&lt;br /&gt;
 .byte $d5,$5a,$aa,$a9,$55,$80,$00,$00,$00,$0a,$95,$55,$55,$50,$56,$a5&lt;br /&gt;
 .byte $6a,$a5,$55,$55,$ab,$55,$aa,$9d,$55,$6a,$96,$95,$56,$05,$7a,$a6&lt;br /&gt;
 .byte $a5,$fe,$a5,$a9,$57,$d6,$a5,$aa,$ad,$d5,$56,$ad,$02,$55,$5a,$a6&lt;br /&gt;
 .byte $a5,$56,$a5,$a9,$55,$5a,$a5,$b5,$5a,$a5,$aa,$00,$00,$00,$d0,$28&lt;br /&gt;
 .byte $a5,$79,$c9,$35,$d0,$02,$e6,$7a,$4c,$3d,$d0,$a9,$01,$85,$4a,$d0&lt;br /&gt;
 .byte $0d,$a9,$00,$85,$4a,$a5,$7a,$d0,$05,$e6,$79,$4c,$3d,$d0,$a9,$00&lt;br /&gt;
 .byte $85,$79,$85,$7a,$f0,$17,$ad,$82,$02,$29,$02,$f0,$06,$a9,$00,$85&lt;br /&gt;
 .byte $55,$10,$10,$c6,$55,$10,$0c,$20,$5a,$d0,$20,$65,$d0,$20,$5f,$d0&lt;br /&gt;
 .byte $20,$7a,$d0,$a5,$4d,$c5,$56,$d0,$03,$4c,$a0,$b0,$a5,$4e,$c5,$4e&lt;br /&gt;
 .byte $f0,$fc,$4c,$a3,$9f,$a9,$20,$85,$54,$60,$a9,$20,$85,$55,$60,$a6&lt;br /&gt;
 .byte $4d,$ca,$86,$56,$60,$e6,$4c,$a5,$4c,$c9,$04,$30,$0a,$a9,$00,$85&lt;br /&gt;
 .byte $4c,$a5,$4a,$49,$01,$85,$4a,$4c,$e9,$b4,$a6,$4a,$bd,$aa,$d2,$8d&lt;br /&gt;
 .byte $a5,$1e,$bd,$ab,$d2,$8d,$59,$1f,$a5,$4c,$aa,$0a,$0a,$0a,$0a,$18&lt;br /&gt;
 .byte $69,$b1,$85,$5e,$a9,$00,$69,$d2,$85,$5f,$a0,$0f,$b1,$5e,$99,$ad&lt;br /&gt;
 .byte $26,$88,$10,$f8,$bd,$ad,$d2,$8d,$ff,$1e,$a5,$7a,$c9,$29,$d0,$16&lt;br /&gt;
 .byte $a5,$4e,$29,$03,$c9,$03,$d0,$0e,$ce,$96,$1d,$ce,$f0,$1d,$ce,$4b&lt;br /&gt;
 .byte $1e,$a9,$01,$8d,$ce,$27,$60,$a5,$52,$10,$0e,$a5,$58,$d0,$0d,$ad&lt;br /&gt;
 .byte $82,$02,$4a,$b0,$f1,$a9,$01,$85,$58,$4c,$94,$b0,$4c,$98,$d2,$a5&lt;br /&gt;
 .byte $52,$10,$f6,$ad,$80,$02,$c9,$f0,$b0,$21,$4c,$9a,$b0,$a5,$4b,$d0&lt;br /&gt;
 .byte $ee,$a5,$57,$d0,$0d,$ad,$82,$02,$29,$08,$d0,$0f,$a9,$01,$85,$57&lt;br /&gt;
 .byte $d0,$38,$ad,$82,$02,$29,$08,$49,$08,$85,$57,$a5,$58,$d0,$0c,$ad&lt;br /&gt;
 .byte $82,$02,$4a,$b0,$09,$a9,$01,$85,$58,$d0,$be,$20,$98,$d2,$a5,$59&lt;br /&gt;
 .byte $d0,$0e,$ad,$82,$02,$29,$02,$d0,$10,$a9,$01,$85,$59,$4c,$9a,$b0&lt;br /&gt;
 .byte $ad,$82,$02,$29,$02,$49,$02,$85,$59,$60,$a5,$4d,$48,$a5,$4e,$48&lt;br /&gt;
 .byte $8a,$48,$a2,$01,$86,$4b,$ca,$86,$19,$86,$1a,$a6,$4d,$ca,$20,$0b&lt;br /&gt;
 .byte $d1,$e4,$4d,$d0,$04,$a9,$60,$85,$3c,$ad,$80,$02,$c9,$f0,$b0,$03&lt;br /&gt;
 .byte $20,$a2,$d2,$a5,$52,$30,$03,$20,$a2,$d2,$a5,$57,$f0,$0b,$ad,$82&lt;br /&gt;
 .byte $02,$29,$08,$49,$08,$85,$57,$10,$d5,$ad,$82,$02,$29,$08,$d0,$ce&lt;br /&gt;
 .byte $68,$aa,$68,$85,$4e,$68,$85,$4d,$a9,$01,$85,$57,$4a,$85,$4b,$a9&lt;br /&gt;
 .byte $40,$85,$3c,$60,$a9,$30,$8d,$00,$22,$a9,$38,$8d,$01,$22,$a9,$36&lt;br /&gt;
 .byte $8d,$02,$22,$a9,$3e,$8d,$03,$22,$a2,$1e,$a9,$30,$9d,$04,$22,$a9&lt;br /&gt;
 .byte $34,$9d,$05,$22,$ca,$ca,$10,$f2,$a2,$1c,$86,$70,$bd,$12,$d4,$8d&lt;br /&gt;
 .byte $91,$01,$bd,$f5,$d3,$85,$71,$a2,$1c,$bd,$c5,$98,$9d,$44,$22,$ca&lt;br /&gt;
 .byte $10,$f7,$a2,$e7,$bd,$0d,$d3,$9d,$60,$22,$ca,$d0,$f7,$a2,$0b,$86&lt;br /&gt;
 .byte $72,$bd,$2f,$d4,$8d,$a5,$01,$85,$3d,$bd,$3b,$d4,$8d,$a6,$01,$85&lt;br /&gt;
 .byte $3e,$bd,$47,$d4,$8d,$a7,$01,$85,$3f,$bd,$53,$d4,$85,$73,$60,$c6&lt;br /&gt;
 .byte $71,$10,$15,$c6,$70,$10,$04,$a9,$1c,$85,$70,$a6,$70,$bd,$12,$d4&lt;br /&gt;
 .byte $8d,$91,$01,$bd,$f5,$d3,$85,$71,$ee,$00,$22,$ad,$00,$22,$c9,$38&lt;br /&gt;
 .byte $90,$05,$a9,$30,$8d,$00,$22,$ee,$02,$22,$ad,$02,$22,$c9,$38,$90&lt;br /&gt;
 .byte $05,$a9,$30,$8d,$02,$22,$ee,$01,$22,$ad,$01,$22,$c9,$40,$90,$05&lt;br /&gt;
 .byte $a9,$38,$8d,$01,$22,$ee,$03,$22,$ad,$03,$22,$c9,$40,$90,$05,$a9&lt;br /&gt;
 .byte $38,$8d,$03,$22,$a2,$1f,$fe,$04,$22,$bd,$04,$22,$c9,$38,$90,$05&lt;br /&gt;
 .byte $a9,$30,$9d,$04,$22,$ca,$10,$ee,$a5,$73,$30,$2b,$c6,$73,$10,$27&lt;br /&gt;
 .byte $c6,$72,$10,$04,$a9,$0b,$85,$72,$a6,$72,$bd,$2f,$d4,$8d,$a5,$01&lt;br /&gt;
 .byte $85,$3d,$bd,$3b,$d4,$8d,$a6,$01,$85,$3e,$bd,$47,$d4,$8d,$a7,$01&lt;br /&gt;
 .byte $85,$3f,$bd,$53,$d4,$85,$73,$60,$ad,$82,$02,$29,$01,$49,$01,$85&lt;br /&gt;
 .byte $58,$60,$a9,$40,$85,$3c,$a6,$4d,$ca,$60,$a0,$30,$a0,$00,$20,$45&lt;br /&gt;
 .byte $62,$00,$00,$00,$00,$18,$1b,$1c,$1e,$22,$22,$1b,$24,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$1e,$22,$26,$1b,$24,$21,$1b,$1a,$1e,$17,$26,$1b,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$17,$0c,$28,$17,$22,$19,$1b,$1a,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$00,$00,$00,$1b,$2a,$23,$1b,$24,$26,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$0c,$22,$1b,$00,$23,$20,$17,$2b,$1b,$24,$00,$00,$00,$00,$00&lt;br /&gt;
 .byte $00,$26,$29,$0c,$00,$23,$20,$17,$2b,$1b,$24,$00,$00,$00,$59,$5a&lt;br /&gt;
 .byte $5b,$5c,$5d,$5e,$41,$40,$40,$5f,$60,$61,$62,$63,$64,$65,$66,$43&lt;br /&gt;
 .byte $40,$67,$68,$40,$69,$40,$6a,$6b,$6c,$6d,$6e,$6f,$70,$71,$72,$73&lt;br /&gt;
 .byte $74,$40,$75,$76,$40,$77,$78,$79,$40,$7a,$7b,$40,$7c,$7d,$7e,$46&lt;br /&gt;
 .byte $43,$40,$7f,$40,$80,$81,$82,$83,$43,$84,$85,$86,$87,$88,$89,$8a&lt;br /&gt;
 .byte $8b,$8c,$8d,$40,$42,$8e,$8f,$90,$91,$92,$40,$93,$43,$40,$44,$95&lt;br /&gt;
 .byte $96,$46,$43,$97,$98,$99,$40,$9a,$9b,$9c,$9d,$46,$9e,$9f,$a0,$a1&lt;br /&gt;
 .byte $a2,$40,$42,$45,$a3,$a4,$a5,$a6,$40,$a7,$45,$40,$44,$a8,$a9,$aa&lt;br /&gt;
 .byte $ab,$ac,$ad,$ae,$af,$b0,$40,$b1,$44,$b2,$40,$b3,$b4,$b5,$b6,$44&lt;br /&gt;
 .byte $44,$40,$42,$45,$42,$46,$44,$b7,$40,$b8,$45,$40,$b9,$ba,$bb,$bc&lt;br /&gt;
 .byte $40,$bd,$be,$bf,$c0,$c1,$c2,$c3,$c4,$41,$40,$c5,$c6,$c7,$c8,$c9&lt;br /&gt;
 .byte $40,$ca,$cb,$cc,$40,$42,$43,$40,$cd,$44,$ce,$40,$cf,$d0,$40,$d1&lt;br /&gt;
 .byte $d2,$d3,$41,$40,$d4,$d5,$d6,$d7,$d8,$d9,$40,$da,$41,$40,$db,$44&lt;br /&gt;
 .byte $44,$dc,$47,$48,$40,$40,$40,$40,$49,$4a,$4b,$41,$4c,$4d,$4e,$4f&lt;br /&gt;
 .byte $50,$51,$40,$40,$40,$41,$40,$40,$52,$53,$40,$40,$40,$54,$55,$41&lt;br /&gt;
 .byte $40,$56,$57,$58,$40,$3c,$03,$03,$3c,$03,$03,$03,$03,$03,$3c,$03&lt;br /&gt;
 .byte $03,$03,$03,$03,$03,$3c,$03,$03,$03,$3c,$03,$03,$03,$03,$03,$03&lt;br /&gt;
 .byte $03,$03,$24,$15,$06,$f7,$d6,$c5,$b5,$a5,$95,$85,$76,$67,$58,$49&lt;br /&gt;
 .byte $3a,$2b,$1d,$1c,$1b,$0c,$0d,$0c,$0b,$1a,$19,$28,$27,$26,$25,$33&lt;br /&gt;
 .byte $33,$33,$33,$33,$33,$33,$32,$22,$11,$10,$00,$1f,$1e,$1d,$1c,$1b&lt;br /&gt;
 .byte $1a,$18,$16,$22,$11,$10,$00,$10,$10,$10,$10,$10,$10,$10,$10,$10&lt;br /&gt;
 .byte $10,$10,$00,$ff,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$a9&lt;br /&gt;
 .byte $ff,$85,$6b,$85,$6c,$a9,$00,$85,$19,$85,$1a,$60,$c5,$6b,$d0,$09&lt;br /&gt;
 .byte $a9,$00,$85,$19,$a9,$ff,$85,$6b,$60,$38,$e5,$6c,$d0,$06,$85,$1a&lt;br /&gt;
 .byte $a9,$ff,$85,$6c,$60,$85,$6a,$a5,$95,$d0,$f9,$a5,$4b,$d0,$f5,$98&lt;br /&gt;
 .byte $48,$8a,$48,$a0,$01,$a6,$6a,$b9,$6b,$00,$c9,$ff,$f0,$21,$88,$10&lt;br /&gt;
 .byte $f6,$a5,$6c,$29,$7f,$a8,$bd,$30,$d6,$d9,$30,$d6,$a0,$01,$b0,$0f&lt;br /&gt;
 .byte $a5,$6b,$29,$7f,$a8,$bd,$30,$d6,$d9,$30,$d6,$90,$08,$a0,$00,$8a&lt;br /&gt;
 .byte $09,$80,$99,$6b,$00,$68,$aa,$68,$a8,$60,$a5,$4b,$d0,$fb,$a2,$01&lt;br /&gt;
 .byte $b4,$6b,$c8,$d0,$03,$4c,$a4,$d5,$88,$10,$16,$98,$29,$7f,$95,$6b&lt;br /&gt;
 .byte $a8,$a9,$01,$9d,$00,$21,$a9,$ff,$9d,$02,$21,$9d,$04,$21,$9d,$06&lt;br /&gt;
 .byte $21,$b9,$ab,$d5,$85,$5c,$b9,$0a,$d6,$85,$5d,$de,$00,$21,$d0,$d5&lt;br /&gt;
 .byte $b9,$1d,$d6,$9d,$00,$21,$bc,$02,$21,$fe,$04,$21,$fe,$06,$21,$c8&lt;br /&gt;
 .byte $b1,$5c,$c9,$ff,$d0,$08,$95,$6b,$a9,$00,$95,$19,$f0,$b7,$c9,$fe&lt;br /&gt;
 .byte $f0,$14,$c9,$fd,$d0,$1b,$c8,$b1,$5c,$95,$6b,$a8,$b9,$ab,$d5,$85&lt;br /&gt;
 .byte $5c,$b9,$0a,$d6,$85,$5d,$a0,$00,$98,$9d,$04,$21,$9d,$06,$21,$b1&lt;br /&gt;
 .byte $5c,$10,$0d,$c8,$b1,$5c,$9d,$00,$21,$88,$b1,$5c,$c8,$4c,$6a,$d5&lt;br /&gt;
 .byte $0a,$10,$16,$4a,$29,$bf,$9d,$00,$21,$98,$9d,$02,$21,$de,$06,$21&lt;br /&gt;
 .byte $de,$04,$21,$a9,$00,$95,$19,$f0,$3b,$4a,$95,$17,$98,$9d,$02,$21&lt;br /&gt;
 .byte $b4,$6b,$b9,$be,$d5,$85,$5c,$b9,$f7,$d5,$85,$5d,$bc,$06,$21,$b1&lt;br /&gt;
 .byte $5c,$10,$01,$88,$95,$19,$98,$9d,$06,$21,$b4,$6b,$b9,$d1,$d5,$85&lt;br /&gt;
 .byte $5c,$b9,$e4,$d5,$85,$5d,$bc,$04,$21,$b1,$5c,$10,$01,$88,$95,$15&lt;br /&gt;
 .byte $98,$9d,$04,$21,$ca,$30,$03,$4c,$d0,$d4,$60,$43,$8d,$be,$cd,$76&lt;br /&gt;
 .byte $7c,$9d,$9f,$b5,$d8,$e9,$1a,$31,$47,$50,$65,$86,$9b,$b6,$5e,$a6&lt;br /&gt;
 .byte $c6,$22,$d2,$8d,$d1,$d3,$c7,$e1,$02,$26,$42,$4c,$5b,$d1,$91,$d4&lt;br /&gt;
 .byte $c1,$78,$cc,$ce,$cc,$cc,$cc,$cf,$cb,$cd,$ce,$cd,$cb,$d0,$cb,$cb&lt;br /&gt;
 .byte $cc,$cb,$cc,$cb,$d6,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8&lt;br /&gt;
 .byte $d8,$d8,$d8,$d8,$d8,$d8,$d8,$d6,$d6,$d6,$d7,$d8,$d7,$d8,$d8,$d7&lt;br /&gt;
 .byte $d7,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d6,$d6,$d6,$d6,$d7,$d7&lt;br /&gt;
 .byte $d7,$d7,$d7,$d7,$d7,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$02,$01,$02&lt;br /&gt;
 .byte $01,$01,$01,$01,$04,$02,$04,$07,$02,$04,$02,$0e,$01,$02,$01,$01&lt;br /&gt;
 .byte $00,$09,$05,$09,$02,$04,$02,$08,$04,$05,$05,$00,$03,$04,$06,$03&lt;br /&gt;
 .byte $07,$00,$02,$0b,$0b,$11,$11,$0f,$0f,$17,$17,$00,$00,$00,$00,$0b&lt;br /&gt;
 .byte $0b,$11,$11,$0b,$0b,$11,$11,$0f,$0f,$17,$17,$00,$00,$ff,$04,$00&lt;br /&gt;
 .byte $03,$00,$02,$00,$01,$00,$00,$00,$00,$00,$04,$00,$03,$00,$04,$00&lt;br /&gt;
 .byte $03,$00,$02,$00,$01,$00,$00,$00,$04,$04,$04,$04,$0d,$0d,$0d,$0d&lt;br /&gt;
 .byte $0d,$0d,$0d,$0d,$04,$04,$04,$04,$04,$04,$04,$04,$8d,$0c,$0e,$11&lt;br /&gt;
 .byte $16,$0c,$0e,$11,$16,$0c,$0e,$11,$16,$0c,$0e,$11,$16,$0c,$0e,$11&lt;br /&gt;
 .byte $16,$0c,$0e,$11,$16,$ff,$0b,$0b,$0b,$0b,$09,$09,$09,$09,$07,$07&lt;br /&gt;
 .byte $07,$07,$06,$06,$06,$06,$04,$04,$04,$04,$02,$02,$02,$02,$18,$16&lt;br /&gt;
 .byte $14,$11,$0f,$0d,$0b,$ff,$0b,$0a,$09,$09,$07,$06,$05,$0d,$0c,$0b&lt;br /&gt;
 .byte $0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09&lt;br /&gt;
 .byte $08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07&lt;br /&gt;
 .byte $0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c&lt;br /&gt;
 .byte $0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a&lt;br /&gt;
 .byte $09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08&lt;br /&gt;
 .byte $07,$ff,$0f,$0f,$0a,$09,$07,$06,$05,$0e,$0e,$0a,$09,$07,$06,$05&lt;br /&gt;
 .byte $0c,$0c,$09,$08,$07,$06,$05,$0b,$0b,$09,$08,$07,$06,$05,$0a,$0a&lt;br /&gt;
 .byte $08,$07,$06,$05,$04,$09,$08,$07,$06,$05,$04,$03,$08,$06,$05,$04&lt;br /&gt;
 .byte $03,$02,$02,$07,$06,$05,$04,$03,$02,$02,$06,$05,$04,$03,$03,$02&lt;br /&gt;
 .byte $02,$05,$05,$04,$04,$03,$02,$02,$04,$04,$03,$03,$02,$02,$01,$03&lt;br /&gt;
 .byte $03,$03,$02,$02,$02,$02,$0f,$10,$11,$12,$1f,$ff,$0f,$10,$11,$12&lt;br /&gt;
 .byte $0f,$10,$11,$12,$0f,$10,$11,$12,$0f,$10,$11,$12,$ff,$08,$08,$08&lt;br /&gt;
 .byte $08,$06,$06,$06,$06,$04,$04,$04,$04,$02,$02,$02,$02,$04,$ff,$0f&lt;br /&gt;
 .byte $14,$18,$1f,$0f,$14,$18,$1f,$0f,$14,$18,$1f,$0f,$14,$18,$1f,$18&lt;br /&gt;
 .byte $1a,$1c,$1e,$1f,$ff,$08,$08,$08,$08,$08,$08,$08,$08,$07,$08,$09&lt;br /&gt;
 .byte $0a,$0b,$0c,$0d,$0e,$0f,$ff,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$09&lt;br /&gt;
 .byte $09,$09,$09,$08,$07,$06,$05,$04,$1f,$12,$00,$1e,$11,$00,$1d,$10&lt;br /&gt;
 .byte $ff,$08,$08,$00,$08,$08,$00,$08,$08,$1f,$1f,$1e,$1e,$1d,$1c,$1b&lt;br /&gt;
 .byte $1a,$19,$18,$17,$16,$15,$14,$13,$12,$11,$10,$0f,$0e,$0d,$0c,$0b&lt;br /&gt;
 .byte $0a,$ff,$0a,$0a,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08&lt;br /&gt;
 .byte $08,$08,$08,$08,$07,$06,$05,$04,$03,$02,$0d,$0b,$09,$00,$0d,$0b&lt;br /&gt;
 .byte $09,$00,$0d,$0b,$09,$ff,$06,$07,$08,$00,$06,$06,$06,$00,$04,$04&lt;br /&gt;
 .byte $04,$1f,$1f,$1e,$1d,$1c,$1b,$1a,$19,$18,$17,$16,$15,$14,$13,$12&lt;br /&gt;
 .byte $11,$ff,$0a,$0a,$07,$07,$88,$03,$03,$03,$03,$ff,$08,$07,$06,$05&lt;br /&gt;
 .byte $04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$ff,$04,$05,$06,$07,$07&lt;br /&gt;
 .byte $07,$05,$04,$03,$01,$14,$14,$14,$14,$16,$14,$17,$15,$16,$14,$17&lt;br /&gt;
 .byte $15,$17,$14,$15,$14,$14,$16,$14,$15,$17,$14,$17,$15,$16,$14,$17&lt;br /&gt;
 .byte $15,$17,$14,$15,$14,$fe,$0f,$11,$13,$15,$17,$19,$1b,$1d,$1e,$1f&lt;br /&gt;
 .byte $ff,$09,$09,$08,$07,$06,$05,$04,$03,$02,$01,$0f,$0e,$0d,$0c,$0b&lt;br /&gt;
 .byte $0a,$09,$08,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0e,$0d,$0c,$0b&lt;br /&gt;
 .byte $0a,$09,$08,$00,$00,$ff,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18&lt;br /&gt;
 .byte $ff,$03,$03,$03,$06,$06,$06,$05,$05,$05,$02,$88,$84,$87,$8d,$86&lt;br /&gt;
 .byte $83,$88,$84,$8a,$82,$20,$09,$d9,$a9,$00,$8d,$0e,$25,$20,$f7,$3f&lt;br /&gt;
 .byte $60,$20,$09,$d9,$20,$fa,$3f,$a9,$c8,$85,$34,$a9,$00,$85,$fd,$60&lt;br /&gt;
 .byte $a5,$4c,$85,$62,$20,$09,$d9,$a5,$4a,$f0,$08,$ad,$ae,$27,$d0,$03&lt;br /&gt;
 .byte $8d,$0e,$25,$20,$fd,$3f,$4c,$e7,$d8,$ad,$00,$39,$c9,$c6,$d0,$61&lt;br /&gt;
 .byte $ad,$04,$39,$c9,$fe,$d0,$5a,$a2,$0f,$bd,$73,$d9,$9d,$ff,$24,$ca&lt;br /&gt;
 .byte $d0,$f7,$a2,$28,$bd,$97,$d9,$9d,$b3,$18,$ca,$d0,$f7,$a9,$01,$85&lt;br /&gt;
 .byte $fd,$20,$dd,$d1,$a5,$62,$aa,$0a,$0a,$0d,$ae,$27,$8d,$02,$25,$bd&lt;br /&gt;
 .byte $11,$da,$8d,$06,$25,$bd,$15,$da,$8d,$07,$25,$ad,$ae,$27,$f0,$12&lt;br /&gt;
 .byte $a9,$00,$8d,$af,$27,$a2,$03,$b5,$44,$9d,$af,$27,$ca,$d0,$f8,$4c&lt;br /&gt;
 .byte $6c,$d9,$a2,$03,$b5,$3f,$9d,$af,$27,$ca,$d0,$f8,$a2,$00,$a0,$25&lt;br /&gt;
 .byte $60,$68,$68,$60,$8b,$23,$00,$00,$00,$00,$c0,$d9,$af,$27,$83,$d9&lt;br /&gt;
 .byte $70,$d9,$04,$8f,$27,$cb,$08,$27,$cb,$07,$18,$b4,$07,$18,$bb,$07&lt;br /&gt;
 .byte $18,$c2,$07,$18,$c9,$07,$18,$d0,$cd,$40,$c0,$f2,$3c,$00,$00,$db&lt;br /&gt;
 .byte $40,$c0,$ef,$30,$00,$00,$dd,$40,$c8,$f1,$30,$00,$00,$ec,$40,$c8&lt;br /&gt;
 .byte $ef,$2c,$00,$00,$ec,$40,$c0,$ef,$2c,$ec,$80,$c0,$ff,$a0,$00,$00&lt;br /&gt;
 .byte $1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$01,$04,$06,$08,$0d,$0d,$04&lt;br /&gt;
 .byte $11,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$08,$0d,$13,$04,$11,$0c&lt;br /&gt;
 .byte $04,$03,$08,$00,$13,$04,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$00&lt;br /&gt;
 .byte $03,$15,$00,$0d,$02,$04,$03,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d&lt;br /&gt;
 .byte $1d,$04,$17,$0f,$04,$11,$13,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d&lt;br /&gt;
 .byte $1d,$c0,$d4,$e6,$f7,$d9,$d9,$d9,$d9,$00,$00,$00,$fa,$ff,$cf,$0d&lt;br /&gt;
 .byte $0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$00,$00&lt;br /&gt;
 .byte $00,$1a,$10,$14,$00,$29,$32,$46,$09,$84,$1e,$bc,$00,$39,$0d,$33&lt;br /&gt;
 .byte $15,$a9,$85,$0d,$1c,$44,$16,$e3,$e8,$fe,$58,$2a,$fa,$54,$50,$4c&lt;br /&gt;
 .byte $26,$22,$1e,$93,$ed,$48,$18,$19,$1c,$18,$19,$19,$19,$1c,$1c,$1c&lt;br /&gt;
 .byte $1d,$1d,$1e,$5e,$67,$82,$64,$68,$72,$7c,$8b,$95,$9f,$a5,$b2,$bf&lt;br /&gt;
 .byte $c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$a1,$55,$fb&lt;br /&gt;
 .byte $c1,$c6,$4e,$53,$d7,$dc,$ad,$a8,$07,$02,$61,$5c,$bb,$b6,$16,$11&lt;br /&gt;
 .byte $70,$6b,$ca,$c5,$25,$20,$7f,$7a,$d9,$d4,$33,$2e,$8d,$88,$e7,$e2&lt;br /&gt;
 .byte $42,$3d,$9c,$97,$f6,$f1,$51,$4c,$ab,$a6,$05,$00,$5f,$5a,$ba,$b5&lt;br /&gt;
 .byte $cb,$d0,$b1,$ac,$a7,$a2,$0c,$07,$02,$fd,$66,$61,$5c,$57,$c0,$bb&lt;br /&gt;
 .byte $b6,$b1,$1b,$16,$11,$0c,$75,$70,$6b,$66,$cf,$ca,$c5,$c0,$1e,$1f&lt;br /&gt;
 .byte $1e,$1f,$1f,$18,$18,$1f,$1f,$18,$18,$19,$19,$19,$19,$19,$19,$1a&lt;br /&gt;
 .byte $1a,$1a,$1a,$1a,$1a,$1b,$1b,$1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c,$1c&lt;br /&gt;
 .byte $1c,$1d,$1d,$1d,$1d,$1d,$1d,$1e,$1e,$1e,$1e,$1f,$1f,$1f,$1f,$1f&lt;br /&gt;
 .byte $1f,$1f,$1f,$19,$19,$19,$19,$1a,$1a,$1a,$19,$1a,$1a,$1a,$1a,$1a&lt;br /&gt;
 .byte $1a,$1a,$1a,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$85&lt;br /&gt;
 .byte $99,$ad,$44,$51,$04,$04,$04,$04,$00,$02,$00,$02,$00,$02,$00,$02&lt;br /&gt;
 .byte $00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02&lt;br /&gt;
 .byte $00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02&lt;br /&gt;
 .byte $00,$02,$00,$02,$61,$68,$72,$7c,$81,$89,$93,$9d,$a3,$ab,$b5,$bf&lt;br /&gt;
 .byte $c3,$c9,$d3,$dd,$df,$e9,$f3,$fd,$02,$0c,$16,$20,$25,$2f,$39,$43&lt;br /&gt;
 .byte $26,$26,$26,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22&lt;br /&gt;
 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22&lt;br /&gt;
 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22&lt;br /&gt;
 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22&lt;br /&gt;
 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$23,$23,$23,$23,$23,$23,$23&lt;br /&gt;
 .byte $23,$90,$90,$90,$93,$90,$00,$08,$00,$08,$1e,$1e,$1e,$1e,$1e,$1e&lt;br /&gt;
 .byte $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e&lt;br /&gt;
 .byte $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e&lt;br /&gt;
 .byte $1e,$1e,$1e,$1e,$1e,$1e,$f9,$f6,$f6,$fb,$f8,$f6,$f6,$fa,$f8,$f6&lt;br /&gt;
 .byte $f6,$fc,$fa,$f6,$f6,$fe,$f6,$f6,$f6,$fb,$f6,$f6,$f6,$fb,$f6,$f6&lt;br /&gt;
 .byte $f6,$fb,$a0,$a0,$a0,$10,$50,$00,$80,$00,$80,$00,$9a,$00,$9a,$00&lt;br /&gt;
 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00&lt;br /&gt;
 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00&lt;br /&gt;
 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$17,$31,$57,$7d,$13,$31,$57,$7d,$13&lt;br /&gt;
 .byte $31,$57,$7d,$1b,$31,$57,$7d,$0b,$31,$57,$7d,$0b,$31,$57,$7d,$0b&lt;br /&gt;
 .byte $31,$57,$7d,$0f,$27,$cb,$08,$27,$cb,$47,$18,$4e,$47,$18,$a8,$47&lt;br /&gt;
 .byte $18,$a8,$47,$18,$a8,$47,$18,$fa,$47,$19,$4c,$47,$19,$a2,$47,$19&lt;br /&gt;
 .byte $fd,$47,$1a,$57,$47,$1a,$b1,$47,$1b,$0c,$47,$1b,$66,$47,$1b,$c0&lt;br /&gt;
 .byte $47,$1c,$1e,$47,$1d,$3d,$47,$1d,$93,$47,$1d,$ed,$47,$1e,$48,$47&lt;br /&gt;
 .byte $1e,$a1,$47,$1e,$fb,$47,$1f,$55,$47,$1f,$b5,$47,$1f,$c1,$47,$1f&lt;br /&gt;
 .byte $d7,$0f,$27,$cb,$06,$27,$cb,$8f,$27,$cb,$17,$13,$6d,$71,$30,$34&lt;br /&gt;
 .byte $8e,$82,$86,$8a,$43,$58,$54,$5c,$60,$50,$4c,$ae,$aa,$b6,$b2,$a6&lt;br /&gt;
 .byte $a2,$c1,$c5,$d1,$c9,$cd,$d7,$db,$e7,$df,$e3,$1a,$1a,$1a,$1a,$1c&lt;br /&gt;
 .byte $1c,$1c,$1c,$1c,$1c,$1d,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f&lt;br /&gt;
 .byte $1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$a4,$fb,$aa,$ba&lt;br /&gt;
 .byte $97,$ba,$a0,$08,$11,$ba,$17,$00,$00,$8e,$ba,$20,$20,$8e,$8e,$a9&lt;br /&gt;
 .byte $be,$3c,$3c,$8e,$8e,$c4,$c0,$c2,$8e,$8e,$de,$c0,$c2,$a8,$a0,$a8&lt;br /&gt;
 .byte $a8,$a8,$a8,$a8,$c0,$c0,$a8,$c0,$c0,$c0,$a0,$a8,$c0,$c0,$af,$af&lt;br /&gt;
 .byte $a0,$a8,$c0,$c0,$af,$af,$a0,$a8,$a8,$af,$af,$a0,$a8,$a8,$1a,$1b&lt;br /&gt;
 .byte $14,$5c,$17,$5c,$1c,$17,$1a,$5c,$17,$18,$18,$05,$5c,$3e,$3e,$37&lt;br /&gt;
 .byte $37,$05,$3f,$3e,$3e,$37,$37,$06,$3f,$3f,$37,$37,$03,$3f,$3f,$88&lt;br /&gt;
 .byte $00,$2e,$38,$6d,$7a,$7c,$00,$8b,$05,$37,$fd,$82,$19,$3b,$f7,$a2&lt;br /&gt;
 .byte $a0,$a0,$1b,$b0,$f7,$a2,$a0,$a0,$1b,$b0,$b0,$f9,$84,$15,$b0,$b0&lt;br /&gt;
 .byte $bb,$ca,$7f,$f6,$ba,$eb,$19,$1a,$1b,$1d,$1f,$1f,$71,$85,$99,$ad&lt;br /&gt;
 .byte $59,$00,$26,$26,$26,$26,$26,$22,$90,$90,$90,$90,$68,$92,$2e,$2e&lt;br /&gt;
 .byte $2e,$2e,$20,$a8,$58,$b2,$0c,$66,$bb,$13,$6d,$ca,$2a,$7f,$de,$30&lt;br /&gt;
 .byte $82,$ec,$43,$a1,$f6,$56,$b0,$0a,$4c,$a2,$c1,$d7,$18,$18,$19,$19&lt;br /&gt;
 .byte $19,$1a,$1a,$1a,$1b,$1b,$1b,$1c,$1c,$1c,$1d,$1d,$1d,$1e,$1e,$1f&lt;br /&gt;
 .byte $1f,$1f,$1f,$1f,$b2,$c9,$cd,$df,$e3,$1f,$1f,$1f,$1f,$1f,$60,$8a&lt;br /&gt;
 .byte $34,$71,$1f,$1c,$1c,$1a,$b6,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba&lt;br /&gt;
 .byte $7c,$7c,$9c,$9c,$9c,$9c,$9c,$9c,$9c,$9c,$be,$de,$9e,$9e,$9e,$9e&lt;br /&gt;
 .byte $9e,$9e,$9e,$9e,$02,$03,$01,$02,$ff,$03,$03,$02,$03,$ff,$04,$04&lt;br /&gt;
 .byte $04,$05,$ff,$05,$06,$06,$07,$00,$08,$08,$09,$0a,$01,$0a,$0b,$0c&lt;br /&gt;
 .byte $0b,$01,$0c,$0c,$0f,$0e,$01,$0c,$14,$1e,$26,$00,$80,$00,$5a,$dc&lt;br /&gt;
 .byte $00,$00,$01,$01,$01,$01,$04,$04,$04,$04,$02,$fc,$fc,$fc,$fc,$fd&lt;br /&gt;
 .byte $00,$00,$00,$00,$c0,$a0,$80,$40,$10,$04,$02,$01,$00,$00,$00,$00&lt;br /&gt;
 .byte $7f,$05,$04,$03,$7f,$04,$03,$02,$7f,$03,$02,$01,$00,$00,$00,$40&lt;br /&gt;
 .byte $00,$e0,$c0,$a0,$80,$00,$80,$40,$10,$03,$02,$01,$01,$00,$00,$00&lt;br /&gt;
 .byte $02,$02,$01,$01,$20,$d0,$60,$e0,$80,$00,$80,$20,$a0,$30,$e0,$fd&lt;br /&gt;
 .byte $fd,$fe,$fe,$ff,$00,$00,$01,$01,$02,$02,$03,$04,$04,$ff,$02,$00&lt;br /&gt;
 .byte $03,$ff,$01,$01,$02,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b5&lt;br /&gt;
 .byte $b5,$b5,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$01,$ff&lt;br /&gt;
 .byte $01,$ff,$01,$ff,$01,$ff,$01,$ff,$01,$a7,$67,$5f,$37,$5e,$29,$9d&lt;br /&gt;
 .byte $5b,$be,$be,$be,$be,$be,$be,$be,$be,$be,$be,$c2,$c2,$c2,$bb,$bb&lt;br /&gt;
 .byte $bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$1a,$1a,$1a,$1a,$1a,$1a&lt;br /&gt;
 .byte $1a,$1a,$1a,$1a,$16,$16,$16,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f&lt;br /&gt;
 .byte $1f,$1f,$1f,$01,$02,$02,$9c,$9c,$9c,$1c,$1c,$1c,$71,$85,$99,$ad&lt;br /&gt;
 .byte $26,$26,$26,$26,$03,$08,$0c,$10,$3f,$0f,$0f,$03,$03,$00,$00,$00&lt;br /&gt;
 .byte $00,$00,$00,$54,$54,$55,$55,$55,$55,$55,$55,$55,$95,$95,$95,$a5&lt;br /&gt;
 .byte $a9,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa&lt;br /&gt;
 .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$ff,$ff,$ff,$ff&lt;br /&gt;
 .byte $ff,$ff,$ff,$3f,$3f,$0f,$0f,$0f,$0f,$0f,$5f,$5f,$03,$43,$57,$55&lt;br /&gt;
 .byte $5f,$5f,$5f,$5f,$5f,$5f,$5f,$5f,$95,$95,$5f,$95,$55,$a5,$5f,$a5&lt;br /&gt;
 .byte $a5,$aa,$af,$aa,$aa,$aa,$af,$aa,$aa,$aa,$af,$aa,$aa,$aa,$af,$aa&lt;br /&gt;
 .byte $47,$43,$43,$28,$43,$29,$31,$39,$38,$34&lt;br /&gt;
&lt;br /&gt;
  ORG $FF7A&lt;br /&gt;
START&lt;br /&gt;
  JMP GameColdInit&lt;br /&gt;
&lt;br /&gt;
 .byte $3F &lt;br /&gt;
 .byte $39 &lt;br /&gt;
 .byte $34 &lt;br /&gt;
&lt;br /&gt;
CART_SIGNATURE:  ; FF80-FFF7&lt;br /&gt;
 .byte $04,$C4,$76,$30,$6A,$8C,$8A,$3A,$CA,$F5,$BC,$71,$CA,$76,$08,$AB&lt;br /&gt;
 .byte $75,$58,$CD,$19,$2A,$29,$2E,$F0,$DB,$7B,$84,$98,$A4,$0E,$0A,$7C&lt;br /&gt;
 .byte $3F,$D8,$93,$8D,$59,$98,$FA,$77,$03,$FF,$E9,$9B,$70,$A8,$B3,$A5&lt;br /&gt;
 .byte $AA,$E7,$7F,$82,$CF,$DD,$5F,$F4,$54,$79,$BA,$D7,$6D,$73,$26,$CE&lt;br /&gt;
 .byte $B3,$06,$39,$94,$BA,$74,$A1,$E7,$8F,$AF,$6C,$B2,$E2,$74,$70,$0B&lt;br /&gt;
 .byte $2E,$68,$F2,$4F,$27,$E2,$AA,$4D,$F7,$B0,$CD,$C6,$9D,$B1,$42,$59&lt;br /&gt;
 .byte $CE,$0D,$59,$14,$13,$8E,$71,$5C,$A0,$09,$4E,$00,$85,$99,$E7,$CA&lt;br /&gt;
 .byte $E4,$A5,$D9,$A1,$2B,$47,$A4,$CE&lt;br /&gt;
&lt;br /&gt;
 .byte $FF  ; region verification. $FF=all regions&lt;br /&gt;
 .byte $E7  ; encryption check starts at $E000 &lt;br /&gt;
&lt;br /&gt;
 .word NMI_ROUTINE&lt;br /&gt;
 .word START&lt;br /&gt;
 .word IRQ_ROUTINE&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1289</id>
		<title>Assembly Source Code</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1289"/>
				<updated>2025-08-21T01:20:13Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: /* JOUST 7800 NTSC */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Assembly Source Code ==&lt;br /&gt;
The following source code files will compile on DASM, making them useful for both studying and modifying.&lt;br /&gt;
&lt;br /&gt;
=== [[7800_NTSC_BIOS]] ===&lt;br /&gt;
''The NTSC BIOS does a bit of sanity checking, verifies if the inserted cart is cryptographically signed for 7800 mode.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[7800 PAL BIOS]] ===&lt;br /&gt;
''The PAL BIOS lacks the cryptographic checks of the NTSC BIOS, due to US munition laws that made export of cryptographic technology illegal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[JOUST 7800 NTSC Source Code]] ===&lt;br /&gt;
''A complete disassembly of the finest 8-bit port of Joust.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Main_Page&amp;diff=1288</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Main_Page&amp;diff=1288"/>
				<updated>2025-08-21T01:19:50Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Atari 7800 Development Wiki Home==&lt;br /&gt;
&lt;br /&gt;
Welcome to the &amp;lt;b&amp;gt;Atari 7800 Development wiki&amp;lt;/b&amp;gt;! This site aims to be the definitive source for accurate and up-to-date information on &amp;lt;b&amp;gt;programming the Atari 7800 console&amp;lt;/b&amp;gt;. If you're interested in &amp;lt;b&amp;gt;7800 homebrew&amp;lt;/b&amp;gt; programming, you've come to the right place!&lt;br /&gt;
&lt;br /&gt;
You can begin by checking out one of the links presented in the next section, or you may use the wiki search function to quickly find information on a specific topic.&lt;br /&gt;
&lt;br /&gt;
==Wiki Sections==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;The [[7800 Software Guide]] &lt;br /&gt;
:An updated version of the documentation originally produced by Atari and GCC. Several inaccuracies have been discovered and corrected, and new sections have been added.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800AsmDevKit]] &lt;br /&gt;
:A quick way to get started with programming the 7800 using assembly language. All the tools you need to create a game, cross-platform and available for multiple OSes. 7800.8bitdev.org is the official home of the 7800AsmDevKit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800basic]] &lt;br /&gt;
:A quick way to get started with programming the 7800 using a higher level language. 7800basic is a compiled language, designed for efficiency. 7800.8bitdev.org is the official home of 7800basic.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800 Tutorials and Guides]] &lt;br /&gt;
:Covers more advanced 7800 topics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[Emulators and Tools]] &lt;br /&gt;
:Covers information on tools useful to the 7800 developer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[Assembly Source Code]]&lt;br /&gt;
:Reverse engineered source code in DASM format.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[Historic Documents]]&lt;br /&gt;
:Various Atari 7800 related historic documents.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1286</id>
		<title>Assembly Source Code</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Assembly_Source_Code&amp;diff=1286"/>
				<updated>2025-08-21T01:11:58Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;== Assembly Source Code == The following source code files will compile on DASM, making them useful for both studying and modifying.  === 7800_NTSC_BIOS === ''The NTSC BIO...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Assembly Source Code ==&lt;br /&gt;
The following source code files will compile on DASM, making them useful for both studying and modifying.&lt;br /&gt;
&lt;br /&gt;
=== [[7800_NTSC_BIOS]] ===&lt;br /&gt;
''The NTSC BIOS does a bit of sanity checking, verifies if the inserted cart is cryptographically signed for 7800 mode.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[7800 PAL BIOS]] ===&lt;br /&gt;
''The PAL BIOS lacks the cryptographic checks of the NTSC BIOS, due to US munition laws that made export of cryptographic technology illegal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== [[JOUST 7800 NTSC]] ===&lt;br /&gt;
''A complete disassembly of the finest 8-bit port of Joust.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1285</id>
		<title>7800 PAL BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1285"/>
				<updated>2025-08-05T12:58:13Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 PAL BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Disassembly of the Atari 7800 PAL BIOS&lt;br /&gt;
;&lt;br /&gt;
; - Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; - Mike Saarna&lt;br /&gt;
; - Gemini 2.5 Pro&lt;br /&gt;
;&lt;br /&gt;
; Key differences from the NTSC BIOS:&lt;br /&gt;
;   1. Built-in Game: Includes a full version of Asteroids that runs if no&lt;br /&gt;
;      valid cartridge is detected.&lt;br /&gt;
;   2. No Encryption: Due to 1980s-era encryption export laws, the complex&lt;br /&gt;
;      cart verification from the NTSC BIOS is absent. 7800 cartridge checks&lt;br /&gt;
;      just confirm 7800 footer bytes and lack of 2600 ROM mirrors.&lt;br /&gt;
;&lt;br /&gt;
; The code must be assembled with DASM.&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; I. HARDWARE AND MEMORY EQUATES&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
STACKPTR  EQU     $FF&lt;br /&gt;
REGION    EQU     $FE&lt;br /&gt;
&lt;br /&gt;
; --- TIA (Television Interface Adapter) Registers ---&lt;br /&gt;
INPTCTRL  EQU     $01                    ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.&lt;br /&gt;
TIAWSYNC  EQU     $02                    ; TIA's WSYNC, not Maria's&lt;br /&gt;
CXP0FB    EQU     $02                    ; TIA Collision Register&lt;br /&gt;
CXP1FB    EQU     $03                    ; TIA Collision Register&lt;br /&gt;
COLUP0    EQU     $06                    ; TIA P0 Color&lt;br /&gt;
COLUBK    EQU     $09                    ; TIA Background Color&lt;br /&gt;
INPT4     EQU     $0C                    ; Input Port 4 (Joystick Triggers)&lt;br /&gt;
INPT5     EQU     $0D                    ; Input Port 5 (Joystick Triggers)&lt;br /&gt;
AUDC0     EQU     $15                    ; Audio Control 0&lt;br /&gt;
AUDC1     EQU     $16                    ; Audio Control 1&lt;br /&gt;
AUDF0     EQU     $17                    ; Audio Frequency 0&lt;br /&gt;
AUDF1     EQU     $18                    ; Audio Frequency 1&lt;br /&gt;
AUDV0     EQU     $19                    ; Audio Volume 0&lt;br /&gt;
AUDV1     EQU     $1A                    ; Audio Volume 1&lt;br /&gt;
&lt;br /&gt;
; --- Maria (Custom Graphics Chip) Registers ---&lt;br /&gt;
BACKGRND  EQU     $20                    ; Background Color&lt;br /&gt;
P0C1      EQU     $21                    ; Palette 0, Color 1&lt;br /&gt;
P0C2      EQU     $22                    ; Palette 0, Color 2&lt;br /&gt;
P0C3      EQU     $23                    ; Palette 0, Color 3&lt;br /&gt;
WSYNC     EQU     $24                    ; Maria Wait for Sync (halts CPU until horizontal blank)&lt;br /&gt;
P1C1      EQU     $25                    ; Palette 1, Color 1&lt;br /&gt;
P1C2      EQU     $26                    ; Palette 1, Color 2&lt;br /&gt;
P1C3      EQU     $27                    ; Palette 1, Color 3&lt;br /&gt;
MSTAT     EQU     $28                    ; Maria Status Register (VBLANK, etc.)&lt;br /&gt;
P2C1      EQU     $29                    ; Palette 2, Color 1&lt;br /&gt;
P2C2      EQU     $2A                    ; Palette 2, Color 2&lt;br /&gt;
P2C3      EQU     $2B                    ; Palette 2, Color 3&lt;br /&gt;
DPPH      EQU     $2C                    ; Display List Pointer High Byte&lt;br /&gt;
P3C1      EQU     $2D                    ; Palette 3, Color 1&lt;br /&gt;
P3C2      EQU     $2E                    ; Palette 3, Color 2&lt;br /&gt;
P3C3      EQU     $2F                    ; Palette 3, Color 3&lt;br /&gt;
DPPL      EQU     $30                    ; Display List Pointer Low Byte&lt;br /&gt;
P4C1      EQU     $31                    ; Palette 4, Color 1&lt;br /&gt;
P4C2      EQU     $32                    ; Palette 4, Color 2&lt;br /&gt;
P4C3      EQU     $33                    ; Palette 4, Color 3&lt;br /&gt;
CHARBASE  EQU     $34                    ; Character Mode High Pointer&lt;br /&gt;
P5C1      EQU     $35                    ; Palette 5, Color 1&lt;br /&gt;
P5C2      EQU     $36                    ; Palette 5, Color 2&lt;br /&gt;
P5C3      EQU     $37                    ; Palette 5, Color 3&lt;br /&gt;
OFFSET    EQU     $38                    ; Not used by BIOS&lt;br /&gt;
P6C1      EQU     $39                    ; Palette 6, Color 1&lt;br /&gt;
P6C2      EQU     $3A                    ; Palette 6, Color 2&lt;br /&gt;
P6C3      EQU     $3B                    ; Palette 6, Color 3&lt;br /&gt;
CTRL      EQU     $3C                    ; Maria Control Register (DMA, graphics mode)&lt;br /&gt;
P7C1      EQU     $3D                    ; Palette 7, Color 1&lt;br /&gt;
P7C2      EQU     $3E                    ; Palette 7, Color 2&lt;br /&gt;
P7C3      EQU     $3F                    ; Palette 7, Color 3&lt;br /&gt;
&lt;br /&gt;
; --- RAM Address Equates ---&lt;br /&gt;
RAM_BASE_1    EQU $2000&lt;br /&gt;
RAM_BASE_2    EQU $2100&lt;br /&gt;
RAM_CODE_BASE EQU $2300&lt;br /&gt;
RAM_DLL_BASE  EQU $2700&lt;br /&gt;
RAM_DLL_START EQU $2707&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; II. BUILT-IN ASTEROIDS GAME DATA&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
	ORG     $C000&lt;br /&gt;
        ; This directive includes the 15,933 byte ROM image for the built-in&lt;br /&gt;
        ; Asteroids game. To generate this file from a PAL BIOS ROM on Mac OS&lt;br /&gt;
        ; or Linux, do the following...&lt;br /&gt;
        ;&lt;br /&gt;
        ;   dd if=7800pal.rom of=ASTEROID.BIN bs=1 count=15933&lt;br /&gt;
        &lt;br /&gt;
        INCBIN &amp;quot;ASTEROID.BIN&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; III. MAIN BIOS LOGIC (EXECUTED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        ORG     $FE3D&lt;br /&gt;
&lt;br /&gt;
; --- Data for Initial Display List ---&lt;br /&gt;
; This data is copied to RAM at RAM_DLL_BASE ($2700) during initialization.&lt;br /&gt;
DisplayList_InitialData:&lt;br /&gt;
        .byte     $00	; DL entry - this is copied to $2700&lt;br /&gt;
        .byte     $40&lt;br /&gt;
        .byte     $F0&lt;br /&gt;
        .byte     $1F&lt;br /&gt;
        .byte     $BB&lt;br /&gt;
        .byte     $00&lt;br /&gt;
        .byte     $00&lt;br /&gt;
&lt;br /&gt;
        .byte     $8F	; DLL entry - this is copied repeatedly at $2707&lt;br /&gt;
        .byte     &amp;gt;RAM_DLL_BASE&lt;br /&gt;
DisplayList_InitialData_End:&lt;br /&gt;
        .byte     &amp;lt;RAM_DLL_BASE&lt;br /&gt;
&lt;br /&gt;
; --- BIOS Entry Point on Power-On/Reset ---&lt;br /&gt;
Bios_EntryPoint_Reset:&lt;br /&gt;
          SEI                            ; Disable interrupts.&lt;br /&gt;
          CLD                            ; Clear decimal mode.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$02                   ; Enable Maria and map BIOS into memory.&lt;br /&gt;
          STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
          LDX     #STACKPTR&lt;br /&gt;
          TXS                            ; Set stack pointer.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$7F&lt;br /&gt;
          STA     CTRL                   ; Turn off Maria DMA.&lt;br /&gt;
          LDA     #$00&lt;br /&gt;
          STA     BACKGRND               ; Set background color to black.&lt;br /&gt;
&lt;br /&gt;
          LDX     #$7F                   ; Copy 2600 mode initialization code to RIOT RAM.&lt;br /&gt;
Bios_Copy2600InitToRam_Loop:&lt;br /&gt;
          LDA     TiaInitCode_2600Mode,X ; Move from ROM...&lt;br /&gt;
          STA     $480,X                 ; ...to RIOT RAM at $0480.&lt;br /&gt;
          DEX&lt;br /&gt;
          BPL     Bios_Copy2600InitToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the main cartridge checking logic from ROM to system RAM.&lt;br /&gt;
        ; This is done so the system can disable the BIOS ROM to read the&lt;br /&gt;
        ; cartridge, while still executing the necessary checker code from RAM.&lt;br /&gt;
        LDX     #[TiaInitCode_2600Mode - RamCode_Start]&lt;br /&gt;
Bios_CopyCartCheckToRam_Loop:&lt;br /&gt;
        LDA     RamCode_Start-1,X&lt;br /&gt;
        STA     RAM_CODE_BASE-1,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     Bios_CopyCartCheckToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        LDA     #0                     ; Zero out all TIA registers.&lt;br /&gt;
        TAX&lt;br /&gt;
Bios_ClearTiaRegs_Loop:&lt;br /&gt;
        STA     1,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2C&lt;br /&gt;
        BNE     Bios_ClearTiaRegs_Loop&lt;br /&gt;
        LDA     #$02                   ; Switch back into Maria mode.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        ; Initialize the first 64 bytes of both RAM chips to $FF.&lt;br /&gt;
        LDA     #$FF&lt;br /&gt;
        LDX     #$3F&lt;br /&gt;
Bios_InitRam_Loop:&lt;br /&gt;
        STA     RAM_BASE_1,X&lt;br /&gt;
        STA     RAM_BASE_2,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_InitRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the initial Display List data to its location in RAM.&lt;br /&gt;
        LDX     #(DisplayList_InitialData_End - DisplayList_InitialData)&lt;br /&gt;
Bios_CopyDisplayList_Loop:&lt;br /&gt;
        LDA     DisplayList_InitialData,X&lt;br /&gt;
        STA     RAM_DLL_BASE,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_CopyDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Replicate the last 3 bytes of the DL data to fill out the list.&lt;br /&gt;
        INX&lt;br /&gt;
        LDY     #80&lt;br /&gt;
Bios_FillDisplayList_Loop:&lt;br /&gt;
        LDA     RAM_DLL_START,X&lt;br /&gt;
        STA     RAM_DLL_START+3,X&lt;br /&gt;
        INX&lt;br /&gt;
        DEY&lt;br /&gt;
        BNE     Bios_FillDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Jump to the cartridge test routine, now located in RAM.&lt;br /&gt;
        JMP     [CartCheck_Start - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; IV. RAM-EXECUTED CODE (COPIED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
; This block of code is not executed from its ROM address. It is copied to&lt;br /&gt;
; system RAM starting at RAM_CODE_BASE ($2300) and executed from there.&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
RamCode_Start: ; (Base address for relative calculations, starts at $FEBD in ROM)&lt;br /&gt;
CartCheck_RunInternalGame:&lt;br /&gt;
        LDA     #$13                   ; Enable BIOS ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
        JMP     StartInternalAsteroidsGame ; Jump to the built-in game.&lt;br /&gt;
&lt;br /&gt;
CartCheck_Start:&lt;br /&gt;
        LDA     #$16                   ; Enable external cartridge ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        LDY     #$FF&lt;br /&gt;
        LDX     #$7F&lt;br /&gt;
; --- Cartridge Presence Test (Floating Bus Check) ---&lt;br /&gt;
; This loop compares the same ROM regions using different base addresses. &lt;br /&gt;
; If no cart is present, the bus will &amp;quot;float&amp;quot; with the last byte of the opcode&lt;br /&gt;
; (due to bus capacitance) and the last byte of the opcode differs in our test. &lt;br /&gt;
; Therefore, if our compared bytes differ, a cart IS NOT present.&lt;br /&gt;
CartCheck_FloatingBus_Loop:&lt;br /&gt;
        LDA     $FE00,X&lt;br /&gt;
        CMP     $FD80,Y&lt;br /&gt;
        BNE     CartCheck_RunInternalGame&lt;br /&gt;
        DEY&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_FloatingBus_Loop&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Reset Vector Test ---&lt;br /&gt;
; A valid cart must have a valid reset vector. $FFFF or $0000 indicates an&lt;br /&gt;
; empty socket or a problem.&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          AND     $FFFD&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines high -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          ORA     $FFFD&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines low -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
; --- Simple 7800 Signature Checks ---&lt;br /&gt;
          LDA     $FFF8                  ; Check region verification byte.&lt;br /&gt;
          ORA     #REGION&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF8&lt;br /&gt;
        EOR     #$F0&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Check Maria signature byte.&lt;br /&gt;
        AND     #$0B                   ; $07 or $03 are valid values.&lt;br /&gt;
        CMP     #$03&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Get bottom of cart address range.&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        CMP     #$40                   ; Make sure it is not below $4000.&lt;br /&gt;
        BCC     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        SBC     #$01                   ; Check that start vector is within cart range.&lt;br /&gt;
        CMP     $FFFD&lt;br /&gt;
        BCS     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
; --- Final Header Check ---&lt;br /&gt;
; This appears to be a final, simple checksum or signature validation.&lt;br /&gt;
        LDA     $1BEA&lt;br /&gt;
        EOR     #$FF&lt;br /&gt;
        STA     $1BEA&lt;br /&gt;
&lt;br /&gt;
        TAY&lt;br /&gt;
        LDX     #$05&lt;br /&gt;
CartCheck_HeaderValidation_Loop:&lt;br /&gt;
        LDA     $FFFA,X&lt;br /&gt;
        CMP     $DFFA,X&lt;br /&gt;
        BNE     CartCheck_HeaderValidation_Fail&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_HeaderValidation_Loop&lt;br /&gt;
&lt;br /&gt;
        CPY     $1BEA&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
CartCheck_HeaderValidation_Fail:&lt;br /&gt;
        LDA     #$02&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
        LDA     #&amp;gt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPH&lt;br /&gt;
        LDA     #&amp;lt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPL                   ; Set Display List pointer.&lt;br /&gt;
        LDA     #$43&lt;br /&gt;
        STA     $78&lt;br /&gt;
        STA     CTRL                   ; Turn graphics on.&lt;br /&gt;
        LDX     #$01&lt;br /&gt;
Util_WaitTwoFrames:&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Util_WaitTwoFrames&lt;br /&gt;
&lt;br /&gt;
        LDA     #$60                   ; Turn off graphics DMA.&lt;br /&gt;
        STA     CTRL&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 7800 Mode ---&lt;br /&gt;
Boot_Enter7800Mode:&lt;br /&gt;
        LDX     #$16                   ; Enable cartridge ROM and Maria.&lt;br /&gt;
        STX     INPTCTRL&lt;br /&gt;
        TXS                            ; Set stack pointer.&lt;br /&gt;
        SED                            ; Set decimal mode.&lt;br /&gt;
        JMP     ($FFFC)                ; Jump to the cartridge's reset vector.&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 2600 Mode ---&lt;br /&gt;
CartCheck_7800Fail_Try2600:&lt;br /&gt;
Boot_Enter2600Mode_FromRam:&lt;br /&gt;
        LDA     #$02                   ; Enable BIOS ROM.&lt;br /&gt;
        STA     INPTCTRL               ; Lock cart in 2600 mode.&lt;br /&gt;
        JMP     $480                   ; Execute 2600 init code from RIOT RAM.&lt;br /&gt;
&lt;br /&gt;
; --- Utility: Wait for Vertical Blank ---&lt;br /&gt;
Util_WaitForVblank:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK ended yet?&lt;br /&gt;
        BMI     Util_WaitForVblank&lt;br /&gt;
Util_WaitForVblank_Start:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK started yet?&lt;br /&gt;
        BPL     Util_WaitForVblank_Start&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
; --- 2600 TIA Setup Code (Copied to and executed from RIOT RAM at $0480) ---&lt;br /&gt;
TiaInitCode_2600Mode:&lt;br /&gt;
        LDA     #0&lt;br /&gt;
        TAX&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
TiaInit_ClearLoop:&lt;br /&gt;
        STA     $03,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2A&lt;br /&gt;
        BNE     TiaInit_ClearLoop&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #4&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        LDX     #4&lt;br /&gt;
TiaInit_DelayLoop:&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     TiaInit_DelayLoop&lt;br /&gt;
        TXS&lt;br /&gt;
        STA     $110&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        STA     $11&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        STA     $1C&lt;br /&gt;
        STA     $F&lt;br /&gt;
        NOP&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        BIT     CXP1FB&lt;br /&gt;
        BMI     TiaInit_SetColors2&lt;br /&gt;
TiaInit_SetColors1:&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUBK&lt;br /&gt;
        STA     $F112&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors2:&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors3&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUP0&lt;br /&gt;
        STA     $F118&lt;br /&gt;
TiaInit_DummyLabel:&lt;br /&gt;
        STA     $F460&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors3:&lt;br /&gt;
        STA     $2C&lt;br /&gt;
        LDA     #$08&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        NOP&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
TiaInit_Finalize:&lt;br /&gt;
        LDA     #$FD&lt;br /&gt;
        STA     8&lt;br /&gt;
        JMP     ($FFFC)&lt;br /&gt;
&lt;br /&gt;
; --- Internal Asteroids Game Startup Logic ---&lt;br /&gt;
; This routine is only called from inside the Asteroids game code.&lt;br /&gt;
Asteroids_InternalSubroutine_Equate = $F444&lt;br /&gt;
Asteroids_InternalSubroutine:&lt;br /&gt;
        JSR     Asteroids_InternalSubroutine_Equate&lt;br /&gt;
        LDA     $82&lt;br /&gt;
        BPL     Asteroids_Sub_SkipZero&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
Asteroids_Sub_SkipZero:&lt;br /&gt;
        ASL&lt;br /&gt;
        ASL&lt;br /&gt;
        CLC&lt;br /&gt;
        ADC     $83&lt;br /&gt;
        STA     $55&lt;br /&gt;
        LDA     #$01&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
StartInternalAsteroidsGame:&lt;br /&gt;
        JSR     Util_WaitForVblank&lt;br /&gt;
StartInternalGame_WaitFrame1:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_WaitFrame1&lt;br /&gt;
        LDA     #$9E&lt;br /&gt;
        LDY     #$00&lt;br /&gt;
        LDX     #$00&lt;br /&gt;
StartInternalGame_WaitFrame2:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_SyncWaitDone&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     StartInternalGame_WaitFrame2&lt;br /&gt;
StartInternalGame_SyncWaitDone:&lt;br /&gt;
        CPX     #$78&lt;br /&gt;
        BCS     StartInternalGame_SetDPPL&lt;br /&gt;
        LDA     #$98&lt;br /&gt;
        LDY     #$2B&lt;br /&gt;
StartInternalGame_SetDPPL:&lt;br /&gt;
        STA     DPPL&lt;br /&gt;
        STY     $2001&lt;br /&gt;
        JMP     $D000                  ; Jump into the Asteroids game code.&lt;br /&gt;
&lt;br /&gt;
        .byte     0,0,0,0,0,0,0,0&lt;br /&gt;
        .byte     0,0&lt;br /&gt;
&lt;br /&gt;
; --- Equates for Asteroids Game Vectors ---&lt;br /&gt;
ASTEROIDS_NMI_VECTOR   EQU     $D2E9&lt;br /&gt;
ASTEROIDS_IRQ_VECTOR   EQU     $D329&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; V. 6502 HARDWARE VECTORS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        .word   ASTEROIDS_NMI_VECTOR	; NMI (DLI handler for Asteroids)&lt;br /&gt;
        .word   Bios_EntryPoint_Reset	; RESET&lt;br /&gt;
        .word   ASTEROIDS_IRQ_VECTOR	; IRQ&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1284</id>
		<title>7800 PAL BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1284"/>
				<updated>2025-08-05T12:52:51Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 PAL BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Disassembly of the Atari 7800 PAL BIOS&lt;br /&gt;
;&lt;br /&gt;
; - Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; - Mike Saarna&lt;br /&gt;
; - Gemini 2.5 Pro&lt;br /&gt;
;&lt;br /&gt;
; Key differences from the NTSC BIOS:&lt;br /&gt;
;   1. Built-in Game: Includes a full version of Asteroids that runs if no&lt;br /&gt;
;      valid cartridge is detected.&lt;br /&gt;
;   2. No Encryption: Due to 1980s-era export laws, the complex signature&lt;br /&gt;
;      verification from the NTSC BIOS is absent. Cartridge checks are simpler.&lt;br /&gt;
;&lt;br /&gt;
; The code must be assembled with DASM.&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; I. HARDWARE AND MEMORY EQUATES&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
STACKPTR  EQU     $FF&lt;br /&gt;
REGION    EQU     $FE&lt;br /&gt;
&lt;br /&gt;
; --- TIA (Television Interface Adapter) Registers ---&lt;br /&gt;
INPTCTRL  EQU     $01                    ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.&lt;br /&gt;
TIAWSYNC  EQU     $02                    ; TIA's WSYNC, not Maria's&lt;br /&gt;
CXP0FB    EQU     $02                    ; TIA Collision Register&lt;br /&gt;
CXP1FB    EQU     $03                    ; TIA Collision Register&lt;br /&gt;
COLUP0    EQU     $06                    ; TIA P0 Color&lt;br /&gt;
COLUBK    EQU     $09                    ; TIA Background Color&lt;br /&gt;
INPT4     EQU     $0C                    ; Input Port 4 (Joystick Triggers)&lt;br /&gt;
INPT5     EQU     $0D                    ; Input Port 5 (Joystick Triggers)&lt;br /&gt;
AUDC0     EQU     $15                    ; Audio Control 0&lt;br /&gt;
AUDC1     EQU     $16                    ; Audio Control 1&lt;br /&gt;
AUDF0     EQU     $17                    ; Audio Frequency 0&lt;br /&gt;
AUDF1     EQU     $18                    ; Audio Frequency 1&lt;br /&gt;
AUDV0     EQU     $19                    ; Audio Volume 0&lt;br /&gt;
AUDV1     EQU     $1A                    ; Audio Volume 1&lt;br /&gt;
&lt;br /&gt;
; --- Maria (Custom Graphics Chip) Registers ---&lt;br /&gt;
BACKGRND  EQU     $20                    ; Background Color&lt;br /&gt;
P0C1      EQU     $21                    ; Palette 0, Color 1&lt;br /&gt;
P0C2      EQU     $22                    ; Palette 0, Color 2&lt;br /&gt;
P0C3      EQU     $23                    ; Palette 0, Color 3&lt;br /&gt;
WSYNC     EQU     $24                    ; Maria Wait for Sync (halts CPU until horizontal blank)&lt;br /&gt;
P1C1      EQU     $25                    ; Palette 1, Color 1&lt;br /&gt;
P1C2      EQU     $26                    ; Palette 1, Color 2&lt;br /&gt;
P1C3      EQU     $27                    ; Palette 1, Color 3&lt;br /&gt;
MSTAT     EQU     $28                    ; Maria Status Register (VBLANK, etc.)&lt;br /&gt;
P2C1      EQU     $29                    ; Palette 2, Color 1&lt;br /&gt;
P2C2      EQU     $2A                    ; Palette 2, Color 2&lt;br /&gt;
P2C3      EQU     $2B                    ; Palette 2, Color 3&lt;br /&gt;
DPPH      EQU     $2C                    ; Display List Pointer High Byte&lt;br /&gt;
P3C1      EQU     $2D                    ; Palette 3, Color 1&lt;br /&gt;
P3C2      EQU     $2E                    ; Palette 3, Color 2&lt;br /&gt;
P3C3      EQU     $2F                    ; Palette 3, Color 3&lt;br /&gt;
DPPL      EQU     $30                    ; Display List Pointer Low Byte&lt;br /&gt;
P4C1      EQU     $31                    ; Palette 4, Color 1&lt;br /&gt;
P4C2      EQU     $32                    ; Palette 4, Color 2&lt;br /&gt;
P4C3      EQU     $33                    ; Palette 4, Color 3&lt;br /&gt;
CHARBASE  EQU     $34                    ; Character Mode High Pointer&lt;br /&gt;
P5C1      EQU     $35                    ; Palette 5, Color 1&lt;br /&gt;
P5C2      EQU     $36                    ; Palette 5, Color 2&lt;br /&gt;
P5C3      EQU     $37                    ; Palette 5, Color 3&lt;br /&gt;
OFFSET    EQU     $38                    ; Not used by BIOS&lt;br /&gt;
P6C1      EQU     $39                    ; Palette 6, Color 1&lt;br /&gt;
P6C2      EQU     $3A                    ; Palette 6, Color 2&lt;br /&gt;
P6C3      EQU     $3B                    ; Palette 6, Color 3&lt;br /&gt;
CTRL      EQU     $3C                    ; Maria Control Register (DMA, graphics mode)&lt;br /&gt;
P7C1      EQU     $3D                    ; Palette 7, Color 1&lt;br /&gt;
P7C2      EQU     $3E                    ; Palette 7, Color 2&lt;br /&gt;
P7C3      EQU     $3F                    ; Palette 7, Color 3&lt;br /&gt;
&lt;br /&gt;
; --- RAM Address Equates ---&lt;br /&gt;
RAM_BASE_1    EQU $2000&lt;br /&gt;
RAM_BASE_2    EQU $2100&lt;br /&gt;
RAM_CODE_BASE EQU $2300&lt;br /&gt;
RAM_DLL_BASE  EQU $2700&lt;br /&gt;
RAM_DLL_START EQU $2707&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; II. BUILT-IN ASTEROIDS GAME DATA&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
	ORG     $C000&lt;br /&gt;
        ; This directive includes the 15,933 byte ROM image for the built-in&lt;br /&gt;
        ; Asteroids game. To generate this file from a PAL BIOS ROM on Mac OS&lt;br /&gt;
        ; or Linux, do the following...&lt;br /&gt;
        ;&lt;br /&gt;
        ;   dd if=7800pal.rom of=ASTEROID.BIN bs=1 count=15933&lt;br /&gt;
        &lt;br /&gt;
        INCBIN &amp;quot;ASTEROID.BIN&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; III. MAIN BIOS LOGIC (EXECUTED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        ORG     $FE3D&lt;br /&gt;
&lt;br /&gt;
; --- Data for Initial Display List ---&lt;br /&gt;
; This data is copied to RAM at RAM_DLL_BASE ($2700) during initialization.&lt;br /&gt;
DisplayList_InitialData:&lt;br /&gt;
        .byte     $00	; DL entry - this is copied to $2700&lt;br /&gt;
        .byte     $40&lt;br /&gt;
        .byte     $F0&lt;br /&gt;
        .byte     $1F&lt;br /&gt;
        .byte     $BB&lt;br /&gt;
        .byte     $00&lt;br /&gt;
        .byte     $00&lt;br /&gt;
&lt;br /&gt;
        .byte     $8F	; DLL entry - this is copied repeatedly at $2707&lt;br /&gt;
        .byte     &amp;gt;RAM_DLL_BASE&lt;br /&gt;
DisplayList_InitialData_End:&lt;br /&gt;
        .byte     &amp;lt;RAM_DLL_BASE&lt;br /&gt;
&lt;br /&gt;
; --- BIOS Entry Point on Power-On/Reset ---&lt;br /&gt;
Bios_EntryPoint_Reset:&lt;br /&gt;
          SEI                            ; Disable interrupts.&lt;br /&gt;
          CLD                            ; Clear decimal mode.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$02                   ; Enable Maria and map BIOS into memory.&lt;br /&gt;
          STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
          LDX     #STACKPTR&lt;br /&gt;
          TXS                            ; Set stack pointer.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$7F&lt;br /&gt;
          STA     CTRL                   ; Turn off Maria DMA.&lt;br /&gt;
          LDA     #$00&lt;br /&gt;
          STA     BACKGRND               ; Set background color to black.&lt;br /&gt;
&lt;br /&gt;
          LDX     #$7F                   ; Copy 2600 mode initialization code to RIOT RAM.&lt;br /&gt;
Bios_Copy2600InitToRam_Loop:&lt;br /&gt;
          LDA     TiaInitCode_2600Mode,X ; Move from ROM...&lt;br /&gt;
          STA     $480,X                 ; ...to RIOT RAM at $0480.&lt;br /&gt;
          DEX&lt;br /&gt;
          BPL     Bios_Copy2600InitToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the main cartridge checking logic from ROM to system RAM.&lt;br /&gt;
        ; This is done so the system can disable the BIOS ROM to read the&lt;br /&gt;
        ; cartridge, while still executing the necessary checker code from RAM.&lt;br /&gt;
        LDX     #[TiaInitCode_2600Mode - RamCode_Start]&lt;br /&gt;
Bios_CopyCartCheckToRam_Loop:&lt;br /&gt;
        LDA     RamCode_Start-1,X&lt;br /&gt;
        STA     RAM_CODE_BASE-1,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     Bios_CopyCartCheckToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        LDA     #0                     ; Zero out all TIA registers.&lt;br /&gt;
        TAX&lt;br /&gt;
Bios_ClearTiaRegs_Loop:&lt;br /&gt;
        STA     1,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2C&lt;br /&gt;
        BNE     Bios_ClearTiaRegs_Loop&lt;br /&gt;
        LDA     #$02                   ; Switch back into Maria mode.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        ; Initialize the first 64 bytes of both RAM chips to $FF.&lt;br /&gt;
        LDA     #$FF&lt;br /&gt;
        LDX     #$3F&lt;br /&gt;
Bios_InitRam_Loop:&lt;br /&gt;
        STA     RAM_BASE_1,X&lt;br /&gt;
        STA     RAM_BASE_2,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_InitRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the initial Display List data to its location in RAM.&lt;br /&gt;
        LDX     #(DisplayList_InitialData_End - DisplayList_InitialData)&lt;br /&gt;
Bios_CopyDisplayList_Loop:&lt;br /&gt;
        LDA     DisplayList_InitialData,X&lt;br /&gt;
        STA     RAM_DLL_BASE,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_CopyDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Replicate the last 3 bytes of the DL data to fill out the list.&lt;br /&gt;
        INX&lt;br /&gt;
        LDY     #80&lt;br /&gt;
Bios_FillDisplayList_Loop:&lt;br /&gt;
        LDA     RAM_DLL_START,X&lt;br /&gt;
        STA     RAM_DLL_START+3,X&lt;br /&gt;
        INX&lt;br /&gt;
        DEY&lt;br /&gt;
        BNE     Bios_FillDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Jump to the cartridge test routine, now located in RAM.&lt;br /&gt;
        JMP     [CartCheck_Start - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; IV. RAM-EXECUTED CODE (COPIED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
; This block of code is not executed from its ROM address. It is copied to&lt;br /&gt;
; system RAM starting at RAM_CODE_BASE ($2300) and executed from there.&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
RamCode_Start: ; (Base address for relative calculations, starts at $FEBD in ROM)&lt;br /&gt;
CartCheck_RunInternalGame:&lt;br /&gt;
        LDA     #$13                   ; Enable BIOS ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
        JMP     StartInternalAsteroidsGame ; Jump to the built-in game.&lt;br /&gt;
&lt;br /&gt;
CartCheck_Start:&lt;br /&gt;
        LDA     #$16                   ; Enable external cartridge ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        LDY     #$FF&lt;br /&gt;
        LDX     #$7F&lt;br /&gt;
; --- Cartridge Presence Test (Floating Bus Check) ---&lt;br /&gt;
; This loop compares the same ROM regions using different base addresses. &lt;br /&gt;
; If no cart is present, the bus will &amp;quot;float&amp;quot; with the last byte of the opcode&lt;br /&gt;
; (due to bus capacitance) and the last byte of the opcode differs in our test. &lt;br /&gt;
; Therefore, if our compared bytes differ, a cart IS NOT present.&lt;br /&gt;
CartCheck_FloatingBus_Loop:&lt;br /&gt;
        LDA     $FE00,X&lt;br /&gt;
        CMP     $FD80,Y&lt;br /&gt;
        BNE     CartCheck_RunInternalGame&lt;br /&gt;
        DEY&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_FloatingBus_Loop&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Reset Vector Test ---&lt;br /&gt;
; A valid cart must have a valid reset vector. $FFFF or $0000 indicates an&lt;br /&gt;
; empty socket or a problem.&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          AND     $FFFD&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines high -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          ORA     $FFFD&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines low -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
; --- Simple 7800 Signature Checks ---&lt;br /&gt;
          LDA     $FFF8                  ; Check region verification byte.&lt;br /&gt;
          ORA     #REGION&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF8&lt;br /&gt;
        EOR     #$F0&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Check Maria signature byte.&lt;br /&gt;
        AND     #$0B                   ; $07 or $03 are valid values.&lt;br /&gt;
        CMP     #$03&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Get bottom of cart address range.&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        CMP     #$40                   ; Make sure it is not below $4000.&lt;br /&gt;
        BCC     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        SBC     #$01                   ; Check that start vector is within cart range.&lt;br /&gt;
        CMP     $FFFD&lt;br /&gt;
        BCS     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
; --- Final Header Check ---&lt;br /&gt;
; This appears to be a final, simple checksum or signature validation.&lt;br /&gt;
        LDA     $1BEA&lt;br /&gt;
        EOR     #$FF&lt;br /&gt;
        STA     $1BEA&lt;br /&gt;
&lt;br /&gt;
        TAY&lt;br /&gt;
        LDX     #$05&lt;br /&gt;
CartCheck_HeaderValidation_Loop:&lt;br /&gt;
        LDA     $FFFA,X&lt;br /&gt;
        CMP     $DFFA,X&lt;br /&gt;
        BNE     CartCheck_HeaderValidation_Fail&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_HeaderValidation_Loop&lt;br /&gt;
&lt;br /&gt;
        CPY     $1BEA&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
CartCheck_HeaderValidation_Fail:&lt;br /&gt;
        LDA     #$02&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
        LDA     #&amp;gt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPH&lt;br /&gt;
        LDA     #&amp;lt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPL                   ; Set Display List pointer.&lt;br /&gt;
        LDA     #$43&lt;br /&gt;
        STA     $78&lt;br /&gt;
        STA     CTRL                   ; Turn graphics on.&lt;br /&gt;
        LDX     #$01&lt;br /&gt;
Util_WaitTwoFrames:&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Util_WaitTwoFrames&lt;br /&gt;
&lt;br /&gt;
        LDA     #$60                   ; Turn off graphics DMA.&lt;br /&gt;
        STA     CTRL&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 7800 Mode ---&lt;br /&gt;
Boot_Enter7800Mode:&lt;br /&gt;
        LDX     #$16                   ; Enable cartridge ROM and Maria.&lt;br /&gt;
        STX     INPTCTRL&lt;br /&gt;
        TXS                            ; Set stack pointer.&lt;br /&gt;
        SED                            ; Set decimal mode.&lt;br /&gt;
        JMP     ($FFFC)                ; Jump to the cartridge's reset vector.&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 2600 Mode ---&lt;br /&gt;
CartCheck_7800Fail_Try2600:&lt;br /&gt;
Boot_Enter2600Mode_FromRam:&lt;br /&gt;
        LDA     #$02                   ; Enable BIOS ROM.&lt;br /&gt;
        STA     INPTCTRL               ; Lock cart in 2600 mode.&lt;br /&gt;
        JMP     $480                   ; Execute 2600 init code from RIOT RAM.&lt;br /&gt;
&lt;br /&gt;
; --- Utility: Wait for Vertical Blank ---&lt;br /&gt;
Util_WaitForVblank:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK ended yet?&lt;br /&gt;
        BMI     Util_WaitForVblank&lt;br /&gt;
Util_WaitForVblank_Start:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK started yet?&lt;br /&gt;
        BPL     Util_WaitForVblank_Start&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
; --- 2600 TIA Setup Code (Copied to and executed from RIOT RAM at $0480) ---&lt;br /&gt;
TiaInitCode_2600Mode:&lt;br /&gt;
        LDA     #0&lt;br /&gt;
        TAX&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
TiaInit_ClearLoop:&lt;br /&gt;
        STA     $03,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2A&lt;br /&gt;
        BNE     TiaInit_ClearLoop&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #4&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        LDX     #4&lt;br /&gt;
TiaInit_DelayLoop:&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     TiaInit_DelayLoop&lt;br /&gt;
        TXS&lt;br /&gt;
        STA     $110&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        STA     $11&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        STA     $1C&lt;br /&gt;
        STA     $F&lt;br /&gt;
        NOP&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        BIT     CXP1FB&lt;br /&gt;
        BMI     TiaInit_SetColors2&lt;br /&gt;
TiaInit_SetColors1:&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUBK&lt;br /&gt;
        STA     $F112&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors2:&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors3&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUP0&lt;br /&gt;
        STA     $F118&lt;br /&gt;
TiaInit_DummyLabel:&lt;br /&gt;
        STA     $F460&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors3:&lt;br /&gt;
        STA     $2C&lt;br /&gt;
        LDA     #$08&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        NOP&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
TiaInit_Finalize:&lt;br /&gt;
        LDA     #$FD&lt;br /&gt;
        STA     8&lt;br /&gt;
        JMP     ($FFFC)&lt;br /&gt;
&lt;br /&gt;
; --- Internal Asteroids Game Startup Logic ---&lt;br /&gt;
; This routine is only called from inside the Asteroids game code.&lt;br /&gt;
Asteroids_InternalSubroutine_Equate = $F444&lt;br /&gt;
Asteroids_InternalSubroutine:&lt;br /&gt;
        JSR     Asteroids_InternalSubroutine_Equate&lt;br /&gt;
        LDA     $82&lt;br /&gt;
        BPL     Asteroids_Sub_SkipZero&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
Asteroids_Sub_SkipZero:&lt;br /&gt;
        ASL&lt;br /&gt;
        ASL&lt;br /&gt;
        CLC&lt;br /&gt;
        ADC     $83&lt;br /&gt;
        STA     $55&lt;br /&gt;
        LDA     #$01&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
StartInternalAsteroidsGame:&lt;br /&gt;
        JSR     Util_WaitForVblank&lt;br /&gt;
StartInternalGame_WaitFrame1:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_WaitFrame1&lt;br /&gt;
        LDA     #$9E&lt;br /&gt;
        LDY     #$00&lt;br /&gt;
        LDX     #$00&lt;br /&gt;
StartInternalGame_WaitFrame2:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_SyncWaitDone&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     StartInternalGame_WaitFrame2&lt;br /&gt;
StartInternalGame_SyncWaitDone:&lt;br /&gt;
        CPX     #$78&lt;br /&gt;
        BCS     StartInternalGame_SetDPPL&lt;br /&gt;
        LDA     #$98&lt;br /&gt;
        LDY     #$2B&lt;br /&gt;
StartInternalGame_SetDPPL:&lt;br /&gt;
        STA     DPPL&lt;br /&gt;
        STY     $2001&lt;br /&gt;
        JMP     $D000                  ; Jump into the Asteroids game code.&lt;br /&gt;
&lt;br /&gt;
        .byte     0,0,0,0,0,0,0,0&lt;br /&gt;
        .byte     0,0&lt;br /&gt;
&lt;br /&gt;
; --- Equates for Asteroids Game Vectors ---&lt;br /&gt;
ASTEROIDS_NMI_VECTOR   EQU     $D2E9&lt;br /&gt;
ASTEROIDS_IRQ_VECTOR   EQU     $D329&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; V. 6502 HARDWARE VECTORS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        .word   ASTEROIDS_NMI_VECTOR	; NMI (DLI handler for Asteroids)&lt;br /&gt;
        .word   Bios_EntryPoint_Reset	; RESET&lt;br /&gt;
        .word   ASTEROIDS_IRQ_VECTOR	; IRQ&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:LLM_Creative_Writing.md&amp;diff=1283</id>
		<title>File:LLM Creative Writing.md</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:LLM_Creative_Writing.md&amp;diff=1283"/>
				<updated>2025-07-28T18:30:20Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: MSaarna uploaded a new version of File:LLM Creative Writing.md&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:LLM_Web_App.md&amp;diff=1282</id>
		<title>File:LLM Web App.md</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:LLM_Web_App.md&amp;diff=1282"/>
				<updated>2025-07-28T18:29:26Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: MSaarna uploaded a new version of File:LLM Web App.md&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:LLM_General_Coding.md&amp;diff=1281</id>
		<title>File:LLM General Coding.md</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:LLM_General_Coding.md&amp;diff=1281"/>
				<updated>2025-07-28T18:28:22Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=LLM_Prompts&amp;diff=1268</id>
		<title>LLM Prompts</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=LLM_Prompts&amp;diff=1268"/>
				<updated>2025-07-26T17:18:17Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following are Markdown-formatted prompt files I’ve developed or enhanced for use with large language models (LLMs). They are tailored to improve task performance in coding, web development, and creative writing.&lt;br /&gt;
&lt;br /&gt;
If your browser opens these files directly rather than downloading them, you may want to right-click the links and choose “Save link as…” to preserve Unicode characters.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_General_Coding.md|LLM_General_Coding.md]] ==&lt;br /&gt;
This general-purpose coding prompt was originally inspired by a Claude community submission. I later refined it in collaboration with ChatGPT, incorporating insights from recent research on prompt engineering to improve its effectiveness.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_Web_App.md|LLM_Web_App.md]] ==&lt;br /&gt;
This variant is tailored for building simple web applications. It instructs the LLM to produce a single self-contained HTML file as output, which I find useful for sharing prototypes. If you prefer a different output format, you can easily modify that directive in the prompt file using a text editor.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_Creative_Writing.md|LLM_Creative_Writing.md]] ==&lt;br /&gt;
This creative writing prompt guides the LLM to take on multiple collaborative writing roles, enhancing ideation, structure, and narrative quality. It's especially helpful for story development and brainstorming sessions.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=LLM_Prompts&amp;diff=1267</id>
		<title>LLM Prompts</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=LLM_Prompts&amp;diff=1267"/>
				<updated>2025-07-26T17:15:48Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;The following are LLM prompts in Markdown file format that I've found useful for certain tasks. If your browser opens up the files directly, you may want to instead right-clic...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following are LLM prompts in Markdown file format that I've found useful for certain tasks. If your browser opens up the files directly, you may want to instead right-click and &amp;quot;save link as...&amp;quot; to preserve the unicode within.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_General_Coding.md|LLM_General_Coding.md]] ==&lt;br /&gt;
This general coding prompt originated as a Claude community prompt, but I worked with ChatGPT to enhance it's effectiveness based on the latest prompt research.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_Web_App.md|LLM_Web_App.md]] ==&lt;br /&gt;
This is a web-app specific version of the general coding prompt. Note that it's directed to produce a single html file as output, which I prefer for easily giving my apps to others. If this isn't suitable in your context, just open the file with a text editor and modify that directive.&lt;br /&gt;
&lt;br /&gt;
== [[Media:LLM_Creative_Writing.md|LLM_Creative_Writing.md]] ==&lt;br /&gt;
This is my creative writing version of the prompt. It has the LLM take on the several collaborative writing roles.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:LLM_Creative_Writing.md&amp;diff=1266</id>
		<title>File:LLM Creative Writing.md</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:LLM_Creative_Writing.md&amp;diff=1266"/>
				<updated>2025-07-26T17:13:57Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:LLM_Web_App.md&amp;diff=1265</id>
		<title>File:LLM Web App.md</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:LLM_Web_App.md&amp;diff=1265"/>
				<updated>2025-07-26T17:07:25Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1263</id>
		<title>7800 PAL BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1263"/>
				<updated>2025-07-24T17:11:40Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 PAL BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Disassembly of the Atari 7800 PAL BIOS&lt;br /&gt;
;&lt;br /&gt;
; - Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; - Mike Saarna&lt;br /&gt;
; - Gemini 2.5 Pro&lt;br /&gt;
;&lt;br /&gt;
; Key differences from the NTSC BIOS:&lt;br /&gt;
;   1. Built-in Game: Includes a full version of Asteroids that runs if no&lt;br /&gt;
;      valid cartridge is detected.&lt;br /&gt;
;   2. No Encryption: Due to 1980s-era export laws, the complex signature&lt;br /&gt;
;      verification from the NTSC BIOS is absent. Cartridge checks are simpler.&lt;br /&gt;
;&lt;br /&gt;
; The code must be assembled with DASM.&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; I. HARDWARE AND MEMORY EQUATES&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
STACKPTR  EQU     $FF&lt;br /&gt;
REGION    EQU     $FE&lt;br /&gt;
&lt;br /&gt;
; --- TIA (Television Interface Adapter) Registers ---&lt;br /&gt;
INPTCTRL  EQU     $01                    ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.&lt;br /&gt;
TIAWSYNC  EQU     $02                    ; TIA's WSYNC, not Maria's&lt;br /&gt;
CXP0FB    EQU     $02                    ; TIA Collision Register&lt;br /&gt;
CXP1FB    EQU     $03                    ; TIA Collision Register&lt;br /&gt;
COLUP0    EQU     $06                    ; TIA P0 Color&lt;br /&gt;
COLUBK    EQU     $09                    ; TIA Background Color&lt;br /&gt;
INPT4     EQU     $0C                    ; Input Port 4 (Joystick Triggers)&lt;br /&gt;
INPT5     EQU     $0D                    ; Input Port 5 (Joystick Triggers)&lt;br /&gt;
AUDC0     EQU     $15                    ; Audio Control 0&lt;br /&gt;
AUDC1     EQU     $16                    ; Audio Control 1&lt;br /&gt;
AUDF0     EQU     $17                    ; Audio Frequency 0&lt;br /&gt;
AUDF1     EQU     $18                    ; Audio Frequency 1&lt;br /&gt;
AUDV0     EQU     $19                    ; Audio Volume 0&lt;br /&gt;
AUDV1     EQU     $1A                    ; Audio Volume 1&lt;br /&gt;
&lt;br /&gt;
; --- Maria (Custom Graphics Chip) Registers ---&lt;br /&gt;
BACKGRND  EQU     $20                    ; Background Color&lt;br /&gt;
P0C1      EQU     $21                    ; Palette 0, Color 1&lt;br /&gt;
P0C2      EQU     $22                    ; Palette 0, Color 2&lt;br /&gt;
P0C3      EQU     $23                    ; Palette 0, Color 3&lt;br /&gt;
WSYNC     EQU     $24                    ; Maria Wait for Sync (halts CPU until horizontal blank)&lt;br /&gt;
P1C1      EQU     $25                    ; Palette 1, Color 1&lt;br /&gt;
P1C2      EQU     $26                    ; Palette 1, Color 2&lt;br /&gt;
P1C3      EQU     $27                    ; Palette 1, Color 3&lt;br /&gt;
MSTAT     EQU     $28                    ; Maria Status Register (VBLANK, etc.)&lt;br /&gt;
P2C1      EQU     $29                    ; Palette 2, Color 1&lt;br /&gt;
P2C2      EQU     $2A                    ; Palette 2, Color 2&lt;br /&gt;
P2C3      EQU     $2B                    ; Palette 2, Color 3&lt;br /&gt;
DPPH      EQU     $2C                    ; Display List Pointer High Byte&lt;br /&gt;
P3C1      EQU     $2D                    ; Palette 3, Color 1&lt;br /&gt;
P3C2      EQU     $2E                    ; Palette 3, Color 2&lt;br /&gt;
P3C3      EQU     $2F                    ; Palette 3, Color 3&lt;br /&gt;
DPPL      EQU     $30                    ; Display List Pointer Low Byte&lt;br /&gt;
P4C1      EQU     $31                    ; Palette 4, Color 1&lt;br /&gt;
P4C2      EQU     $32                    ; Palette 4, Color 2&lt;br /&gt;
P4C3      EQU     $33                    ; Palette 4, Color 3&lt;br /&gt;
CHARBASE  EQU     $34                    ; Character Mode High Pointer&lt;br /&gt;
P5C1      EQU     $35                    ; Palette 5, Color 1&lt;br /&gt;
P5C2      EQU     $36                    ; Palette 5, Color 2&lt;br /&gt;
P5C3      EQU     $37                    ; Palette 5, Color 3&lt;br /&gt;
OFFSET    EQU     $38                    ; Not used by BIOS&lt;br /&gt;
P6C1      EQU     $39                    ; Palette 6, Color 1&lt;br /&gt;
P6C2      EQU     $3A                    ; Palette 6, Color 2&lt;br /&gt;
P6C3      EQU     $3B                    ; Palette 6, Color 3&lt;br /&gt;
CTRL      EQU     $3C                    ; Maria Control Register (DMA, graphics mode)&lt;br /&gt;
P7C1      EQU     $3D                    ; Palette 7, Color 1&lt;br /&gt;
P7C2      EQU     $3E                    ; Palette 7, Color 2&lt;br /&gt;
P7C3      EQU     $3F                    ; Palette 7, Color 3&lt;br /&gt;
&lt;br /&gt;
; --- RAM Address Equates ---&lt;br /&gt;
RAM_BASE_1    EQU $2000&lt;br /&gt;
RAM_BASE_2    EQU $2100&lt;br /&gt;
RAM_CODE_BASE EQU $2300&lt;br /&gt;
RAM_DLL_BASE  EQU $2700&lt;br /&gt;
RAM_DLL_START EQU $2707&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; II. BUILT-IN ASTEROIDS GAME DATA&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
	ORG     $C000&lt;br /&gt;
        ; This directive includes the 15,933 byte ROM image for the built-in&lt;br /&gt;
        ; Asteroids game. To generate this file from a PAL BIOS ROM on Mac OS&lt;br /&gt;
        ; or Linux, do the following...&lt;br /&gt;
        ;&lt;br /&gt;
        ;   dd if=7800pal.rom of=ASTEROID.BIN bs=1 count=15933&lt;br /&gt;
        &lt;br /&gt;
        INCBIN &amp;quot;ASTEROID.BIN&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; III. MAIN BIOS LOGIC (EXECUTED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        ORG     $FE3D&lt;br /&gt;
&lt;br /&gt;
; --- Data for Initial Display List ---&lt;br /&gt;
; This data is copied to RAM at RAM_DLL_BASE ($2700) during initialization.&lt;br /&gt;
DisplayList_InitialData:&lt;br /&gt;
        .byte     $00	; DL entry - this is copied to $2700&lt;br /&gt;
        .byte     $40&lt;br /&gt;
        .byte     $F0&lt;br /&gt;
        .byte     $1F&lt;br /&gt;
        .byte     $BB&lt;br /&gt;
        .byte     $00&lt;br /&gt;
        .byte     $00&lt;br /&gt;
&lt;br /&gt;
        .byte     $8F	; DLL entry - this is copied repeatedly at $2707&lt;br /&gt;
        .byte     &amp;gt;RAM_DLL_BASE&lt;br /&gt;
DisplayList_InitialData_End:&lt;br /&gt;
        .byte     &amp;lt;RAM_DLL_BASE&lt;br /&gt;
&lt;br /&gt;
; --- BIOS Entry Point on Power-On/Reset ---&lt;br /&gt;
Bios_EntryPoint_Reset:&lt;br /&gt;
          SEI                            ; Disable interrupts.&lt;br /&gt;
          CLD                            ; Clear decimal mode.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$02                   ; Enable Maria and map BIOS into memory.&lt;br /&gt;
          STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
          LDX     #STACKPTR&lt;br /&gt;
          TXS                            ; Set stack pointer.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$7F&lt;br /&gt;
          STA     CTRL                   ; Turn off Maria DMA.&lt;br /&gt;
          LDA     #$00&lt;br /&gt;
          STA     BACKGRND               ; Set background color to black.&lt;br /&gt;
&lt;br /&gt;
          LDX     #$7F                   ; Copy 2600 mode initialization code to RIOT RAM.&lt;br /&gt;
Bios_Copy2600InitToRam_Loop:&lt;br /&gt;
          LDA     TiaInitCode_2600Mode,X ; Move from ROM...&lt;br /&gt;
          STA     $480,X                 ; ...to RIOT RAM at $0480.&lt;br /&gt;
          DEX&lt;br /&gt;
          BPL     Bios_Copy2600InitToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the main cartridge checking logic from ROM to system RAM.&lt;br /&gt;
        ; This is done so the system can disable the BIOS ROM to read the&lt;br /&gt;
        ; cartridge, while still executing the necessary checker code from RAM.&lt;br /&gt;
        LDX     #[TiaInitCode_2600Mode - RamCode_Start]&lt;br /&gt;
Bios_CopyCartCheckToRam_Loop:&lt;br /&gt;
        LDA     RamCode_Start-1,X&lt;br /&gt;
        STA     RAM_CODE_BASE-1,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     Bios_CopyCartCheckToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        LDA     #0                     ; Zero out all TIA registers.&lt;br /&gt;
        TAX&lt;br /&gt;
Bios_ClearTiaRegs_Loop:&lt;br /&gt;
        STA     1,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2C&lt;br /&gt;
        BNE     Bios_ClearTiaRegs_Loop&lt;br /&gt;
        LDA     #$02                   ; Switch back into Maria mode.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        ; Initialize the first 64 bytes of both RAM chips to $FF.&lt;br /&gt;
        LDA     #$FF&lt;br /&gt;
        LDX     #$3F&lt;br /&gt;
Bios_InitRam_Loop:&lt;br /&gt;
        STA     RAM_BASE_1,X&lt;br /&gt;
        STA     RAM_BASE_2,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_InitRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the initial Display List data to its location in RAM.&lt;br /&gt;
        LDX     #(DisplayList_InitialData_End - DisplayList_InitialData)&lt;br /&gt;
Bios_CopyDisplayList_Loop:&lt;br /&gt;
        LDA     DisplayList_InitialData,X&lt;br /&gt;
        STA     RAM_DLL_BASE,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_CopyDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Replicate the last 3 bytes of the DL data to fill out the list.&lt;br /&gt;
        INX&lt;br /&gt;
        LDY     #80&lt;br /&gt;
Bios_FillDisplayList_Loop:&lt;br /&gt;
        LDA     RAM_DLL_START,X&lt;br /&gt;
        STA     RAM_DLL_START+3,X&lt;br /&gt;
        INX&lt;br /&gt;
        DEY&lt;br /&gt;
        BNE     Bios_FillDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Jump to the cartridge test routine, now located in RAM.&lt;br /&gt;
        JMP     [CartCheck_Start - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; IV. RAM-EXECUTED CODE (COPIED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
; This block of code is not executed from its ROM address. It is copied to&lt;br /&gt;
; system RAM starting at RAM_CODE_BASE ($2300) and executed from there.&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
RamCode_Start: ; (Base address for relative calculations, starts at $FEBD in ROM)&lt;br /&gt;
CartCheck_RunInternalGame:&lt;br /&gt;
        LDA     #$13                   ; Enable BIOS ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
        JMP     StartInternalAsteroidsGame ; Jump to the built-in game.&lt;br /&gt;
&lt;br /&gt;
CartCheck_Start:&lt;br /&gt;
        LDA     #$16                   ; Enable external cartridge ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        LDY     #$FF&lt;br /&gt;
        LDX     #$7F&lt;br /&gt;
; --- Cartridge Presence Test (Floating Bus Check) ---&lt;br /&gt;
; This loop compares the same ROM regions using different base addresses. &lt;br /&gt;
; If no cart is present, the bus will &amp;quot;float&amp;quot; with the last byte of the opcode&lt;br /&gt;
; which differs in our test. Therefore, if the compared bytes differ, then &lt;br /&gt;
; If a cart IS NOT present.&lt;br /&gt;
CartCheck_FloatingBus_Loop:&lt;br /&gt;
        LDA     $FE00,X&lt;br /&gt;
        CMP     $FD80,Y&lt;br /&gt;
        BNE     CartCheck_RunInternalGame&lt;br /&gt;
        DEY&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_FloatingBus_Loop&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Reset Vector Test ---&lt;br /&gt;
; A valid cart must have a valid reset vector. $FFFF or $0000 indicates an&lt;br /&gt;
; empty socket or a problem.&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          AND     $FFFD&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines high -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          ORA     $FFFD&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines low -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
; --- Simple 7800 Signature Checks ---&lt;br /&gt;
          LDA     $FFF8                  ; Check region verification byte.&lt;br /&gt;
          ORA     #REGION&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF8&lt;br /&gt;
        EOR     #$F0&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Check Maria signature byte.&lt;br /&gt;
        AND     #$0B                   ; $07 or $03 are valid values.&lt;br /&gt;
        CMP     #$03&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Get bottom of cart address range.&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        CMP     #$40                   ; Make sure it is not below $4000.&lt;br /&gt;
        BCC     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        SBC     #$01                   ; Check that start vector is within cart range.&lt;br /&gt;
        CMP     $FFFD&lt;br /&gt;
        BCS     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
; --- Final Header Check ---&lt;br /&gt;
; This appears to be a final, simple checksum or signature validation.&lt;br /&gt;
        LDA     $1BEA&lt;br /&gt;
        EOR     #$FF&lt;br /&gt;
        STA     $1BEA&lt;br /&gt;
&lt;br /&gt;
        TAY&lt;br /&gt;
        LDX     #$05&lt;br /&gt;
CartCheck_HeaderValidation_Loop:&lt;br /&gt;
        LDA     $FFFA,X&lt;br /&gt;
        CMP     $DFFA,X&lt;br /&gt;
        BNE     CartCheck_HeaderValidation_Fail&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_HeaderValidation_Loop&lt;br /&gt;
&lt;br /&gt;
        CPY     $1BEA&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
CartCheck_HeaderValidation_Fail:&lt;br /&gt;
        LDA     #$02&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
        LDA     #&amp;gt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPH&lt;br /&gt;
        LDA     #&amp;lt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPL                   ; Set Display List pointer.&lt;br /&gt;
        LDA     #$43&lt;br /&gt;
        STA     $78&lt;br /&gt;
        STA     CTRL                   ; Turn graphics on.&lt;br /&gt;
        LDX     #$01&lt;br /&gt;
Util_WaitTwoFrames:&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Util_WaitTwoFrames&lt;br /&gt;
&lt;br /&gt;
        LDA     #$60                   ; Turn off graphics DMA.&lt;br /&gt;
        STA     CTRL&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 7800 Mode ---&lt;br /&gt;
Boot_Enter7800Mode:&lt;br /&gt;
        LDX     #$16                   ; Enable cartridge ROM and Maria.&lt;br /&gt;
        STX     INPTCTRL&lt;br /&gt;
        TXS                            ; Set stack pointer.&lt;br /&gt;
        SED                            ; Set decimal mode.&lt;br /&gt;
        JMP     ($FFFC)                ; Jump to the cartridge's reset vector.&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 2600 Mode ---&lt;br /&gt;
CartCheck_7800Fail_Try2600:&lt;br /&gt;
Boot_Enter2600Mode_FromRam:&lt;br /&gt;
        LDA     #$02                   ; Enable BIOS ROM.&lt;br /&gt;
        STA     INPTCTRL               ; Lock cart in 2600 mode.&lt;br /&gt;
        JMP     $480                   ; Execute 2600 init code from RIOT RAM.&lt;br /&gt;
&lt;br /&gt;
; --- Utility: Wait for Vertical Blank ---&lt;br /&gt;
Util_WaitForVblank:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK ended yet?&lt;br /&gt;
        BMI     Util_WaitForVblank&lt;br /&gt;
Util_WaitForVblank_Start:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK started yet?&lt;br /&gt;
        BPL     Util_WaitForVblank_Start&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
; --- 2600 TIA Setup Code (Copied to and executed from RIOT RAM at $0480) ---&lt;br /&gt;
TiaInitCode_2600Mode:&lt;br /&gt;
        LDA     #0&lt;br /&gt;
        TAX&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
TiaInit_ClearLoop:&lt;br /&gt;
        STA     $03,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2A&lt;br /&gt;
        BNE     TiaInit_ClearLoop&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #4&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        LDX     #4&lt;br /&gt;
TiaInit_DelayLoop:&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     TiaInit_DelayLoop&lt;br /&gt;
        TXS&lt;br /&gt;
        STA     $110&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        STA     $11&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        STA     $1C&lt;br /&gt;
        STA     $F&lt;br /&gt;
        NOP&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        BIT     CXP1FB&lt;br /&gt;
        BMI     TiaInit_SetColors2&lt;br /&gt;
TiaInit_SetColors1:&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUBK&lt;br /&gt;
        STA     $F112&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors2:&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors3&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUP0&lt;br /&gt;
        STA     $F118&lt;br /&gt;
TiaInit_DummyLabel:&lt;br /&gt;
        STA     $F460&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors3:&lt;br /&gt;
        STA     $2C&lt;br /&gt;
        LDA     #$08&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        NOP&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
TiaInit_Finalize:&lt;br /&gt;
        LDA     #$FD&lt;br /&gt;
        STA     8&lt;br /&gt;
        JMP     ($FFFC)&lt;br /&gt;
&lt;br /&gt;
; --- Internal Asteroids Game Startup Logic ---&lt;br /&gt;
; This routine is only called from inside the Asteroids game code.&lt;br /&gt;
Asteroids_InternalSubroutine_Equate = $F444&lt;br /&gt;
Asteroids_InternalSubroutine:&lt;br /&gt;
        JSR     Asteroids_InternalSubroutine_Equate&lt;br /&gt;
        LDA     $82&lt;br /&gt;
        BPL     Asteroids_Sub_SkipZero&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
Asteroids_Sub_SkipZero:&lt;br /&gt;
        ASL&lt;br /&gt;
        ASL&lt;br /&gt;
        CLC&lt;br /&gt;
        ADC     $83&lt;br /&gt;
        STA     $55&lt;br /&gt;
        LDA     #$01&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
StartInternalAsteroidsGame:&lt;br /&gt;
        JSR     Util_WaitForVblank&lt;br /&gt;
StartInternalGame_WaitFrame1:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_WaitFrame1&lt;br /&gt;
        LDA     #$9E&lt;br /&gt;
        LDY     #$00&lt;br /&gt;
        LDX     #$00&lt;br /&gt;
StartInternalGame_WaitFrame2:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_SyncWaitDone&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     StartInternalGame_WaitFrame2&lt;br /&gt;
StartInternalGame_SyncWaitDone:&lt;br /&gt;
        CPX     #$78&lt;br /&gt;
        BCS     StartInternalGame_SetDPPL&lt;br /&gt;
        LDA     #$98&lt;br /&gt;
        LDY     #$2B&lt;br /&gt;
StartInternalGame_SetDPPL:&lt;br /&gt;
        STA     DPPL&lt;br /&gt;
        STY     $2001&lt;br /&gt;
        JMP     $D000                  ; Jump into the Asteroids game code.&lt;br /&gt;
&lt;br /&gt;
        .byte     0,0,0,0,0,0,0,0&lt;br /&gt;
        .byte     0,0&lt;br /&gt;
&lt;br /&gt;
; --- Equates for Asteroids Game Vectors ---&lt;br /&gt;
ASTEROIDS_NMI_VECTOR   EQU     $D2E9&lt;br /&gt;
ASTEROIDS_IRQ_VECTOR   EQU     $D329&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; V. 6502 HARDWARE VECTORS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        .word   ASTEROIDS_NMI_VECTOR	; NMI (DLI handler for Asteroids)&lt;br /&gt;
        .word   Bios_EntryPoint_Reset	; RESET&lt;br /&gt;
        .word   ASTEROIDS_IRQ_VECTOR	; IRQ&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1262</id>
		<title>Historic Documents</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1262"/>
				<updated>2025-07-20T20:03:08Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Historic Technical Documents ==&lt;br /&gt;
&lt;br /&gt;
This collection of historical documents centers on the Atari 7800 and its hardware, with many originating from the late Atari historian Curt Vendel. Some materials were publicly available through his Atari Museum website, while others have been preserved from his private archives and are now being shared more widely.&lt;br /&gt;
&lt;br /&gt;
In reverse chronological order:&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_standards.pdf|7800_standards.pdf]] ===&lt;br /&gt;
''Atari's game development standards for programmers, covering items like game options and attract modes. (October 1987)&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_Maria_Specs.pdf|7800_Maria_Specs.pdf]] ===&lt;br /&gt;
''A five-page document outlining Maria's technical specs and architecture. This appears to be a high-level introduction to the Maria chip for customers. (October 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' Page 1 mentions a version of Maria (number 1722) intended for 680X0 series processors.&lt;br /&gt;
* '''Note 2:''' Page 5 notes that the CTRL register's test/forbidden DMA mode “Does not assert HALT,” a detail not known to be documented elsewhere.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_keyboard_programming.pdf|7800_keyboard_programming.pdf]] ===&lt;br /&gt;
''GCC's guide to programming the planned 7800 Prosystem keyboard peripheral. (June 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_ntsc_bios_source_code.pdf|7800_ntsc_bios_source_code.pdf]] ===&lt;br /&gt;
''A rough scan of the 7800's NTSC BIOS source code. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, you might wish to check out the [[7800_NTSC_BIOS]] or [[7800 PAL BIOS]] pages, both of which can build with modern assemblers.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:TIA-Maria_Gate-Level_Logic_Diagrams.pdf|TIA-Maria_Gate-Level_Logic_Diagrams.pdf]] ===&lt;br /&gt;
''This document contains gate level diagrams for the different sections of the planned TIA-Maria hybrid chip. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Gcc1702b_maria_specs.pdf|Gcc1702b_maria_specs.pdf]] ===&lt;br /&gt;
''The Maria Chip Specification acceptance form, meant for sign-off by VCC, GCC, and Atari. (March 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Minnie_Subsystem_Top-Level_Specification_-_GCC-1730_(MGspec_19840221_sjg).pdf|Minnie Subsystem Top-Level Specification – GCC-1730]] ===&lt;br /&gt;
''The top-level specification for the planned &amp;quot;Minnie&amp;quot; in-cart sound chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:MiniGumby_Sound_Synthesis_System,_Analog_Output_Section_Specification_-_GCC_1730_(analog_output_spec_19840203_sjg).pdf|MiniGumby Sound Synthesis – Analog Output Section Specification – GCC-1730]] ===&lt;br /&gt;
''The analog output section specification for the same planned &amp;quot;Minnie&amp;quot; chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_software.pdf|7800_software.pdf]] ===&lt;br /&gt;
''The 7800 Software Guide covers most programming aspects about the 7800.  (??? 1984)''&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, check out the [[7800_Software_Guide]] page instead, which has supplementary information and corrections from the modern era.&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:3600_software_guide.pdf|3600_software_guide.pdf]] ===&lt;br /&gt;
''A document covering programming the 7800, before the 3600 was renamed to the 7800. (October 1983)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip|GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip]] ===&lt;br /&gt;
''The files in this archive appear to represent layout and mask preparation data from various development stages and regional variants of the MARIA chip, including what may be NTSC and PAL configurations. (August 1983)''&lt;br /&gt;
* '''Note 1:''' While some files use the `.GDS` extension, only the &amp;quot;example.gds&amp;quot; file conforms to the standard GDSII (Calma Stream) layout format. See the contained README.txt for more information.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1261</id>
		<title>Historic Documents</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1261"/>
				<updated>2025-07-20T20:02:19Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Historic Technical Documents ==&lt;br /&gt;
&lt;br /&gt;
This collection of historical documents centers on the Atari 7800 and its hardware, with many originating from the late Atari historian Curt Vendel. Some materials were publicly available through his Atari Museum website, while others have been preserved from his private archives and are now being shared more widely.&lt;br /&gt;
&lt;br /&gt;
In reverse chronological order:&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_standards.pdf|7800_standards.pdf]] ===&lt;br /&gt;
''Atari's game development standards for programmers, covering items like game options and attract modes. (October 1987)&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_Maria_Specs.pdf|7800_Maria_Specs.pdf]] ===&lt;br /&gt;
''A five-page document outlining Maria's technical specs and architecture. This appears to be a high-level introduction to the Maria chip for customers. (October 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' Page 1 mentions a version of Maria (number 1722) intended for 680X0 series processors.&lt;br /&gt;
* '''Note 2:''' Page 5 notes that the CTRL register's test/forbidden DMA mode “Does not assert HALT,” a detail not known to be documented elsewhere.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_keyboard_programming.pdf|7800_keyboard_programming.pdf]] ===&lt;br /&gt;
''GCC's guide to programming the planned 7800 Prosystem keyboard peripheral. (June 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_ntsc_bios_source_code.pdf|7800_ntsc_bios_source_code.pdf]] ===&lt;br /&gt;
''A rough scan of the 7800's NTSC BIOS source code. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, you might wish to check out the [[7800_NTSC_BIOS]] page, or the [[7800 PAL BIOS]] page, both of which can build with modern assemblers.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:TIA-Maria_Gate-Level_Logic_Diagrams.pdf|TIA-Maria_Gate-Level_Logic_Diagrams.pdf]] ===&lt;br /&gt;
''This document contains gate level diagrams for the different sections of the planned TIA-Maria hybrid chip. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Gcc1702b_maria_specs.pdf|Gcc1702b_maria_specs.pdf]] ===&lt;br /&gt;
''The Maria Chip Specification acceptance form, meant for sign-off by VCC, GCC, and Atari. (March 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Minnie_Subsystem_Top-Level_Specification_-_GCC-1730_(MGspec_19840221_sjg).pdf|Minnie Subsystem Top-Level Specification – GCC-1730]] ===&lt;br /&gt;
''The top-level specification for the planned &amp;quot;Minnie&amp;quot; in-cart sound chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:MiniGumby_Sound_Synthesis_System,_Analog_Output_Section_Specification_-_GCC_1730_(analog_output_spec_19840203_sjg).pdf|MiniGumby Sound Synthesis – Analog Output Section Specification – GCC-1730]] ===&lt;br /&gt;
''The analog output section specification for the same planned &amp;quot;Minnie&amp;quot; chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_software.pdf|7800_software.pdf]] ===&lt;br /&gt;
''The 7800 Software Guide covers most programming aspects about the 7800.  (??? 1984)''&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, check out the [[7800_Software_Guide]] page instead, which has supplementary information and corrections from the modern era.&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:3600_software_guide.pdf|3600_software_guide.pdf]] ===&lt;br /&gt;
''A document covering programming the 7800, before the 3600 was renamed to the 7800. (October 1983)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip|GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip]] ===&lt;br /&gt;
''The files in this archive appear to represent layout and mask preparation data from various development stages and regional variants of the MARIA chip, including what may be NTSC and PAL configurations. (August 1983)''&lt;br /&gt;
* '''Note 1:''' While some files use the `.GDS` extension, only the &amp;quot;example.gds&amp;quot; file conforms to the standard GDSII (Calma Stream) layout format. See the contained README.txt for more information.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1260</id>
		<title>7800 PAL BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_PAL_BIOS&amp;diff=1260"/>
				<updated>2025-07-20T20:00:58Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;==7800 PAL BIOS==  This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.   &amp;lt;pre&amp;gt;  ; Disasse...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 PAL BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Disassembly of the Atari 7800 PAL BIOS&lt;br /&gt;
;&lt;br /&gt;
; - Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; - Mike Saarna&lt;br /&gt;
; - Gemini 2.5 Pro&lt;br /&gt;
;&lt;br /&gt;
; Key differences from the NTSC BIOS:&lt;br /&gt;
;   1. Built-in Game: Includes a full version of Asteroids that runs if no&lt;br /&gt;
;      valid cartridge is detected.&lt;br /&gt;
;   2. No Encryption: Due to 1980s-era export laws, the complex signature&lt;br /&gt;
;      verification from the NTSC BIOS is absent. Cartridge checks are simpler.&lt;br /&gt;
;&lt;br /&gt;
; The code must be assembled with DASM.&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; I. HARDWARE AND MEMORY EQUATES&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
STACKPTR  EQU     $FF&lt;br /&gt;
REGION    EQU     $FE&lt;br /&gt;
&lt;br /&gt;
; --- TIA (Television Interface Adapter) Registers ---&lt;br /&gt;
INPTCTRL  EQU     $01                    ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.&lt;br /&gt;
TIAWSYNC  EQU     $02                    ; TIA's WSYNC, not Maria's&lt;br /&gt;
CXP0FB    EQU     $02                    ; TIA Collision Register&lt;br /&gt;
CXP1FB    EQU     $03                    ; TIA Collision Register&lt;br /&gt;
COLUP0    EQU     $06                    ; TIA P0 Color&lt;br /&gt;
COLUBK    EQU     $09                    ; TIA Background Color&lt;br /&gt;
INPT4     EQU     $0C                    ; Input Port 4 (Joystick Triggers)&lt;br /&gt;
INPT5     EQU     $0D                    ; Input Port 5 (Joystick Triggers)&lt;br /&gt;
AUDC0     EQU     $15                    ; Audio Control 0&lt;br /&gt;
AUDC1     EQU     $16                    ; Audio Control 1&lt;br /&gt;
AUDF0     EQU     $17                    ; Audio Frequency 0&lt;br /&gt;
AUDF1     EQU     $18                    ; Audio Frequency 1&lt;br /&gt;
AUDV0     EQU     $19                    ; Audio Volume 0&lt;br /&gt;
AUDV1     EQU     $1A                    ; Audio Volume 1&lt;br /&gt;
&lt;br /&gt;
; --- Maria (Custom Graphics Chip) Registers ---&lt;br /&gt;
BACKGRND  EQU     $20                    ; Background Color&lt;br /&gt;
P0C1      EQU     $21                    ; Palette 0, Color 1&lt;br /&gt;
P0C2      EQU     $22                    ; Palette 0, Color 2&lt;br /&gt;
P0C3      EQU     $23                    ; Palette 0, Color 3&lt;br /&gt;
WSYNC     EQU     $24                    ; Maria Wait for Sync (halts CPU until horizontal blank)&lt;br /&gt;
P1C1      EQU     $25                    ; Palette 1, Color 1&lt;br /&gt;
P1C2      EQU     $26                    ; Palette 1, Color 2&lt;br /&gt;
P1C3      EQU     $27                    ; Palette 1, Color 3&lt;br /&gt;
MSTAT     EQU     $28                    ; Maria Status Register (VBLANK, etc.)&lt;br /&gt;
P2C1      EQU     $29                    ; Palette 2, Color 1&lt;br /&gt;
P2C2      EQU     $2A                    ; Palette 2, Color 2&lt;br /&gt;
P2C3      EQU     $2B                    ; Palette 2, Color 3&lt;br /&gt;
DPPH      EQU     $2C                    ; Display List Pointer High Byte&lt;br /&gt;
P3C1      EQU     $2D                    ; Palette 3, Color 1&lt;br /&gt;
P3C2      EQU     $2E                    ; Palette 3, Color 2&lt;br /&gt;
P3C3      EQU     $2F                    ; Palette 3, Color 3&lt;br /&gt;
DPPL      EQU     $30                    ; Display List Pointer Low Byte&lt;br /&gt;
P4C1      EQU     $31                    ; Palette 4, Color 1&lt;br /&gt;
P4C2      EQU     $32                    ; Palette 4, Color 2&lt;br /&gt;
P4C3      EQU     $33                    ; Palette 4, Color 3&lt;br /&gt;
CHARBASE  EQU     $34                    ; Character Mode High Pointer&lt;br /&gt;
P5C1      EQU     $35                    ; Palette 5, Color 1&lt;br /&gt;
P5C2      EQU     $36                    ; Palette 5, Color 2&lt;br /&gt;
P5C3      EQU     $37                    ; Palette 5, Color 3&lt;br /&gt;
OFFSET    EQU     $38                    ; Not used by BIOS&lt;br /&gt;
P6C1      EQU     $39                    ; Palette 6, Color 1&lt;br /&gt;
P6C2      EQU     $3A                    ; Palette 6, Color 2&lt;br /&gt;
P6C3      EQU     $3B                    ; Palette 6, Color 3&lt;br /&gt;
CTRL      EQU     $3C                    ; Maria Control Register (DMA, graphics mode)&lt;br /&gt;
P7C1      EQU     $3D                    ; Palette 7, Color 1&lt;br /&gt;
P7C2      EQU     $3E                    ; Palette 7, Color 2&lt;br /&gt;
P7C3      EQU     $3F                    ; Palette 7, Color 3&lt;br /&gt;
&lt;br /&gt;
; --- RAM Address Equates ---&lt;br /&gt;
RAM_BASE_1    EQU $2000&lt;br /&gt;
RAM_BASE_2    EQU $2100&lt;br /&gt;
RAM_CODE_BASE EQU $2300&lt;br /&gt;
RAM_DLL_BASE  EQU $2700&lt;br /&gt;
RAM_DLL_START EQU $2707&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; II. BUILT-IN ASTEROIDS GAME DATA&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
	ORG     $C000&lt;br /&gt;
        ; This directive includes the 15,933 byte ROM image for the built-in&lt;br /&gt;
        ; Asteroids game. To generate this file from a PAL BIOS ROM on Mac OS&lt;br /&gt;
        ; or Linux, do the following...&lt;br /&gt;
        ;&lt;br /&gt;
        ;   dd if=7800pal.rom of=ASTEROID.BIN bs=1 count=15933&lt;br /&gt;
        &lt;br /&gt;
        INCBIN &amp;quot;ASTEROID.BIN&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; III. MAIN BIOS LOGIC (EXECUTED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        ORG     $FE3D&lt;br /&gt;
&lt;br /&gt;
; --- Data for Initial Display List ---&lt;br /&gt;
; This data is copied to RAM at RAM_DLL_BASE ($2700) during initialization.&lt;br /&gt;
DisplayList_InitialData:&lt;br /&gt;
        .byte     $00	; DL entry - this is copied to $2700&lt;br /&gt;
        .byte     $40&lt;br /&gt;
        .byte     $F0&lt;br /&gt;
        .byte     $1F&lt;br /&gt;
        .byte     $BB&lt;br /&gt;
        .byte     $00&lt;br /&gt;
        .byte     $00&lt;br /&gt;
&lt;br /&gt;
        .byte     $8F	; DLL entry - this is copied repeatedly at $2707&lt;br /&gt;
        .byte     &amp;gt;RAM_DLL_BASE&lt;br /&gt;
DisplayList_InitialData_End:&lt;br /&gt;
        .byte     &amp;lt;RAM_DLL_BASE&lt;br /&gt;
&lt;br /&gt;
; --- BIOS Entry Point on Power-On/Reset ---&lt;br /&gt;
Bios_EntryPoint_Reset:&lt;br /&gt;
          SEI                            ; Disable interrupts.&lt;br /&gt;
          CLD                            ; Clear decimal mode.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$02                   ; Enable Maria and map BIOS into memory.&lt;br /&gt;
          STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
          LDX     #STACKPTR&lt;br /&gt;
          TXS                            ; Set stack pointer.&lt;br /&gt;
&lt;br /&gt;
          LDA     #$7F&lt;br /&gt;
          STA     CTRL                   ; Turn off Maria DMA.&lt;br /&gt;
          LDA     #$00&lt;br /&gt;
          STA     BACKGRND               ; Set background color to black.&lt;br /&gt;
&lt;br /&gt;
          LDX     #$7F                   ; Copy 2600 mode initialization code to RIOT RAM.&lt;br /&gt;
Bios_Copy2600InitToRam_Loop:&lt;br /&gt;
          LDA     TiaInitCode_2600Mode,X ; Move from ROM...&lt;br /&gt;
          STA     $480,X                 ; ...to RIOT RAM at $0480.&lt;br /&gt;
          DEX&lt;br /&gt;
          BPL     Bios_Copy2600InitToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the main cartridge checking logic from ROM to system RAM.&lt;br /&gt;
        ; This is done so the system can disable the BIOS ROM to read the&lt;br /&gt;
        ; cartridge, while still executing the necessary checker code from RAM.&lt;br /&gt;
        LDX     #[TiaInitCode_2600Mode - RamCode_Start]&lt;br /&gt;
Bios_CopyCartCheckToRam_Loop:&lt;br /&gt;
        LDA     RamCode_Start-1,X&lt;br /&gt;
        STA     RAM_CODE_BASE-1,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     Bios_CopyCartCheckToRam_Loop&lt;br /&gt;
&lt;br /&gt;
        LDA     #0                     ; Zero out all TIA registers.&lt;br /&gt;
        TAX&lt;br /&gt;
Bios_ClearTiaRegs_Loop:&lt;br /&gt;
        STA     1,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2C&lt;br /&gt;
        BNE     Bios_ClearTiaRegs_Loop&lt;br /&gt;
        LDA     #$02                   ; Switch back into Maria mode.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        ; Initialize the first 64 bytes of both RAM chips to $FF.&lt;br /&gt;
        LDA     #$FF&lt;br /&gt;
        LDX     #$3F&lt;br /&gt;
Bios_InitRam_Loop:&lt;br /&gt;
        STA     RAM_BASE_1,X&lt;br /&gt;
        STA     RAM_BASE_2,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_InitRam_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Copy the initial Display List data to its location in RAM.&lt;br /&gt;
        LDX     #(DisplayList_InitialData_End - DisplayList_InitialData)&lt;br /&gt;
Bios_CopyDisplayList_Loop:&lt;br /&gt;
        LDA     DisplayList_InitialData,X&lt;br /&gt;
        STA     RAM_DLL_BASE,X&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Bios_CopyDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Replicate the last 3 bytes of the DL data to fill out the list.&lt;br /&gt;
        INX&lt;br /&gt;
        LDY     #80&lt;br /&gt;
Bios_FillDisplayList_Loop:&lt;br /&gt;
        LDA     RAM_DLL_START,X&lt;br /&gt;
        STA     RAM_DLL_START+3,X&lt;br /&gt;
        INX&lt;br /&gt;
        DEY&lt;br /&gt;
        BNE     Bios_FillDisplayList_Loop&lt;br /&gt;
&lt;br /&gt;
        ; Jump to the cartridge test routine, now located in RAM.&lt;br /&gt;
        JMP     [CartCheck_Start - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; IV. RAM-EXECUTED CODE (COPIED FROM ROM)&lt;br /&gt;
;&lt;br /&gt;
; This block of code is not executed from its ROM address. It is copied to&lt;br /&gt;
; system RAM starting at RAM_CODE_BASE ($2300) and executed from there.&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
RamCode_Start: ; (Base address for relative calculations, starts at $FEBD in ROM)&lt;br /&gt;
CartCheck_RunInternalGame:&lt;br /&gt;
        LDA     #$13                   ; Enable BIOS ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
        JMP     StartInternalAsteroidsGame ; Jump to the built-in game.&lt;br /&gt;
&lt;br /&gt;
CartCheck_Start:&lt;br /&gt;
        LDA     #$16                   ; Enable external cartridge ROM and Maria.&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        LDY     #$FF&lt;br /&gt;
        LDX     #$7F&lt;br /&gt;
; --- Cartridge Presence Test (Floating Bus Check) ---&lt;br /&gt;
; This loop compares the same ROM regions using different base addresses. &lt;br /&gt;
; If no cart is present, the bus will &amp;quot;float&amp;quot; with the last byte of the opcode&lt;br /&gt;
; which differs in our test. Therefore, if the compared bytes differ, then &lt;br /&gt;
; If a cart IS NOT present.&lt;br /&gt;
CartCheck_FloatingBus_Loop:&lt;br /&gt;
        LDA     $FE00,X&lt;br /&gt;
        CMP     $FD80,Y&lt;br /&gt;
        BNE     CartCheck_RunInternalGame&lt;br /&gt;
        DEY&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_FloatingBus_Loop&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Reset Vector Test ---&lt;br /&gt;
; A valid cart must have a valid reset vector. $FFFF or $0000 indicates an&lt;br /&gt;
; empty socket or a problem.&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          AND     $FFFD&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines high -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
          LDA     $FFFC&lt;br /&gt;
          ORA     $FFFD&lt;br /&gt;
          BEQ     CartCheck_RunInternalGame ; All lines low -&amp;gt; No cart.&lt;br /&gt;
&lt;br /&gt;
; --- Simple 7800 Signature Checks ---&lt;br /&gt;
          LDA     $FFF8                  ; Check region verification byte.&lt;br /&gt;
          ORA     #REGION&lt;br /&gt;
          CMP     #$FF&lt;br /&gt;
          BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF8&lt;br /&gt;
        EOR     #$F0&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Check Maria signature byte.&lt;br /&gt;
        AND     #$0B                   ; $07 or $03 are valid values.&lt;br /&gt;
        CMP     #$03&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        LDA     $FFF9                  ; Get bottom of cart address range.&lt;br /&gt;
        AND     #$F0&lt;br /&gt;
        CMP     #$40                   ; Make sure it is not below $4000.&lt;br /&gt;
        BCC     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
        SBC     #$01                   ; Check that start vector is within cart range.&lt;br /&gt;
        CMP     $FFFD&lt;br /&gt;
        BCS     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
; --- Final Header Check ---&lt;br /&gt;
; This appears to be a final, simple checksum or signature validation.&lt;br /&gt;
        LDA     $1BEA&lt;br /&gt;
        EOR     #$FF&lt;br /&gt;
        STA     $1BEA&lt;br /&gt;
&lt;br /&gt;
        TAY&lt;br /&gt;
        LDX     #$05&lt;br /&gt;
CartCheck_HeaderValidation_Loop:&lt;br /&gt;
        LDA     $FFFA,X&lt;br /&gt;
        CMP     $DFFA,X&lt;br /&gt;
        BNE     CartCheck_HeaderValidation_Fail&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     CartCheck_HeaderValidation_Loop&lt;br /&gt;
&lt;br /&gt;
        CPY     $1BEA&lt;br /&gt;
        BNE     CartCheck_7800Fail_Try2600&lt;br /&gt;
&lt;br /&gt;
CartCheck_HeaderValidation_Fail:&lt;br /&gt;
        LDA     #$02&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
&lt;br /&gt;
        LDA     #&amp;gt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPH&lt;br /&gt;
        LDA     #&amp;lt;(RAM_DLL_START)&lt;br /&gt;
        STA     DPPL                   ; Set Display List pointer.&lt;br /&gt;
        LDA     #$43&lt;br /&gt;
        STA     $78&lt;br /&gt;
        STA     CTRL                   ; Turn graphics on.&lt;br /&gt;
        LDX     #$01&lt;br /&gt;
Util_WaitTwoFrames:&lt;br /&gt;
        JSR     [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     Util_WaitTwoFrames&lt;br /&gt;
&lt;br /&gt;
        LDA     #$60                   ; Turn off graphics DMA.&lt;br /&gt;
        STA     CTRL&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 7800 Mode ---&lt;br /&gt;
Boot_Enter7800Mode:&lt;br /&gt;
        LDX     #$16                   ; Enable cartridge ROM and Maria.&lt;br /&gt;
        STX     INPTCTRL&lt;br /&gt;
        TXS                            ; Set stack pointer.&lt;br /&gt;
        SED                            ; Set decimal mode.&lt;br /&gt;
        JMP     ($FFFC)                ; Jump to the cartridge's reset vector.&lt;br /&gt;
&lt;br /&gt;
; --- Boot into 2600 Mode ---&lt;br /&gt;
CartCheck_7800Fail_Try2600:&lt;br /&gt;
Boot_Enter2600Mode_FromRam:&lt;br /&gt;
        LDA     #$02                   ; Enable BIOS ROM.&lt;br /&gt;
        STA     INPTCTRL               ; Lock cart in 2600 mode.&lt;br /&gt;
        JMP     $480                   ; Execute 2600 init code from RIOT RAM.&lt;br /&gt;
&lt;br /&gt;
; --- Utility: Wait for Vertical Blank ---&lt;br /&gt;
Util_WaitForVblank:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK ended yet?&lt;br /&gt;
        BMI     Util_WaitForVblank&lt;br /&gt;
Util_WaitForVblank_Start:&lt;br /&gt;
        BIT     MSTAT                  ; Is VBLANK started yet?&lt;br /&gt;
        BPL     Util_WaitForVblank_Start&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
; --- 2600 TIA Setup Code (Copied to and executed from RIOT RAM at $0480) ---&lt;br /&gt;
TiaInitCode_2600Mode:&lt;br /&gt;
        LDA     #0&lt;br /&gt;
        TAX&lt;br /&gt;
        STA     INPTCTRL&lt;br /&gt;
TiaInit_ClearLoop:&lt;br /&gt;
        STA     $03,X&lt;br /&gt;
        INX&lt;br /&gt;
        CPX     #$2A&lt;br /&gt;
        BNE     TiaInit_ClearLoop&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #4&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        LDX     #4&lt;br /&gt;
TiaInit_DelayLoop:&lt;br /&gt;
        DEX&lt;br /&gt;
        BPL     TiaInit_DelayLoop&lt;br /&gt;
        TXS&lt;br /&gt;
        STA     $110&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        STA     $11&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        STA     $1C&lt;br /&gt;
        STA     $F&lt;br /&gt;
        NOP&lt;br /&gt;
        STA     TIAWSYNC&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
        NOP&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
        BIT     CXP1FB&lt;br /&gt;
        BMI     TiaInit_SetColors2&lt;br /&gt;
TiaInit_SetColors1:&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUBK&lt;br /&gt;
        STA     $F112&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors2:&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors3&lt;br /&gt;
        LDA     #2&lt;br /&gt;
        STA     COLUP0&lt;br /&gt;
        STA     $F118&lt;br /&gt;
TiaInit_DummyLabel:&lt;br /&gt;
        STA     $F460&lt;br /&gt;
        BNE     TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors3:&lt;br /&gt;
        STA     $2C&lt;br /&gt;
        LDA     #$08&lt;br /&gt;
        STA     $1B&lt;br /&gt;
        JSR     [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]&lt;br /&gt;
        NOP&lt;br /&gt;
        BIT     CXP0FB&lt;br /&gt;
        BMI     TiaInit_SetColors1&lt;br /&gt;
TiaInit_Finalize:&lt;br /&gt;
        LDA     #$FD&lt;br /&gt;
        STA     8&lt;br /&gt;
        JMP     ($FFFC)&lt;br /&gt;
&lt;br /&gt;
; --- Internal Asteroids Game Startup Logic ---&lt;br /&gt;
; This routine is only called from inside the Asteroids game code.&lt;br /&gt;
Asteroids_InternalSubroutine_Equate = $F444&lt;br /&gt;
Asteroids_InternalSubroutine:&lt;br /&gt;
        JSR     Asteroids_InternalSubroutine_Equate&lt;br /&gt;
        LDA     $82&lt;br /&gt;
        BPL     Asteroids_Sub_SkipZero&lt;br /&gt;
        LDA     #$00&lt;br /&gt;
Asteroids_Sub_SkipZero:&lt;br /&gt;
        ASL&lt;br /&gt;
        ASL&lt;br /&gt;
        CLC&lt;br /&gt;
        ADC     $83&lt;br /&gt;
        STA     $55&lt;br /&gt;
        LDA     #$01&lt;br /&gt;
        RTS&lt;br /&gt;
&lt;br /&gt;
StartInternalAsteroidsGame:&lt;br /&gt;
        JSR     Util_WaitForVblank&lt;br /&gt;
StartInternalGame_WaitFrame1:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_WaitFrame1&lt;br /&gt;
        LDA     #$9E&lt;br /&gt;
        LDY     #$00&lt;br /&gt;
        LDX     #$00&lt;br /&gt;
StartInternalGame_WaitFrame2:&lt;br /&gt;
        BIT     MSTAT&lt;br /&gt;
        BMI     StartInternalGame_SyncWaitDone&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        STA     WSYNC&lt;br /&gt;
        DEX&lt;br /&gt;
        BNE     StartInternalGame_WaitFrame2&lt;br /&gt;
StartInternalGame_SyncWaitDone:&lt;br /&gt;
        CPX     #$78&lt;br /&gt;
        BCS     StartInternalGame_SetDPPL&lt;br /&gt;
        LDA     #$98&lt;br /&gt;
        LDY     #$2B&lt;br /&gt;
StartInternalGame_SetDPPL:&lt;br /&gt;
        STA     DPPL&lt;br /&gt;
        STY     $2001&lt;br /&gt;
        JMP     $D000                  ; Jump into the Asteroids game code.&lt;br /&gt;
&lt;br /&gt;
        .byte     0,0,0,0,0,0,0,0&lt;br /&gt;
        .byte     0,0&lt;br /&gt;
&lt;br /&gt;
; --- Equates for Asteroids Game Vectors ---&lt;br /&gt;
ASTEROIDS_NMI_VECTOR   EQU     $D2E9&lt;br /&gt;
ASTEROIDS_IRQ_VECTOR   EQU     $D329&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; V. 6502 HARDWARE VECTORS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
        .word   ASTEROIDS_NMI_VECTOR	; NMI (DLI handler for Asteroids)&lt;br /&gt;
        .word   Bios_EntryPoint_Reset	; RESET&lt;br /&gt;
        .word   ASTEROIDS_IRQ_VECTOR	; IRQ&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1259</id>
		<title>7800 NTSC BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1259"/>
				<updated>2025-07-20T18:27:34Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 NTSC BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 NTSC BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Disassembly of the Atari 7800 NTSC BIOS (bios7800.bin)&lt;br /&gt;
; Originally disassembled by DiStella v2.0 on Sun Mar 08 20:30:38 1998&lt;br /&gt;
;&lt;br /&gt;
; This version has been heavily commented and refactored for maximum clarity,&lt;br /&gt;
; with generic labels (e.g., LF400) renamed to descriptive ones.&lt;br /&gt;
; The goal is to explain the inner workings of the BIOS for educational&lt;br /&gt;
; and development purposes.&lt;br /&gt;
;&lt;br /&gt;
; Original comments by:&lt;br /&gt;
;   - Keith Henrickson &amp;lt;flipper@phin.com&amp;gt;&lt;br /&gt;
;   - Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
;   - Mike Saarna (dasm fixups, additional comments)&lt;br /&gt;
;   - Gemini 2.5 Pro (semantic meaningful label names, comments galore)&lt;br /&gt;
;&lt;br /&gt;
; The code must be assembled with DASM.&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; I. HARDWARE AND MEMORY EQUATES&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
; --- Misc System Equates ---&lt;br /&gt;
LFD80 = $FD80&lt;br /&gt;
CartKey           = $FF80   ; Start address of the 8-byte cartridge security key&lt;br /&gt;
CartRegion        = $FFF8   ; Cartridge region/signature byte&lt;br /&gt;
CartKeyStartPage  = $FFF9   ; Cartridge ROM start page and signature byte&lt;br /&gt;
CartResetVectorHi = $FFFD   ; High byte of the cartridge's RESET vector address&lt;br /&gt;
LF112             = $F112&lt;br /&gt;
LF118             = $F118&lt;br /&gt;
LF460             = $F460&lt;br /&gt;
LF700             = $F700&lt;br /&gt;
LF800             = $F800&lt;br /&gt;
&lt;br /&gt;
; --- 7800 System Control ---&lt;br /&gt;
INPTCTRL = $01              ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.&lt;br /&gt;
&lt;br /&gt;
; --- TIA (Television Interface Adapter) Registers (for 2600 Mode) ---&lt;br /&gt;
VSYNC   =  $00              ; Vertical Sync&lt;br /&gt;
VBLANK  =  $01              ; Vertical Blank&lt;br /&gt;
WSYNC   =  $02              ; Wait for Horizontal Sync&lt;br /&gt;
RSYNC   =  $03              ; Reset Horizontal Sync Counter&lt;br /&gt;
COLUP0  =  $06              ; Color-Luminance for Player 0&lt;br /&gt;
COLUPF  =  $08              ; Color-Luminance for Playfield&lt;br /&gt;
COLUBK  =  $09              ; Color-Luminance for Background&lt;br /&gt;
PF2     =  $0F              ; Playfield Register 2&lt;br /&gt;
RESP1   =  $11              ; Reset Player 1&lt;br /&gt;
GRP0    =  $1B              ; Player 0 Graphics&lt;br /&gt;
GRP1    =  $1C              ; Player 1 Graphics&lt;br /&gt;
&lt;br /&gt;
; --- Maria (Custom Graphics Chip) Registers ---&lt;br /&gt;
BACKGRND =  $20             ; Background Color&lt;br /&gt;
POC1     =  $21             ; Palette 0, Color 1&lt;br /&gt;
P0C2     =  $22             ; Palette 0, Color 2&lt;br /&gt;
POC3     =  $23             ; Palette 0, Color 3&lt;br /&gt;
MWSYNC   =  $24             ; Maria Wait for Sync&lt;br /&gt;
P1C1     =  $25             ; Palette 1, Color 1&lt;br /&gt;
P1C2     =  $26             ; Palette 1, Color 2&lt;br /&gt;
P1C3     =  $27             ; Palette 1, Color 3&lt;br /&gt;
MSTAT    =  $28             ; Maria Status Register (VBLANK, etc.)&lt;br /&gt;
DPPH     =  $2C             ; Display List Pointer High Byte&lt;br /&gt;
DPPL     =  $30             ; Display List Pointer Low Byte&lt;br /&gt;
CTRL     =  $3C             ; Maria Control Register (DMA, graphics mode)&lt;br /&gt;
&lt;br /&gt;
; --- Zero Page RAM Vectors/Variables ---&lt;br /&gt;
DLIAddr       =  $F4        ; RAM vector for Display List Interrupts (NMI)&lt;br /&gt;
ConsoleRegion =  $FE        ; Console region byte (used in cart verification)&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; II. CARTRIDGE AUTHENTICATION &amp;amp; MODE SWITCHING LOGIC&lt;br /&gt;
;&lt;br /&gt;
; This entire block of code from $F000 to $F880 is not executed from ROM.&lt;br /&gt;
; Instead, it is copied to RAM ($2300-$2700) by the main BIOS init routine&lt;br /&gt;
; at Bios_InitSystem. The jump to $2306 then begins execution from RAM.&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
       ORG $F000&lt;br /&gt;
&lt;br /&gt;
; --- NMI Vector (ROM) ---&lt;br /&gt;
; This is the hardware NMI vector. It immediately jumps to a RAM vector at $F4,&lt;br /&gt;
; which allows the running program (including the BIOS itself) to define its&lt;br /&gt;
; own NMI handler.&lt;br /&gt;
NmiVector_Rom:&lt;br /&gt;
       pha                ; This is the NMI routine.&lt;br /&gt;
       jmp (DLIAddr)      ; Jump to RAM NMI vector.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       ORG $F400&lt;br /&gt;
&lt;br /&gt;
; --- RAM Routine: Cartridge Detection and Authentication ---&lt;br /&gt;
; This code is designed to be executed from RAM starting at address $2300.&lt;br /&gt;
; Its primary job is to determine if a valid, signed 7800 cartridge is&lt;br /&gt;
; present. If it is, the system boots in 7800 mode. If not, it attempts&lt;br /&gt;
; to boot in 2600 mode.&lt;br /&gt;
&lt;br /&gt;
RamExec_Start:&lt;br /&gt;
SwitchTo2600Mode1:&lt;br /&gt;
       jmp    Enter2600Mode           ; Branch to the 2600 mode initialization routine.&lt;br /&gt;
SwitchTo2600Mode2:&lt;br /&gt;
       jmp    Enter2600Mode           ; Branch to the 2600 mode initialization routine.&lt;br /&gt;
&lt;br /&gt;
CartTest:&lt;br /&gt;
       lda    #$16                    ; Value to enable Maria and map in the cartridge ROM.&lt;br /&gt;
       sta    INPTCTRL                ; Switch in cart + enable Maria.&lt;br /&gt;
&lt;br /&gt;
       ldy    #$FF                    ; Initialize Y to $FF.&lt;br /&gt;
       ldx    #$7F                    ; Initialize X to $7F.&lt;br /&gt;
; --- Cartridge Presence Test ---&lt;br /&gt;
; This loop compares two different ROM regions ($FD80-$FDFF and $FE00-$FE7F).&lt;br /&gt;
; If a cartridge is not present, the data bus &amp;quot;floats&amp;quot;, and reading any address&lt;br /&gt;
; might return the last value seen on the bus (or garbage). By comparing two&lt;br /&gt;
; regions that should contain different data, the BIOS can detect this state.&lt;br /&gt;
; If the data is the same, it's likely a floating bus, so no cart is present.&lt;br /&gt;
CartPresenceCheck_Loop:&lt;br /&gt;
       lda    LFE00,X                 ; Read from the $FExx range.&lt;br /&gt;
       cmp    LFD80,Y                 ; Compare with the $FDxx range.&lt;br /&gt;
       bne    SwitchTo2600Mode1       ; If they differ, the test passes (so far). Branch if they are the same (fail).&lt;br /&gt;
       dey                            ;&lt;br /&gt;
       dex                            ;&lt;br /&gt;
       bpl    CartPresenceCheck_Loop  ; Loop for 128 bytes.&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Reset Vector Test ---&lt;br /&gt;
; A valid 7800 or 2600 cart must have a valid reset vector. A vector of $FFFF&lt;br /&gt;
; or $0000 typically indicates an empty socket or a problem.&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       and    CartResetVectorHi       ;&lt;br /&gt;
       cmp    #$FF                    ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is $FFFF, then go 2600.&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       ora    CartResetVectorHi       ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is $0000, then go 2600.&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Signature/Region Verification ---&lt;br /&gt;
; This is a series of simple, quick checks on bytes in the $FFF8-$FFF9 region&lt;br /&gt;
; of the cartridge ROM to see if it looks like an official 7800 cart.&lt;br /&gt;
       lda    CartRegion              ; Read signature byte at $FFF8.&lt;br /&gt;
       ora    #ConsoleRegion          ; OR with the console's region byte ($FE).&lt;br /&gt;
       cmp    #$FF                    ;&lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low-bit of CartRegion=0, then go 2600.&lt;br /&gt;
       lda    CartRegion              ;&lt;br /&gt;
       eor    #$F0                    ; Invert high nibble.&lt;br /&gt;
       and    #$F0                    ; Isolate the high nibble.&lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If high nibble was not originally $F, then go 2600.&lt;br /&gt;
       lda    CartKeyStartPage        ; Read signature byte at $FFF9.&lt;br /&gt;
       and    #$0B                    ;&lt;br /&gt;
       cmp    #$03                    ;&lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low nibble of $FFF9 was not 3 or 7, go 2600.&lt;br /&gt;
&lt;br /&gt;
; --- Cartridge Header Processing ---&lt;br /&gt;
; If the quick checks pass, the BIOS proceeds with the full authentication.&lt;br /&gt;
       lda    CartKeyStartPage        ;&lt;br /&gt;
       and    #$F0                    ; Extract ROM start page from high nibble of $FFF9.&lt;br /&gt;
       sta    $EE                     ; Store it in zero page.&lt;br /&gt;
       sta    $2406                   ; Store it in RAM for the authentication routine.&lt;br /&gt;
       cmp    #$40                    ;&lt;br /&gt;
       bcc    SwitchTo2600Mode2       ; If ROM start page &amp;lt; $40 (i.e., address &amp;lt; $4000), fail.&lt;br /&gt;
       sbc    #$01                    ;&lt;br /&gt;
       cmp    CartResetVectorHi       ; Compare ROM start page with high byte of reset vector.&lt;br /&gt;
       bcs    SwitchTo2600Mode2       ; If start page is &amp;gt;= reset vector high byte, fail.&lt;br /&gt;
       jsr    $2536                   ; If all checks pass, start the full authentication process.&lt;br /&gt;
&lt;br /&gt;
; --- Obfuscated Authentication Code ---&lt;br /&gt;
; The following code is part of the digital signature verification. It involves&lt;br /&gt;
; complex mixing, rotating, and lookup operations on the cartridge's security&lt;br /&gt;
; key and internal BIOS data tables. Its purpose is to be difficult to analyze&lt;br /&gt;
; and replicate. The high-level goal is to compute a hash from the cart key&lt;br /&gt;
; and compare it against an expected result.&lt;br /&gt;
&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       sta    $F0&lt;br /&gt;
       jsr    $241B&lt;br /&gt;
       lda    #$16&lt;br /&gt;
       sta    INPTCTRL&lt;br /&gt;
       ldx    #$00&lt;br /&gt;
       txa&lt;br /&gt;
Auth_RamFillLoop1:&lt;br /&gt;
       sta    $1800,X&lt;br /&gt;
       dex&lt;br /&gt;
       bne    Auth_RamFillLoop1&lt;br /&gt;
       pha&lt;br /&gt;
       ldy    #$7F&lt;br /&gt;
Auth_CopyRomToRamLoop:&lt;br /&gt;
       lda    LFF00,Y&lt;br /&gt;
       sta    $1800,Y&lt;br /&gt;
       dey&lt;br /&gt;
       cpy    #$F8&lt;br /&gt;
       bne    Auth_CopyRomToRamLoop&lt;br /&gt;
       lda    #$2E&lt;br /&gt;
       sta    $2409&lt;br /&gt;
       lda    #$24&lt;br /&gt;
       sta    $240A&lt;br /&gt;
&lt;br /&gt;
Auth_MainLoop1:&lt;br /&gt;
       jsr    $241B&lt;br /&gt;
       pla&lt;br /&gt;
       jsr    $23FF&lt;br /&gt;
       pha&lt;br /&gt;
       inc    $2406&lt;br /&gt;
       lda    $2406&lt;br /&gt;
       cmp    #$FF&lt;br /&gt;
       bne    Auth_MainLoop1&lt;br /&gt;
&lt;br /&gt;
       jsr    $241B&lt;br /&gt;
       jsr    $2412&lt;br /&gt;
       jsr    $2412&lt;br /&gt;
       lda    #$36&lt;br /&gt;
       sta    $2409&lt;br /&gt;
       lda    #$24&lt;br /&gt;
       sta    $240A&lt;br /&gt;
       dec    $2406&lt;br /&gt;
Auth_MainLoop2:&lt;br /&gt;
       jsr    $241B&lt;br /&gt;
       pla&lt;br /&gt;
       jsr    $23FF&lt;br /&gt;
       pha&lt;br /&gt;
       dec    $2406&lt;br /&gt;
       lda    $2406&lt;br /&gt;
       cmp    $EE&lt;br /&gt;
       bcs    Auth_MainLoop2&lt;br /&gt;
       lda    #$60&lt;br /&gt;
       sta    CTRL&lt;br /&gt;
       ldx    #$77&lt;br /&gt;
Auth_XorAndStoreLoop:&lt;br /&gt;
       lda    $1800,X&lt;br /&gt;
       eor    $1850,X&lt;br /&gt;
       eor    $1888,X&lt;br /&gt;
       sta    $1A00,X&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_XorAndStoreLoop&lt;br /&gt;
       lda    $1A00&lt;br /&gt;
       and    #$07&lt;br /&gt;
       sta    $1A00&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       ldx    #$04&lt;br /&gt;
       sta    $1A00,X&lt;br /&gt;
       sta    $2000,X&lt;br /&gt;
&lt;br /&gt;
; --- Final Authentication Check ---&lt;br /&gt;
; After all the cryptographic hashing, this is the final comparison.&lt;br /&gt;
; It compares two blocks of memory in RAM. If they match, the cart is authentic.&lt;br /&gt;
       ldx    #$77&lt;br /&gt;
Auth_FinalCompareLoop:&lt;br /&gt;
       lda    $2000,X                 ; Read from one workspace area.&lt;br /&gt;
       cmp    $1A00,X                 ; Compare with the computed hash.&lt;br /&gt;
       bne    Auth_FailAndSwitchTo2600; If they don't match, authentication fails.&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_FinalCompareLoop   ; Loop until all bytes are compared.&lt;br /&gt;
       jmp    Enter7800Mode           ; AUTHENTICATION PASSED: Jump to 7800 mode init.&lt;br /&gt;
Auth_FailAndSwitchTo2600:&lt;br /&gt;
       jmp    Enter2600Mode           ; AUTHENTICATION FAILED: Jump to 2600 mode init.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; --- Authentication Subroutines ---&lt;br /&gt;
; More opaque subroutines used by the main authentication algorithm.&lt;br /&gt;
Auth_Sub_MixAndLookup_Equate =  $F500&lt;br /&gt;
       ldx    #$00&lt;br /&gt;
Auth_Sub_MixAndLookup_Loop:&lt;br /&gt;
       adc    $1800,X&lt;br /&gt;
       adc    LFF00,X&lt;br /&gt;
       tay&lt;br /&gt;
       lda    $2DD5,Y&lt;br /&gt;
       sta    $1800,X&lt;br /&gt;
       inx&lt;br /&gt;
       bne    Auth_Sub_MixAndLookup_Loop&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
       ldx    #$00&lt;br /&gt;
Auth_Sub_RotateRam_Loop:&lt;br /&gt;
       rol    $1800,X&lt;br /&gt;
       inx&lt;br /&gt;
       bne    Auth_Sub_RotateRam_Loop&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
; Subroutine at $241B - This routine briefly disables the cartridge to access BIOS ROM/RAM.&lt;br /&gt;
       php&lt;br /&gt;
       dec    $F0&lt;br /&gt;
       bpl    Auth_Sub_AccessBios_Done&lt;br /&gt;
       lda    #$02&lt;br /&gt;
       sta    INPTCTRL&lt;br /&gt;
Auth_Sub_AccessBios_WaitLoop:&lt;br /&gt;
       lda    $F0&lt;br /&gt;
       bmi    Auth_Sub_AccessBios_WaitLoop&lt;br /&gt;
       lda    #$16&lt;br /&gt;
       sta    INPTCTRL&lt;br /&gt;
Auth_Sub_AccessBios_Done:&lt;br /&gt;
       plp&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
; --- Authentication Signature Data Tables ---&lt;br /&gt;
; These large blocks of byte data are part of the digital signature scheme.&lt;br /&gt;
; They are used as lookup tables and keys during the verification process.&lt;br /&gt;
AuthData_Table1: .byte $C7,$65,$AB,$CA,$EE,$F7,$83,$09&lt;br /&gt;
AuthData_Table2: .byte $E1,$D0,$92,$67,$62,$B6,$72,$55,$8E,$91,$DC,$C5,$81,$BE,$78,$20&lt;br /&gt;
       .byte $59,$B7,$E6,$3D,$06,$45,$AF,$C8,$08,$31,$38,$D1,$FB,$73,$84,$A9&lt;br /&gt;
       .byte $17,$FC,$34,$87,$A3,$94,$FA,$90,$B8,$ED,$CE,$3B,$5B,$0A,$43,$D9&lt;br /&gt;
       .byte $F3,$53,$82,$B3,$0D,$6D,$5A,$60,$9D,$51,$A7,$B9&lt;br /&gt;
AuthData_Table3: .byte $11,$10,$BC,$E4,$7F,$80,$41,$E7,$E3&lt;br /&gt;
AuthData_Table4: .byte $F6,$56,$26,$35,$EC,$D6,$DF,$0C,$7F,$F4,$9E,$AC,$52,$46,$EF,$CF&lt;br /&gt;
       .byte $BF,$A2,$3F,$A4,$13,$15,$97,$4A,$1C,$B0,$42,$8C,$B1,$05,$58,$80&lt;br /&gt;
       .byte $18,$77,$2B,$02,$3E,$A8,$49,$1A,$6A&lt;br /&gt;
AuthData_Table5: .byte $CB,$6E,$0B,$8A,$EB,$F1,$4F,$14,$79,$8B,$D8,$9F,$9B,$57,$19,$F8&lt;br /&gt;
       .byte $2A,$2D,$76,$0E,$E8,$2E,$4B,$F9,$07,$03,$DE,$93,$16,$7E,$D4,$E5&lt;br /&gt;
       .byte $B2,$F0,$7D,$7A,$DA,$D2,$A1,$CC,$1D,$E0,$5E,$23,$A0,$95,$22,$1E&lt;br /&gt;
       .byte $36,$85,$FE,$1F,$39&lt;br /&gt;
AuthData_Table6: .byte $AA,$89,$96,$AD,$0F,$2F,$C0,$47&lt;br /&gt;
AuthData_Table7: .byte $27,$5D,$24,$EA,$C3,$A5,$F5,$21,$5F,$1B,$40,$8F,$AE,$74,$25,$DD&lt;br /&gt;
       .byte $C1,$7C,$CD,$A6,$70,$D7,$33,$7B,$2C,$75,$BB,$86,$99,$BD,$54&lt;br /&gt;
AuthData_Table8: .byte $9A,$6C,$63,$32,$48,$4C,$8D,$BA&lt;br /&gt;
AuthData_Table9: .byte $5C,$61,$C4,$4E,$29,$37,$12,$C6,$98,$9C,$D5,$69,$6B,$E2,$04,$4D&lt;br /&gt;
       .byte $E9,$C2,$88,$3A,$DB,$64,$01,$44,$6F,$B5,$F2,$30,$28,$FD,$50,$71&lt;br /&gt;
       .byte $3C,$B4,$66,$68,$C9,$D3,$CA,$83,$C7,$AB,$F7,$65,$09,$EE&lt;br /&gt;
&lt;br /&gt;
; --- Main Authentication Routine ($2536) ---&lt;br /&gt;
; This routine is the entry point for the signature verification process.&lt;br /&gt;
; It copies the 128-byte security key from the cartridge ROM into RAM.&lt;br /&gt;
       ldx    #$77      ; ($2536) Start of routine, X=119&lt;br /&gt;
       stx    $E4&lt;br /&gt;
       stx    $E5&lt;br /&gt;
Auth_CopyCartKey_Loop:&lt;br /&gt;
       lda    CartKey,X   ; Read a byte from the cart security key area ($FF80-FFFF).&lt;br /&gt;
       sta    $1901,X           ; Store it in RAM work area 1.&lt;br /&gt;
       sta    $2000,X           ; Store it in RAM work area 2.&lt;br /&gt;
       dex                      ; next byte of key&lt;br /&gt;
       bpl    Auth_CopyCartKey_Loop ; Loop until all 128 bytes are copied.&lt;br /&gt;
&lt;br /&gt;
       lda    #$02      ;&lt;br /&gt;
       sta    INPTCTRL  ; Disable cart ROM to access BIOS routines.&lt;br /&gt;
       jsr    Display_InitLogo ; Initialize Maria for the Fuji logo display.&lt;br /&gt;
       jsr    $257B&lt;br /&gt;
       dec    $F2&lt;br /&gt;
       ldx    #$77&lt;br /&gt;
       stx    $E4&lt;br /&gt;
Auth_CopyInternalKey_Loop:&lt;br /&gt;
       lda    LFED5,X&lt;br /&gt;
       sta    $1901,X&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_CopyInternalKey_Loop&lt;br /&gt;
       lda    $E1&lt;br /&gt;
       sta    $E3&lt;br /&gt;
       jsr    $25E1&lt;br /&gt;
       dec    $F2&lt;br /&gt;
Auth_CopyWorkspace_Start:&lt;br /&gt;
       lda    $E0&lt;br /&gt;
       sta    $2572&lt;br /&gt;
       ldx    #$77&lt;br /&gt;
Auth_CopyWorkspace_Loop:&lt;br /&gt;
       lda    $1800,X&lt;br /&gt;
Auth_CopyWorkspace_Store:&lt;br /&gt;
       sta    $2000,X&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_CopyWorkspace_Loop&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
; --- More Authentication Subroutines ---&lt;br /&gt;
       jsr    $2639   ; ($257B)&lt;br /&gt;
       ldy    $E5&lt;br /&gt;
       iny&lt;br /&gt;
Auth_Sub_KeyProcess_OuterLoop:&lt;br /&gt;
       STY    $E1&lt;br /&gt;
       TYA&lt;br /&gt;
       clc&lt;br /&gt;
       adc    $E2&lt;br /&gt;
       pha&lt;br /&gt;
Auth_Sub_KeyProcess_ClearRam:&lt;br /&gt;
       tax&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       sta    $2671&lt;br /&gt;
Auth_Sub_KeyProcess_ClearRam_Loop:&lt;br /&gt;
       sta    $1800,X&lt;br /&gt;
       dex&lt;br /&gt;
Auth_Sub_KeyProcess_ClearRam_Check:&lt;br /&gt;
       bne    Auth_Sub_KeyProcess_ClearRam_Loop&lt;br /&gt;
       sta    $1800&lt;br /&gt;
Auth_Sub_KeyProcess_SetupCounters:&lt;br /&gt;
       iny&lt;br /&gt;
       STY    $266E&lt;br /&gt;
       STY    $2674&lt;br /&gt;
       STY    $267C&lt;br /&gt;
       STY    $2681&lt;br /&gt;
       ldx    #$00&lt;br /&gt;
Auth_Sub_KeyProcess_InnerLoop:&lt;br /&gt;
       dec    $266E&lt;br /&gt;
       dec    $2674&lt;br /&gt;
       dec    $267C&lt;br /&gt;
       dec    $2681&lt;br /&gt;
       dec    $E1&lt;br /&gt;
       bmi    Auth_Sub_KeyProcess_Done&lt;br /&gt;
Auth_Sub_KeyProcess_BitCheck:&lt;br /&gt;
       ldy    $E1&lt;br /&gt;
       lda    $2000,Y&lt;br /&gt;
       and    $25D9,X&lt;br /&gt;
       beq    Auth_Sub_KeyProcess_NextBit&lt;br /&gt;
       lda    $2662,X&lt;br /&gt;
       sta    $2672&lt;br /&gt;
       jsr    $266A&lt;br /&gt;
Auth_Sub_KeyProcess_NextBit:&lt;br /&gt;
       inx&lt;br /&gt;
       cpx    #$08&lt;br /&gt;
       bmi    Auth_Sub_KeyProcess_BitCheck&lt;br /&gt;
       jmp    $25A4&lt;br /&gt;
Auth_Sub_KeyProcess_Done:&lt;br /&gt;
       pla&lt;br /&gt;
       sta    $E1&lt;br /&gt;
       lda    #$01&lt;br /&gt;
       sta    $E0&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
AuthData_Bitmasks: .byte $01,$02,$04,$08,$10,$20,$40,$80&lt;br /&gt;
&lt;br /&gt;
       jsr    $2639&lt;br /&gt;
       lda    $E3&lt;br /&gt;
       sec&lt;br /&gt;
       sbc    $E4&lt;br /&gt;
       sta    $E0&lt;br /&gt;
       sta    $E1&lt;br /&gt;
       ldx    #$00&lt;br /&gt;
       stx    $1800&lt;br /&gt;
       stx    $268F&lt;br /&gt;
       stx    $26AC&lt;br /&gt;
       dex&lt;br /&gt;
       stx    $26A9&lt;br /&gt;
       stx    $268C&lt;br /&gt;
       stx    $2692&lt;br /&gt;
       stx    $269A&lt;br /&gt;
       stx    $269F&lt;br /&gt;
       ldx    #$07&lt;br /&gt;
       inc    $26A9&lt;br /&gt;
       inc    $268C&lt;br /&gt;
       inc    $2692&lt;br /&gt;
       inc    $269A&lt;br /&gt;
       inc    $269F&lt;br /&gt;
       dec    $E1&lt;br /&gt;
       bmi    Auth_Sub_Op_Done&lt;br /&gt;
Auth_Sub_Op_Loop:&lt;br /&gt;
       lda    $2662,X&lt;br /&gt;
       sta    $2690&lt;br /&gt;
       sta    $26AD&lt;br /&gt;
       jsr    $26A6&lt;br /&gt;
       bcc    Auth_Sub_Op_Next&lt;br /&gt;
       jsr    $2688&lt;br /&gt;
Auth_Sub_Op_Next:&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_Sub_Op_Loop&lt;br /&gt;
       jmp    $2608&lt;br /&gt;
Auth_Sub_Op_Done:&lt;br /&gt;
       lda    $E3&lt;br /&gt;
       sta    $E1&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
       ldx    $E4   ; ($2639)&lt;br /&gt;
       inx&lt;br /&gt;
       stx    $E2&lt;br /&gt;
       ldy    #$00&lt;br /&gt;
       STY    $1900&lt;br /&gt;
Auth_Sub_Rotate_OuterLoop:&lt;br /&gt;
       lda    $2662,Y&lt;br /&gt;
       sta    $2655&lt;br /&gt;
       iny&lt;br /&gt;
       lda    $2662,Y&lt;br /&gt;
       sta    $2659&lt;br /&gt;
       ldx    $E2&lt;br /&gt;
       clc&lt;br /&gt;
Auth_Sub_Rotate_InnerLoop:&lt;br /&gt;
       lda    $1900,X&lt;br /&gt;
       rol&lt;br /&gt;
       sta    $1900,X&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Auth_Sub_Rotate_InnerLoop&lt;br /&gt;
       cpy    #$07&lt;br /&gt;
       bmi    Auth_Sub_Rotate_OuterLoop&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
AuthData_Indices: .byte $19,$1A,$1B,$1C,$1D,$1E,$1F,$21&lt;br /&gt;
&lt;br /&gt;
       ldy    $E2&lt;br /&gt;
       clc&lt;br /&gt;
Auth_Sub_Add_Loop:&lt;br /&gt;
       lda    $1800,Y&lt;br /&gt;
       adc    $1900,Y&lt;br /&gt;
       sta    $1800,Y&lt;br /&gt;
       dey&lt;br /&gt;
       bpl    Auth_Sub_Add_Loop&lt;br /&gt;
       bcc    Auth_Sub_Add_NoCarry&lt;br /&gt;
       lda    $1700,Y&lt;br /&gt;
       adc    #$00&lt;br /&gt;
       sta    $1700,Y&lt;br /&gt;
       dey&lt;br /&gt;
       jmp    $2679&lt;br /&gt;
Auth_Sub_Add_NoCarry:&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
       ldy    $E2&lt;br /&gt;
       sec&lt;br /&gt;
Auth_Sub_Subtract_Loop:&lt;br /&gt;
       lda    $1800,Y&lt;br /&gt;
       sbc    $1900,Y&lt;br /&gt;
       sta    $1800,Y&lt;br /&gt;
       dey&lt;br /&gt;
       bpl    Auth_Sub_Subtract_Loop&lt;br /&gt;
       bcs    Auth_Sub_Subtract_NoBorrow&lt;br /&gt;
       lda    $1700,Y&lt;br /&gt;
       sbc    #$00&lt;br /&gt;
       sta    $1700,Y&lt;br /&gt;
       dey&lt;br /&gt;
       jmp    $2697&lt;br /&gt;
Auth_Sub_Subtract_NoBorrow:&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
       ldy    #$00&lt;br /&gt;
       lda    $1800,Y&lt;br /&gt;
       cmp    $1900,Y&lt;br /&gt;
       beq    Auth_Sub_Compare_Equal&lt;br /&gt;
Auth_Sub_Compare_NotEqual:&lt;br /&gt;
       rts&lt;br /&gt;
&lt;br /&gt;
Auth_Sub_Compare_Equal:&lt;br /&gt;
       cpy    $E2&lt;br /&gt;
       beq    Auth_Sub_Compare_NotEqual&lt;br /&gt;
       iny&lt;br /&gt;
       jmp    $26A8&lt;br /&gt;
&lt;br /&gt;
; --- 7800 Mode Initialization ---&lt;br /&gt;
       ORG $F7B9&lt;br /&gt;
; This label is an equate, not a location. It calculates the correct RAM address&lt;br /&gt;
; for the routine, which is needed by the code executing from RAM.&lt;br /&gt;
; ROM address $F7B9 -&amp;gt; RAM address $26B9. Offset is $D100.&lt;br /&gt;
Enter7800Mode = . - $D100&lt;br /&gt;
Routine_Enter7800Mode:&lt;br /&gt;
       ldx    #$16        ; Enable Maria and Cartridge ROM.&lt;br /&gt;
       stx    INPTCTRL    ; Lock out BIOS, enable cartridge.&lt;br /&gt;
       txs                ; Set up stack pointer.&lt;br /&gt;
       SED                ; Set Decimal Mode (a 7800 convention, often cleared by games).&lt;br /&gt;
       jmp (CartResetVectorLo) ; Jump to the game's starting address on the cartridge.&lt;br /&gt;
&lt;br /&gt;
; --- 2600 Mode Initialization ---&lt;br /&gt;
       ORG $F7C2&lt;br /&gt;
; This label is also an equate to calculate the correct RAM address.&lt;br /&gt;
; ROM address $F7C2 -&amp;gt; RAM address $26C2. Offset is $D100.&lt;br /&gt;
Enter2600Mode = . - $D100&lt;br /&gt;
Routine_Enter2600Mode:&lt;br /&gt;
       lda    #$02        ; Enable 7800 RAM and BIOS ROM.&lt;br /&gt;
       sta    INPTCTRL    ;&lt;br /&gt;
       ldx    #$7F&lt;br /&gt;
; Copy the 2600 TIA setup code from BIOS ROM into RIOT RAM ($0480).&lt;br /&gt;
CopyTiaInitToRam_Loop:&lt;br /&gt;
       lda    TiaInitCode,X&lt;br /&gt;
       sta    $0480,X&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    CopyTiaInitToRam_Loop&lt;br /&gt;
       jmp    $0480       ; Jump to the newly copied code in RIOT RAM to execute it.&lt;br /&gt;
&lt;br /&gt;
; --- 2600 TIA Setup Code (Executed from RIOT RAM at $0480) ---&lt;br /&gt;
TiaInitCode:&lt;br /&gt;
       lda    #$00        ;&lt;br /&gt;
       tax                ;&lt;br /&gt;
       sta    INPTCTRL    ; Disable 7800 RAM/BIOS, giving full control to cart.&lt;br /&gt;
; Clear all TIA registers to put it in a known state.&lt;br /&gt;
TiaInit_ClearLoop:&lt;br /&gt;
       sta    RSYNC,X&lt;br /&gt;
       inx                ;&lt;br /&gt;
       cpx    #$2A        ;&lt;br /&gt;
       bne    TiaInit_ClearLoop&lt;br /&gt;
       sta    WSYNC       ; Wait for horizontal sync.&lt;br /&gt;
       lda    #$04        ;&lt;br /&gt;
       nop                ;&lt;br /&gt;
       bmi    TiaInit_SetColors1&lt;br /&gt;
       ldx    #$04&lt;br /&gt;
TiaInit_DelayLoop:&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    TiaInit_DelayLoop&lt;br /&gt;
       txs&lt;br /&gt;
       sta    $0110&lt;br /&gt;
       jsr    $04CB&lt;br /&gt;
       jsr    $04CB&lt;br /&gt;
       sta    RESP1&lt;br /&gt;
       sta    GRP0&lt;br /&gt;
       sta    GRP1&lt;br /&gt;
       sta    PF2&lt;br /&gt;
       nop&lt;br /&gt;
       sta    WSYNC&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       nop&lt;br /&gt;
       bmi    TiaInit_SetColors1&lt;br /&gt;
       bit    RSYNC&lt;br /&gt;
       bmi    TiaInit_SetColors2&lt;br /&gt;
TiaInit_SetColors1:&lt;br /&gt;
       lda    #$02&lt;br /&gt;
       sta    COLUBK&lt;br /&gt;
       sta    LF112&lt;br /&gt;
       bne    TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors2:&lt;br /&gt;
       bit    WSYNC&lt;br /&gt;
       bmi    TiaInit_SetColors3&lt;br /&gt;
       lda    #$02&lt;br /&gt;
       sta    COLUP0&lt;br /&gt;
       sta    LF118&lt;br /&gt;
       sta    LF460&lt;br /&gt;
       bne    TiaInit_Finalize&lt;br /&gt;
TiaInit_SetColors3:&lt;br /&gt;
       sta    DPPH&lt;br /&gt;
       lda    #$08&lt;br /&gt;
       sta    GRP0&lt;br /&gt;
       jsr    $04CB&lt;br /&gt;
       nop&lt;br /&gt;
       bit    WSYNC&lt;br /&gt;
       bmi    TiaInit_SetColors1&lt;br /&gt;
TiaInit_Finalize:&lt;br /&gt;
       lda    #$FD&lt;br /&gt;
       sta    COLUPF&lt;br /&gt;
       jmp (CartResetVectorLo) ; Jump to the 2600 game's starting address on the cartridge.&lt;br /&gt;
       nop&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; III. BIOS ENTRY, POWER-ON SELF TEST (POST), AND SYSTEM INIT&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
       ORG $F880&lt;br /&gt;
&lt;br /&gt;
; --- Self-Test Failure Handler ---&lt;br /&gt;
; This code is jumped to whenever a POST routine fails. It writes an error&lt;br /&gt;
; code to INPTCTRL, which can be read by external diagnostic hardware.&lt;br /&gt;
Post_FailHandler:&lt;br /&gt;
       lda    #$1D&lt;br /&gt;
       sta    INPTCTRL    ; Enable TIA/Cart/lock out INPTCTRL.&lt;br /&gt;
&lt;br /&gt;
; --- BIOS Entry Point / Cold Start ---&lt;br /&gt;
START:                    ; $F884&lt;br /&gt;
       SEI                ; Disable interrupts on power-on.&lt;br /&gt;
       CLD                ; Clear decimal flag.&lt;br /&gt;
       lda    #$02        ;&lt;br /&gt;
Bios_SetRamAndBios:&lt;br /&gt;
       sta    INPTCTRL    ; Enable 7800 RAM and map BIOS into memory.&lt;br /&gt;
       lda    #$FB        ; Set high byte of NMI vector to $FB.&lt;br /&gt;
       sta    $F5         ;&lt;br /&gt;
       lda    #$12        ; Set low byte of NMI vector to $12.&lt;br /&gt;
       sta    $F4         ; NMI vector is now $FB12 (points to IRQ cleanup).&lt;br /&gt;
       lda    #$7F        ;&lt;br /&gt;
       sta    CTRL        ; Turn off Maria DMA.&lt;br /&gt;
       lda    #$00        ;&lt;br /&gt;
       sta    BACKGRND    ; Set background color to black.&lt;br /&gt;
&lt;br /&gt;
; --- POST: RAM Test 1 (Basic) ---&lt;br /&gt;
; This is a quick test of the two 2KB RAM chips ($2000-$27FF).&lt;br /&gt;
; It writes several patterns to each byte and reads them back.&lt;br /&gt;
       ldx    #$05        ; Loop counter for the 6 test patterns.&lt;br /&gt;
Post_RamTest1_PatternLoop:&lt;br /&gt;
       lda    Post_RamTest_Data,X ; Load a test pattern ($00, $FF, $55, $AA, $69, $0F).&lt;br /&gt;
       ldy    #$00        ; Inner loop counter for 256 bytes.&lt;br /&gt;
Post_RamTest1_PageLoop:&lt;br /&gt;
       sta    $2000,Y     ; Write pattern to first RAM chip.&lt;br /&gt;
       cmp    $2000,Y     ; Read it back and compare.&lt;br /&gt;
       bne    Post_RamTest_Fail1 ; If it fails, branch to error handler.&lt;br /&gt;
       sta    $2100,Y     ; Write pattern to second RAM chip.&lt;br /&gt;
       cmp    $2100,Y     ; Read it back and compare.&lt;br /&gt;
       bne    Post_RamTest_Fail1 ; If it fails, branch to error handler.&lt;br /&gt;
       dey                ;&lt;br /&gt;
       bne    Post_RamTest1_PageLoop ; Loop through all 256 bytes of a page.&lt;br /&gt;
       dex                ;&lt;br /&gt;
       bpl    Post_RamTest1_PatternLoop ; Loop to the next test pattern.&lt;br /&gt;
&lt;br /&gt;
; --- POST: RAM Mirror Test ---&lt;br /&gt;
; Checks that the RAM is correctly mirrored every 256 bytes.&lt;br /&gt;
       lda    #$43        ; Check RAM 0 mirror.&lt;br /&gt;
       sta    $2080       ; Write to $2080.&lt;br /&gt;
       cmp    $80         ; Compare with $0080 (a mirror).&lt;br /&gt;
       bne    Post_RamMirror_Fail ; make sure they match. If not, fail selftest.&lt;br /&gt;
       sta    $2180       ; Check RAM 1 mirror&lt;br /&gt;
       cmp    $0180       ;&lt;br /&gt;
       bne    Post_RamMirror_Fail ; make sure they match. If not, fail selftest.&lt;br /&gt;
       jmp    Post_CpuTest_Start ; continue selftest&lt;br /&gt;
Post_RamMirror_Fail:&lt;br /&gt;
       ldy    #$04        ;&lt;br /&gt;
       jmp    Post_FailHandler ; selftest fail.&lt;br /&gt;
&lt;br /&gt;
; --- POST: RAM Failure Handlers ---&lt;br /&gt;
; These routines are jumped to from the RAM tests to indicate failure.&lt;br /&gt;
Post_RamTest_Fail1:&lt;br /&gt;
       sta    $1800       ; test store and compare&lt;br /&gt;
       cmp    $1800&lt;br /&gt;
       bne    Post_RamTest_Fail3 ; some kind of error code is being determined&lt;br /&gt;
Post_RamTest_Fail2:&lt;br /&gt;
       ldy    #$01&lt;br /&gt;
       jmp    Post_FailHandler&lt;br /&gt;
&lt;br /&gt;
Post_RamTest_Fail_Indirect:&lt;br /&gt;
       ldy    #$02&lt;br /&gt;
       jmp    $F880&lt;br /&gt;
&lt;br /&gt;
Post_RamTest_Fail3:&lt;br /&gt;
       ldy    #$03&lt;br /&gt;
       jmp    Post_FailHandler&lt;br /&gt;
&lt;br /&gt;
; --- POST: RAM Test 2 (Comprehensive) ---&lt;br /&gt;
; This is a more thorough RAM test called later in the boot process. It uses&lt;br /&gt;
; indirect addressing to test all 8 pages of the 4KB RAM.&lt;br /&gt;
Post_RamTest2_Start:&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       sta    $F0         ; Base address low byte pointer.&lt;br /&gt;
       sta    $F2         ;&lt;br /&gt;
       ldy    #$07        ; Loop counter for 8 pages.&lt;br /&gt;
       STY    $F4&lt;br /&gt;
Post_RamTest2_OuterLoop:&lt;br /&gt;
       lda    Post_RamTest_AddrHi1,Y ; Load high byte of address for RAM chip 1.&lt;br /&gt;
       sta    $F1&lt;br /&gt;
       lda    Post_RamTest_AddrHi2,Y ; Load high byte of address for RAM chip 2.&lt;br /&gt;
       sta    $F3&lt;br /&gt;
       ldx    #$05        ; Loop counter for 6 test patterns.&lt;br /&gt;
Post_RamTest2_PatternLoop:&lt;br /&gt;
       lda    Post_RamTest_Data,X ; Load a test pattern.&lt;br /&gt;
Post_RamTest2_InnerLoop:&lt;br /&gt;
       ldy    #$00        ; Inner loop counter for 256 bytes.&lt;br /&gt;
Post_RamTest2_ByteLoop:&lt;br /&gt;
       sta    ($F0),Y     ; Write to RAM 1 via indirect pointer ($F0/$F1).&lt;br /&gt;
       cmp    ($F0),Y     ; Read back and compare.&lt;br /&gt;
       bne    Post_RamTest_Fail2 ; Fail.&lt;br /&gt;
       sta    ($F2),Y     ; Write to RAM 2 via indirect pointer ($F2/$F3).&lt;br /&gt;
       cmp    ($F2),Y     ; Read back and compare.&lt;br /&gt;
       bne    Post_RamTest_Fail_Indirect ; Fail.&lt;br /&gt;
       dey&lt;br /&gt;
       bne    Post_RamTest2_ByteLoop ; Loop through page.&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Post_RamTest2_PatternLoop ; Loop through patterns.&lt;br /&gt;
       dec    $F4&lt;br /&gt;
       ldy    $F4&lt;br /&gt;
       bpl    Post_RamTest2_OuterLoop ; Loop through pages.&lt;br /&gt;
       jmp    Bios_InitSystem ; ram test passed, so jump in here.&lt;br /&gt;
&lt;br /&gt;
; --- RAM Test Data ---&lt;br /&gt;
Post_RamTest_Data: .byte $00,$FF,$55,$AA,$69,$0F&lt;br /&gt;
Post_RamTest_AddrHi1: .byte $22,$23,$24,$25,$26,$27,$22,$23&lt;br /&gt;
Post_RamTest_AddrHi2: .byte $18,$19,$1A,$1B,$1C,$1D,$1E,$1F&lt;br /&gt;
&lt;br /&gt;
Post_CpuTest_Fail:&lt;br /&gt;
       ldy    #$00       ; local place for selftest fail branch target&lt;br /&gt;
       jmp    Post_FailHandler&lt;br /&gt;
&lt;br /&gt;
; --- POST: 6502 CPU Test ---&lt;br /&gt;
; This section exhaustively tests the 6502's instruction set, flags,&lt;br /&gt;
; and addressing modes to ensure the CPU is functioning correctly.&lt;br /&gt;
Post_CpuTest_Start:&lt;br /&gt;
       lda    #$AA       ; test some flags and branches&lt;br /&gt;
       beq    Post_CpuTest_Fail ; test failed&lt;br /&gt;
       bpl    Post_CpuTest_Fail ; test failed&lt;br /&gt;
       bmi    CpuTest_CheckBne ; test passed&lt;br /&gt;
       jmp    Post_CpuTest_Fail ; test failed&lt;br /&gt;
CpuTest_CheckBne:&lt;br /&gt;
       bne    CpuTest_CheckStore ; test passed&lt;br /&gt;
       jmp    Post_CpuTest_Fail ; test failed&lt;br /&gt;
CpuTest_CheckStore:&lt;br /&gt;
       sta    $AA        ; store AA to 00AA&lt;br /&gt;
       cmp    $AA        ; compare it back&lt;br /&gt;
       bne    Post_CpuTest_Fail ; if it doesn't match, selftest fail&lt;br /&gt;
       lda    #$00       ; do some more flag tests&lt;br /&gt;
       bne    Post_CpuTest_Fail ;&lt;br /&gt;
       bmi    Post_CpuTest_Fail ;&lt;br /&gt;
       bpl    CpuTest_CheckBeq ; test passed&lt;br /&gt;
       jmp    Post_CpuTest_Fail ;&lt;br /&gt;
CpuTest_CheckBeq:&lt;br /&gt;
       beq    CpuTest_CheckCmp ; test passed&lt;br /&gt;
       jmp    Post_CpuTest_Fail ;&lt;br /&gt;
CpuTest_CheckCmp:&lt;br /&gt;
       cmp    #$00       ; test the compare instruction&lt;br /&gt;
       bne    Post_CpuTest_Fail ;&lt;br /&gt;
       bcc    Post_CpuTest_Fail ;&lt;br /&gt;
       bcs    CpuTest_CheckCmpBcs ; test passed, since they're equal&lt;br /&gt;
       jmp    Post_CpuTest_Fail ;&lt;br /&gt;
CpuTest_CheckCmpBcs:&lt;br /&gt;
       cmp    #$01       ; compare it to 01&lt;br /&gt;
       bcs    Post_CpuTest_Fail ;&lt;br /&gt;
       bcc    CpuTest_CheckCpx ; A &amp;lt; 01, so carry is clear&lt;br /&gt;
       jmp    Post_CpuTest_Fail ;&lt;br /&gt;
CpuTest_CheckCpx:&lt;br /&gt;
       ldx    #$55       ; test comparisons with the X register&lt;br /&gt;
       cpx    #$56       ;&lt;br /&gt;
       beq    Post_CpuTest_Fail ;&lt;br /&gt;
       stx    $01AA      ;&lt;br /&gt;
       cpx    $01AA      ;&lt;br /&gt;
       bne    Post_CpuTest_Fail ;&lt;br /&gt;
       ldy    $AA        ; and with the Y register.&lt;br /&gt;
       cpy    #$AB       ;&lt;br /&gt;
CpuTest_CheckCpy:&lt;br /&gt;
       beq    Post_CpuTest_Fail ;&lt;br /&gt;
       STY    $0155      ; put some stuff in the stack area to test stack&lt;br /&gt;
       cpy    $0155      ; and then access this data in many different ways&lt;br /&gt;
       bne    Post_CpuTest_Fail ;&lt;br /&gt;
       dex               ;&lt;br /&gt;
       txs               ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       pla               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       txa               ;&lt;br /&gt;
       pha               ;&lt;br /&gt;
       cpx    $0155      ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       TYA               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       tax               ;&lt;br /&gt;
       lda    $0100,X    ;&lt;br /&gt;
       tay               ;&lt;br /&gt;
       cpy    #$55       ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       lda    VSYNC,X    ;&lt;br /&gt;
       cmp    $AA        ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       eor    #$FF       ;&lt;br /&gt;
       sta    $0000,Y    ;&lt;br /&gt;
       cmp    $55        ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       cmp    $0100,Y    ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       cmp    $20AB,X    ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       lda    #$20       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       lda    #$CC       ;&lt;br /&gt;
       sta    $F0        ;&lt;br /&gt;
       sta    ($46,X)    ;&lt;br /&gt;
       cmp    $CC        ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       sta    ($F0),Y    ;&lt;br /&gt;
       cmp    $2121      ;&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central ;&lt;br /&gt;
       lda    #$EE       ; test the indirect jump by setting up a jump&lt;br /&gt;
       sta    $F0        ; to Post_CpuMath_Start&lt;br /&gt;
       lda    #$F9       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       jmp ($00F0)        ; and do it.&lt;br /&gt;
&lt;br /&gt;
CpuTest_ShouldNotBeReached:&lt;br /&gt;
       jmp    Post_CpuTest_Fail_Central&lt;br /&gt;
&lt;br /&gt;
Post_CpuTest_Fail_Central:&lt;br /&gt;
       jmp    Post_CpuTest_Fail&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; --- POST: CPU Math and Logic Tests ---&lt;br /&gt;
Post_CpuMath_Start:&lt;br /&gt;
       lda    #$55       ; now test out the math functions.&lt;br /&gt;
       clc&lt;br /&gt;
       adc    #$55&lt;br /&gt;
       nop&lt;br /&gt;
       bcs    Post_CpuTest_Fail_Central ; test addition.&lt;br /&gt;
       bpl    Post_CpuTest_Fail_Central&lt;br /&gt;
       beq    Post_CpuTest_Fail_Central&lt;br /&gt;
       cmp    #$AA       ; make sure it worked&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central&lt;br /&gt;
       adc    #$55       ; test addition again.&lt;br /&gt;
CpuMath_TestAdcCarry:&lt;br /&gt;
       nop&lt;br /&gt;
       bcc    Post_CpuTest_Fail_Central&lt;br /&gt;
       bmi    Post_CpuTest_Fail_Central&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central&lt;br /&gt;
       sbc    #$55       ; test subtraction&lt;br /&gt;
       bcs    Post_CpuTest_Fail_Central&lt;br /&gt;
       bpl    Post_CpuTest_Fail_Central&lt;br /&gt;
       beq    Post_CpuTest_Fail_Central&lt;br /&gt;
       cmp    #$AB       ; make sure it worked&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central&lt;br /&gt;
       clc&lt;br /&gt;
       sbc    #$AA       ; test subtraction again&lt;br /&gt;
       bcc    Post_CpuTest_Fail_Central&lt;br /&gt;
       bmi    Post_CpuTest_Fail_Central&lt;br /&gt;
       bne    Post_CpuTest_Fail_Central&lt;br /&gt;
       lda    #$FF       ; set up a stack&lt;br /&gt;
       tax               ; and do all kinds of stuff in it for tests&lt;br /&gt;
       inx&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       dex&lt;br /&gt;
       beq    CpuMath_Fail&lt;br /&gt;
       bpl    CpuMath_Fail&lt;br /&gt;
       cpx    #$FF&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       tay&lt;br /&gt;
       iny&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       dey&lt;br /&gt;
       beq    CpuMath_Fail&lt;br /&gt;
       iny&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       sta    $F0&lt;br /&gt;
       inc    $F0&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       cpy    $F0&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       dec    $F0&lt;br /&gt;
       beq    CpuMath_Fail&lt;br /&gt;
       cmp    $F0&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       lda    #$AA&lt;br /&gt;
       clc&lt;br /&gt;
       rol               ; now we get onto the more complex math instrs&lt;br /&gt;
       rol&lt;br /&gt;
       rol&lt;br /&gt;
       cmp    #$52&lt;br /&gt;
       bne    CpuMath_Fail ; make sure rotate left works.&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       cmp    #$AA&lt;br /&gt;
       beq    CpuMath_TestAsl ; test rotate right&lt;br /&gt;
CpuMath_Fail:&lt;br /&gt;
       jmp    Post_CpuTest_Fail ; fail!&lt;br /&gt;
&lt;br /&gt;
CpuMath_TestAsl:&lt;br /&gt;
       asl               ; test arithmetic shift left&lt;br /&gt;
       bcc    CpuMath_Fail&lt;br /&gt;
       asl&lt;br /&gt;
       bcs    CpuMath_Fail&lt;br /&gt;
       asl&lt;br /&gt;
       cmp    #$50&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       eor    #$05&lt;br /&gt;
       lsr               ; and logical shift right&lt;br /&gt;
       bcc    CpuMath_Fail&lt;br /&gt;
       lsr&lt;br /&gt;
       bcs    CpuMath_Fail&lt;br /&gt;
       lsr&lt;br /&gt;
       cmp    #$0A&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       lda    #$55       ; now test the ands and ors.&lt;br /&gt;
       ora    #$1B&lt;br /&gt;
       cmp    #$5F&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       and    #$55&lt;br /&gt;
       and    #$1B&lt;br /&gt;
       cmp    #$11&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       ora    #$55&lt;br /&gt;
       eor    #$1B       ; and the eors&lt;br /&gt;
       cmp    #$4E&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       jsr    Cpu_TestJsr ; test jump subroutine instruction&lt;br /&gt;
       jmp    CpuMath_Fail ; if we return, fail&lt;br /&gt;
&lt;br /&gt;
Cpu_TestJsr:&lt;br /&gt;
       tsx&lt;br /&gt;
       cpx    #$52       ; check stack pointer&lt;br /&gt;
       bne    CpuMath_Fail ; fail if not right&lt;br /&gt;
       pla&lt;br /&gt;
       cmp    #$8D&lt;br /&gt;
       bne    CpuMath_Fail&lt;br /&gt;
       pla&lt;br /&gt;
       cmp    #$FA&lt;br /&gt;
       bne    CpuMath_Fail ; get the old return address off the stack&lt;br /&gt;
       lda    #$F8&lt;br /&gt;
       pha&lt;br /&gt;
       lda    #$E6&lt;br /&gt;
       pha               ; and make our own&lt;br /&gt;
       rts               ; and 'return' to Post_RamTest2_Start&lt;br /&gt;
&lt;br /&gt;
       jmp    CpuMath_Fail ; another jump to catch a failure&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; IV. NMI HANDLER (FUJI LOGO DISPLAY)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
; This NMI routine is responsible for drawing the &amp;quot;Fuji&amp;quot; mountain logo and&lt;br /&gt;
; the &amp;quot;ATARI&amp;quot; text on the screen during the boot-up/authentication process.&lt;br /&gt;
; It is called on every VBLANK. Its main job is to manipulate Maria's palette&lt;br /&gt;
; registers to create the signature color-cycling effect on the Fuji logo.&lt;br /&gt;
&lt;br /&gt;
Nmi_DrawFujiAndAtari:&lt;br /&gt;
       txa          ;Save A&lt;br /&gt;
       pha          ;&lt;br /&gt;
       lda    #$43  ;Setup control register&lt;br /&gt;
       sta    CTRL  ;&lt;br /&gt;
       ldx    #$0F  ; Handle the color scrolling in the FUJI&lt;br /&gt;
       lda    $EF&lt;br /&gt;
       sta    P0C2&lt;br /&gt;
       bit    $F3&lt;br /&gt;
       bvc    Nmi_Sync3&lt;br /&gt;
       bpl    Nmi_Sync2&lt;br /&gt;
Nmi_Sync1:&lt;br /&gt;
       sta    MWSYNC ;Wait for 3 scanlines&lt;br /&gt;
Nmi_Sync2:&lt;br /&gt;
       sta    MWSYNC ;&lt;br /&gt;
Nmi_Sync3:&lt;br /&gt;
       sta    MWSYNC ;&lt;br /&gt;
       sec&lt;br /&gt;
       sbc    #$10&lt;br /&gt;
       cmp    #$10&lt;br /&gt;
       bcs    Nmi_StoreColor&lt;br /&gt;
       sbc    #$0F&lt;br /&gt;
Nmi_StoreColor:&lt;br /&gt;
       sta    P0C2&lt;br /&gt;
       dex&lt;br /&gt;
       bpl    Nmi_Sync1 ;Branch to do next section of fuji&lt;br /&gt;
       ldx    #$40    ;set 160x2/160x4 mode&lt;br /&gt;
       stx    CTRL    ;&lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$0E    ;set Palette 1 color 3&lt;br /&gt;
       sta    P1C3    ;&lt;br /&gt;
       lda    $EF     ;&lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$06    ;set Palette 1 color 1&lt;br /&gt;
       sta    P1C1    ;&lt;br /&gt;
       and    #$F0&lt;br /&gt;
       clc&lt;br /&gt;
       adc    #$40&lt;br /&gt;
       bcc    Nmi_SetPalette1Color2&lt;br /&gt;
       adc    #$0F&lt;br /&gt;
Nmi_SetPalette1Color2:&lt;br /&gt;
       ora    #$03   ;set Palette 1 color 2&lt;br /&gt;
       sta    P1C2&lt;br /&gt;
       dec    $F1&lt;br /&gt;
       bpl    Nmi_RestoreRegs&lt;br /&gt;
       lda    $F3&lt;br /&gt;
       adc    #$60&lt;br /&gt;
       bcc    Nmi_UpdateFrameCounter&lt;br /&gt;
       lda    $EF&lt;br /&gt;
       clc&lt;br /&gt;
       adc    #$10&lt;br /&gt;
       bcc    Nmi_StoreNewBaseColor&lt;br /&gt;
       adc    #$0F&lt;br /&gt;
Nmi_StoreNewBaseColor:&lt;br /&gt;
       sta    $EF&lt;br /&gt;
       lda    $F2&lt;br /&gt;
       sta    $F1&lt;br /&gt;
       lda    #$00&lt;br /&gt;
Nmi_UpdateFrameCounter:&lt;br /&gt;
       sta    $F3&lt;br /&gt;
Nmi_RestoreRegs:&lt;br /&gt;
       lda    #$02&lt;br /&gt;
       sta    $F0&lt;br /&gt;
       pla&lt;br /&gt;
       tax&lt;br /&gt;
       pla&lt;br /&gt;
       rti&lt;br /&gt;
&lt;br /&gt;
Trap_InfiniteLoop:&lt;br /&gt;
       jmp    Trap_InfiniteLoop&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; V. SYSTEM INITIALIZATION (POST-TEST)&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
; This routine is executed after all Power-On Self Tests have passed.&lt;br /&gt;
Bios_InitSystem:&lt;br /&gt;
       ldx    #$FF       ; selftest has passed, start system init&lt;br /&gt;
       txs               ; set up a stack&lt;br /&gt;
       lda    #$00       ; Clear TIA/Maria registers&lt;br /&gt;
       tax               ;&lt;br /&gt;
Bios_ClearRegsLoop:&lt;br /&gt;
       sta    $01,X ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       cpx    #$2C       ;&lt;br /&gt;
       bne    Bios_ClearRegsLoop&lt;br /&gt;
       lda    #$02       ;&lt;br /&gt;
       sta    INPTCTRL   ; Enable 7800 RAM&lt;br /&gt;
       ldx    #$00       ;&lt;br /&gt;
       stx    BACKGRND   ; Set background color&lt;br /&gt;
&lt;br /&gt;
; --- Copy BIOS Routines and Data to RAM ---&lt;br /&gt;
; This is a critical step. It copies the cartridge authentication code,&lt;br /&gt;
; graphics display routines, and associated data from the BIOS ROM&lt;br /&gt;
; into the main system RAM. This allows the BIOS to run its complex&lt;br /&gt;
; authentication logic from RAM, freeing up the cartridge bus.&lt;br /&gt;
Bios_CopyCodeToRam_Loop:&lt;br /&gt;
       lda    RamExec_Start,X ; copy the authentication and title screen to&lt;br /&gt;
       sta    $2300,X    ; ram&lt;br /&gt;
       lda    Auth_Sub_MixAndLookup_Equate,X ;&lt;br /&gt;
       sta    $2400,X    ;&lt;br /&gt;
       lda    AuthData_Table8,X ;&lt;br /&gt;
       sta    $2500,X    ;&lt;br /&gt;
       lda    LF700,X    ;&lt;br /&gt;
       sta    $2600,X    ;&lt;br /&gt;
       lda    LF800,X    ;&lt;br /&gt;
       sta    $2700,X    ;&lt;br /&gt;
       lda    DisplayList_Defs,X ;&lt;br /&gt;
       sta    $2200,X    ;&lt;br /&gt;
       cpx    #$00       ;&lt;br /&gt;
       bmi    Bios_CopyCodeToRam_Done ;&lt;br /&gt;
       lda    DisplayList_Master,X ;&lt;br /&gt;
       sta    $1F84,X     ;&lt;br /&gt;
       lda    GraphicsData_FujiAtari_1,X ;&lt;br /&gt;
       sta    $1984,X     ;&lt;br /&gt;
       lda    LFD3D,X     ;&lt;br /&gt;
       sta    $1A84,X     ;&lt;br /&gt;
       lda    LFDB4,X     ;&lt;br /&gt;
       sta    $1B84,X     ;&lt;br /&gt;
       lda    LFE18,X     ;&lt;br /&gt;
       sta    $1C84,X     ;&lt;br /&gt;
       lda    LFE57,X     ;&lt;br /&gt;
       sta    $1D84,X     ;&lt;br /&gt;
       lda    LFE96,X     ;&lt;br /&gt;
       sta    $1E84,X     ;&lt;br /&gt;
Bios_CopyCodeToRam_Done:&lt;br /&gt;
       dex                ;&lt;br /&gt;
       bne    Bios_CopyCodeToRam_Loop ;&lt;br /&gt;
       jmp    $2306       ; and execute it (CartTest)&lt;br /&gt;
&lt;br /&gt;
;Start display of Atari logo&lt;br /&gt;
Display_InitLogo:&lt;br /&gt;
       lda    CartKeyStartPage      ; Read ROM start byte from cart&lt;br /&gt;
       and    #$04       ; Is rom start greater then $4000?&lt;br /&gt;
       beq    Display_InitLogo_Done ; Branch if not&lt;br /&gt;
       lda    #$03&lt;br /&gt;
       sta    $F1&lt;br /&gt;
       sta    $F2&lt;br /&gt;
       lda    #$49&lt;br /&gt;
       sta    $EF&lt;br /&gt;
       lda    #$66       ;Palette 1 Color 1&lt;br /&gt;
       sta    P1C1       ;&lt;br /&gt;
       lda    #$56       ;Palette 1 Color 2&lt;br /&gt;
       sta    P1C2       ;&lt;br /&gt;
       lda    #$2E       ;Palette 1 Color 3&lt;br /&gt;
       sta    P1C3       ;&lt;br /&gt;
       lda    #$AA       ;Set NMI vector to Nmi_DrawFujiAndAtari&lt;br /&gt;
       sta    $F4        ;&lt;br /&gt;
       lda    #$FA       ;&lt;br /&gt;
       sta    $F5        ;&lt;br /&gt;
Display_WaitForVblankEnd:&lt;br /&gt;
       bit    MSTAT      ;Check VBLANK status&lt;br /&gt;
       bmi    Display_WaitForVblankEnd ;Wait till end of VBLANK&lt;br /&gt;
Display_WaitForVblankStart:&lt;br /&gt;
       bit    MSTAT      ;Check BLANK status&lt;br /&gt;
       bpl    Display_WaitForVblankStart ;Wait for start of next VBLANK&lt;br /&gt;
       lda    #$84       ;Set Display list pointer to $1f84&lt;br /&gt;
       sta    DPPL       ;&lt;br /&gt;
       lda    #$1F       ;&lt;br /&gt;
       sta    DPPH       ;&lt;br /&gt;
       lda    #$43       ;Maria mode = DMA on/320A or 320C&lt;br /&gt;
       sta    CTRL       ;&lt;br /&gt;
Display_InitLogo_Done:&lt;br /&gt;
       rts               ;&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; VI. GRAPHICS DATA AND DISPLAY LISTS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
; --- Display List Definitions for Fuji/Atari Logo ---&lt;br /&gt;
; Each entry defines a block of scanlines, pointing to the graphics data&lt;br /&gt;
; to be displayed. Copied to $2200 in RAM.&lt;br /&gt;
DisplayList_Defs:                       ;$2200&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$1F,$19,$BB            ;$2200   Blank space&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$40,$19,$1F,$BB        ;$2206   First DL on screen&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $85,$1C,$19,$4A            ;$220D   Blank space before Fuji&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $89,$1C,$19,$4A            ;$2213   Fuji line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $8D,$1C,$19,$48            ;$2219   Fuji line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $91,$1B,$19,$46            ;$221F   Fuji line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $96,$19,$19,$42            ;$2225   Fuji line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $9D,$17,$19,$3E            ;$222B   Fuji line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $A6,$17,$19,$3E            ;$2231   Fuji line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1C,$00            ;$2237   Start of Atari&lt;br /&gt;
       .byte $AF,$2C,$1C,$50            ;        and between lines&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1D,$00            ;$2241   End of Atari&lt;br /&gt;
       .byte $AF,$2C,$1D,$50&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$19,$28            ;$224B    Atari line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$19,$28            ;$2251    Atari line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$19,$28            ;$2257     Atari line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $E8,$2D,$19,$28            ;$225D     Atari line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1A,$28            ;$2263     Atari line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1A,$28            ;$2269     Atari line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1A,$28            ;$226F     Atari line 7&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $E8,$2D,$1A,$28            ;$2275     Atari line 8&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1B,$28            ;$227B     Atari line 9&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1B,$28            ;$2281     Atari line 10&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1B,$28            ;$2287     Atari line 11&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
; --- Master Display List for Boot Screen ---&lt;br /&gt;
; This is the main display list that Maria reads. It is a list of pointers&lt;br /&gt;
; to the display list definitions above. Copied to $1F84 in RAM.&lt;br /&gt;
DisplayList_Master:&lt;br /&gt;
       .byte $0F,$22,$06      ;Blank space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $03,$22,$00      ;&lt;br /&gt;
       .byte $85,$22,$0D      ;DLI - Triggers NMI for color cycling&lt;br /&gt;
       .byte $05,$22,$13      ;Draw Fuji&lt;br /&gt;
       .byte $05,$22,$19      ;&lt;br /&gt;
       .byte $05,$22,$1F      ;&lt;br /&gt;
       .byte $05,$22,$25      ;&lt;br /&gt;
       .byte $05,$22,$2B      ;&lt;br /&gt;
       .byte $05,$22,$31      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank area&lt;br /&gt;
       .byte $01,$22,$37      ;Draw &amp;quot;ATARI&amp;quot;&lt;br /&gt;
       .byte $00,$22,$4B      ;Line 1&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$51      ;Line 2&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$57      ;Line 3&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$5D      ;Line 4&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$63      ;Line 5&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$69      ;Line 6&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$6F      ;Line 7&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$75      ;Line 8&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$7B      ;Line 9&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$81      ;Line 10&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$87      ;Line 11&lt;br /&gt;
       .byte $01,$22,$41&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank Space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
&lt;br /&gt;
; --- Fuji/Atari Logo Graphics Data ---&lt;br /&gt;
; These are the raw bitmap graphics for the logo, copied to RAM.&lt;br /&gt;
GraphicsData_FujiAtari_1:&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$fc,$7f,$8f,$c0,$1f,$87,$f8,$7e,$0f,$e0,$7f&lt;br /&gt;
GraphicsData_FujiAtari_2:&lt;br /&gt;
    .byte $81,$fc,$07,$ff,$80,$7f,$80,$7f,$f8,$1f,$ff,$f0,$00,$7f,$80,$03&lt;br /&gt;
GraphicsData_FujiAtari_3:&lt;br /&gt;
    .byte $ff,$fe,$1f,$00,$00,$00,$7f,$80,$00,$00,$3e,$00,$00,$0c,$00,$3f&lt;br /&gt;
GraphicsData_FujiAtari_4:&lt;br /&gt;
    .byte $ff,$ff,$ff,$f0,$00,$c0,$00,$00,$3f,$ff,$ff,$00,$03,$fc,$00,$00&lt;br /&gt;
GraphicsData_FujiAtari_5:&lt;br /&gt;
    .byte $3f,$00,$3f,$ff,$ff,$ff,$f0,$03,$f0,$00,$00,$3f,$ff,$ff,$fc,$03&lt;br /&gt;
GraphicsData_FujiAtari_6:&lt;br /&gt;
    .byte $fc,$00,$00,$ff,$c0,$00,$03,$ff,$00,$00,$0f,$fc,$00,$00,$3f,$f0&lt;br /&gt;
GraphicsData_FujiAtari_7:&lt;br /&gt;
    .byte $03,$ff,$c3,$fc,$00,$03,$ff,$f0,$00,$03,$ff,$00,$00,$3f,$ff,$00&lt;br /&gt;
LFD36:&lt;br /&gt;
    .byte $00,$3f,$f0,$00,$3f,$c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80&lt;br /&gt;
LFD46:&lt;br /&gt;
    .byte $1f,$87,$f8,$7e,$0f,$f0,$7f,$83,$fc,$01,$ff,$80,$7f,$80,$7f,$e0&lt;br /&gt;
LFD56:&lt;br /&gt;
    .byte $1f,$ff,$f8,$00,$7f,$80,$07,$ff,$fe,$1f,$f0,$00,$00,$7f,$80,$00&lt;br /&gt;
LFD66:&lt;br /&gt;
    .byte $03,$fe,$00,$0f,$f3,$fc,$00,$03,$ff,$00,$00,$ff,$3f,$c0,$00,$3f&lt;br /&gt;
LFD76:&lt;br /&gt;
    .byte $f0,$00,$ff,$c3,$fc,$00,$3f,$c0,$ff,$00,$03,$ff,$00,$03,$fc,$0f&lt;br /&gt;
LFD86:&lt;br /&gt;
    .byte $f0,$00,$3f,$f0,$3f,$fc,$03,$fc,$00,$ff,$00,$3f,$c0,$03,$ff,$00&lt;br /&gt;
LFD96:&lt;br /&gt;
    .byte $0f,$f0,$03,$fc,$00,$3f,$f0,$ff,$c0,$03,$fc,$03,$ff,$ff,$ff,$f0&lt;br /&gt;
LFDA6:&lt;br /&gt;
    .byte $03,$ff,$00,$3f,$ff,$ff,$ff,$00,$3f,$f0,$3f,$f0,$03,$fc,$00,$7c&lt;br /&gt;
LFDB6:&lt;br /&gt;
    .byte $7f,$8f,$80,$7c,$7f,$8f,$80,$1f,$87,$f8,$7e,$07,$f0,$7f,$83,$f8&lt;br /&gt;
LFDC6:&lt;br /&gt;
    .byte $00,$ff,$c0,$7f,$80,$ff,$c0,$1f,$ff,$fc,$00,$7f,$80,$0f,$ff,$fe&lt;br /&gt;
LFDD6:&lt;br /&gt;
    .byte $1f,$fc,$00,$00,$7f,$80,$00,$0f,$fe,$0f,$ff,$ff,$ff,$fc,$03,$ff&lt;br /&gt;
LFDE6:&lt;br /&gt;
    .byte $00,$ff,$ff,$ff,$ff,$c0,$3f,$f0,$0f,$fc,$03,$fc,$3f,$f0,$00,$03&lt;br /&gt;
LFDF6:&lt;br /&gt;
    .byte $ff,$03,$ff,$03,$ff,$00,$00,$3f,$f0,$3f&lt;br /&gt;
LFE00:&lt;br /&gt;
    .byte $f0,$03,$ff,$03,$fc,$ff&lt;br /&gt;
LFE06:&lt;br /&gt;
    .byte $c0,$00,$00,$ff,$c3,$ff,$0f,$fc,$00,$00,$0f,$fc,$3f,$f0,$00,$ff&lt;br /&gt;
LFE16:&lt;br /&gt;
    .byte $c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$87,$f8,$7c,$07&lt;br /&gt;
LFE26:&lt;br /&gt;
    .byte $f0,$7f,$83,$f8,$00,$7f,$c0,$7f,$80,$ff,$80,$1f,$ff,$fe,$00,$7f&lt;br /&gt;
LFE36:&lt;br /&gt;
    .byte $80,$1f,$ff,$fe,$1f,$ff,$00,$00,$7f,$80,$00,$3f,$fe,$55,$55,$55&lt;br /&gt;
LFE46:&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55&lt;br /&gt;
LFE56:&lt;br /&gt;
    .byte $55,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f0&lt;br /&gt;
LFE66:&lt;br /&gt;
    .byte $7f,$83,$f0,$00,$3f,$e0,$7f,$81,$ff,$00,$01,$ff,$fe,$00,$7f,$80&lt;br /&gt;
LFE76:&lt;br /&gt;
    .byte $1f,$ff,$e0,$1f,$ff,$c0,$00,$7f,$80,$00,$ff,$fe,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE86:&lt;br /&gt;
    .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE96:&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f8,$7f&lt;br /&gt;
LFEA6:&lt;br /&gt;
    .byte $87,$f0,$00,$1f,$e0,$7f,$81,$fe,$00,$00,$1f,$ff,$00,$7f,$80,$3f&lt;br /&gt;
LFEB6:&lt;br /&gt;
    .byte $fe,$00,$1f,$ff,$e0,$00,$7f,$80,$01,$ff,$fe,$55,$55,$55,$55,$55&lt;br /&gt;
LFEC6:&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$09&lt;br /&gt;
LFED6:&lt;br /&gt;
    .byte $ca,$c9,$c6,$b4,$12,$08,$1b,$60,$58,$81,$4b,$86,$01,$d8,$bf,$d9&lt;br /&gt;
LFEE6:&lt;br /&gt;
    .byte $25,$a0,$7b,$dc,$32,$79,$84,$3b,$7c,$bc,$2f,$e2,$e2,$fa,$8d,$0a&lt;br /&gt;
LFEF6:&lt;br /&gt;
    .byte $00,$3b,$c5,$ec,$af,$2d,$8a,$cd,$06,$93&lt;br /&gt;
LFF00:&lt;br /&gt;
    .byte $6a,$a5,$14,$46,$77,$c4&lt;br /&gt;
LFF06:&lt;br /&gt;
    .byte $6a,$b2,$53,$36,$ef,$8c,$ce,$0c,$a2,$68,$71,$d3,$73,$e8,$f7,$6d&lt;br /&gt;
LFF16:&lt;br /&gt;
    .byte $06,$b5,$20,$ef,$23,$47,$0c,$51,$55,$c8,$fe,$f4,$58,$c4,$3f,$20&lt;br /&gt;
LFF26:&lt;br /&gt;
    .byte $a7,$67,$38,$b0,$76,$e2,$c4,$d8,$05,$63,$f8,$3c,$58,$3b,$2d,$22&lt;br /&gt;
LFF36:&lt;br /&gt;
    .byte $cc,$88,$b3,$71,$8f,$1d,$80,$0a,$87,$bd,$a1,$59,$23,$e9,$70,$e2&lt;br /&gt;
LFF46:&lt;br /&gt;
    .byte $d3,$ec,$46,$68,$80,$42,$39,$ea,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF56:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF66:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF76:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF86:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF96:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFA6:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFB6:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFC6:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFD6:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFE6:&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LFD3D = $FD3D&lt;br /&gt;
LFDB4 = $FDB4&lt;br /&gt;
LFDD5 = $FDD5&lt;br /&gt;
LFE18 = $FE18&lt;br /&gt;
LFE57 = $FE57&lt;br /&gt;
LFE84 = $FE84&lt;br /&gt;
LFE96 = $FE96&lt;br /&gt;
LFED5 = $FED5&lt;br /&gt;
LFF00 = $FF00&lt;br /&gt;
&lt;br /&gt;
GccCopyright:&lt;br /&gt;
       .byte $47,$43,$43,$28,$43,$29 ; 'GCC(C)'&lt;br /&gt;
       .byte $31,$39,$38,$34,$2D,$F7 ; '1984-'&lt;br /&gt;
&lt;br /&gt;
;=============================================================================&lt;br /&gt;
;&lt;br /&gt;
; VII. 6502 HARDWARE VECTORS&lt;br /&gt;
;&lt;br /&gt;
;=============================================================================&lt;br /&gt;
&lt;br /&gt;
; These are the processor's hard-wired vectors at the top of memory.&lt;br /&gt;
; The BIOS uses these to direct the CPU on NMI, Reset, and IRQ events.&lt;br /&gt;
; When a cartridge is mapped in, its own vectors at these locations are used.&lt;br /&gt;
&lt;br /&gt;
CartNMIVectorLo:&lt;br /&gt;
       .byte $00,$F0 ; System NMI vector points to NmiVector_Rom.&lt;br /&gt;
CartResetVectorLo:&lt;br /&gt;
       .word START   ; System RESET vector points to $F884.&lt;br /&gt;
CartIRQVectorLo:&lt;br /&gt;
       .byte $33,$F9 ; System IRQ vector.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1258</id>
		<title>7800 NTSC BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1258"/>
				<updated>2025-07-20T17:44:15Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 NTSC BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 NTSC BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Disassembly of bios7800.bin&lt;br /&gt;
; Disassembled Sun Mar 08 20:30:38 1998&lt;br /&gt;
; Using DiStella v2.0&lt;br /&gt;
;&lt;br /&gt;
; Comments added by Keith Henrickson &amp;lt;flipper@phin.com&amp;gt;&lt;br /&gt;
; Further commented by Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; Fixed to compile correctly with dasm, and additional comments by &lt;br /&gt;
; Mike Saarna. You can't have my email!&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
; some misc equates&lt;br /&gt;
LFD80 = $FD80&lt;br /&gt;
CartKey           = $FF80&lt;br /&gt;
CartRegion        = $FFF8&lt;br /&gt;
CartKeyStartPage  = $FFF9&lt;br /&gt;
CartResetVectorHi = $FFFD&lt;br /&gt;
LF112 = $F112&lt;br /&gt;
LF118 = $F118&lt;br /&gt;
LF460   =   $F460&lt;br /&gt;
LF700   =   $F700&lt;br /&gt;
LF800   =   $F800&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 7800 system&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01&lt;br /&gt;
&lt;br /&gt;
; TIA&lt;br /&gt;
&lt;br /&gt;
VSYNC   =  $00&lt;br /&gt;
VBLANK  =  $01&lt;br /&gt;
WSYNC   =  $02&lt;br /&gt;
RSYNC   =  $03&lt;br /&gt;
COLUP0  =  $06&lt;br /&gt;
COLUPF  =  $08&lt;br /&gt;
COLUBK  =  $09&lt;br /&gt;
PF2     =  $0F&lt;br /&gt;
RESP1   =  $11&lt;br /&gt;
GRP0    =  $1B&lt;br /&gt;
GRP1    =  $1C&lt;br /&gt;
&lt;br /&gt;
;Maria&lt;br /&gt;
&lt;br /&gt;
BACKGRND =  $20&lt;br /&gt;
POC1     =  $21&lt;br /&gt;
P0C2     =  $22&lt;br /&gt;
POC3     =  $23&lt;br /&gt;
MWSYNC   =  $24&lt;br /&gt;
P1C1     =  $25&lt;br /&gt;
P1C2     =  $26&lt;br /&gt;
P1C3     =  $27&lt;br /&gt;
MSTAT    =  $28&lt;br /&gt;
DPPH     =  $2C&lt;br /&gt;
DPPL     =  $30&lt;br /&gt;
CTRL     =  $3C&lt;br /&gt;
&lt;br /&gt;
DLIAddr       =  $F4&lt;br /&gt;
ConsoleRegion = $FE&lt;br /&gt;
&lt;br /&gt;
       ORG $F000&lt;br /&gt;
&lt;br /&gt;
LF000: pha                ; This is the NMI routine.&lt;br /&gt;
       jmp (DLIAddr)      ; RAM NMI vector&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       ORG $F400&lt;br /&gt;
&lt;br /&gt;
; this code is designed to be executed while stored in ram at 2300.&lt;br /&gt;
LF400&lt;br /&gt;
SwitchTo2600Mode1&lt;br /&gt;
       jmp    $26C2                   ; Enter 2600 mode.&lt;br /&gt;
SwitchTo2600Mode2&lt;br /&gt;
       jmp    $26C2                   ; Enter 2600 mode.&lt;br /&gt;
&lt;br /&gt;
CartTest&lt;br /&gt;
       lda    #$16                    ; ($2306)&lt;br /&gt;
       sta    INPTCTRL                ; Switch in cart + enable Maria&lt;br /&gt;
&lt;br /&gt;
       ldy    #$FF                    ;&lt;br /&gt;
       ldx    #$7F                    ;&lt;br /&gt;
CartTestLoop&lt;br /&gt;
       lda    LFE00,X                 ; Compare same FE7F+ ROM with differing opcodes, &lt;br /&gt;
       cmp    LFD80,Y                 ;    to avoid false positives from a floating bus.&lt;br /&gt;
       bne    SwitchTo2600Mode1       ; Switch to 2600 mode&lt;br /&gt;
       dey                            ;&lt;br /&gt;
       dex                            ;&lt;br /&gt;
       bpl    CartTestLoop&lt;br /&gt;
&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       and    CartResetVectorHi       ;&lt;br /&gt;
       cmp    #$FF                    ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is FFFF, then go 2600.&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       ora    CartResetVectorHi       ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is 0000, then go 2600.&lt;br /&gt;
       lda    CartRegion              ; &amp;quot;Region verification&amp;quot;&lt;br /&gt;
       ora    #ConsoleRegion&lt;br /&gt;
       cmp    #$FF                    ; &lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low-bit of CartRegion=0, then go 2600.&lt;br /&gt;
       lda    CartRegion              ;&lt;br /&gt;
       eor    #$F0                    ; Invert high nibble&lt;br /&gt;
       and    #$F0                    ; Extract high nibble&lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If high nibble was not F, then go 2600.&lt;br /&gt;
       lda    CartKeyStartPage        ;&lt;br /&gt;
       and    #$0B                    ; &lt;br /&gt;
       cmp    #$03                    ; &lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low nibble FFF9 was not 3 or 7, go 2600.&lt;br /&gt;
       lda    CartKeyStartPage        ;&lt;br /&gt;
       and    #$F0                    ; Extract ROM start from high nibble&lt;br /&gt;
       sta    $EE                     ; Store it &lt;br /&gt;
       sta    $2406                   ; Store it a couple of places for auth. (whocares)&lt;br /&gt;
       cmp    #$40                    ;&lt;br /&gt;
       bcc    SwitchTo2600Mode2       ; If ROM start &amp;lt; than 4, then go 2600&lt;br /&gt;
       sbc    #$01                    ; Subtract 1.&lt;br /&gt;
       cmp    CartResetVectorHi       ; High byte of reset vector&lt;br /&gt;
       bcs    SwitchTo2600Mode2       ; If high-byte of start is &amp;gt;=, go 2600&lt;br /&gt;
       jsr    $2536                   ; Start the authentication process.&lt;br /&gt;
&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       lda    #$16    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
       txa            &lt;br /&gt;
LF46D: sta    $1800,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bne    LF46D   &lt;br /&gt;
       pha            &lt;br /&gt;
       ldy    #$7F    &lt;br /&gt;
LF476: lda    LFF00,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       cpy    #$F8    &lt;br /&gt;
       bne    LF476   &lt;br /&gt;
       lda    #$2E    &lt;br /&gt;
       sta    $2409   &lt;br /&gt;
       lda    #$24    &lt;br /&gt;
       sta    $240A   &lt;br /&gt;
&lt;br /&gt;
LF48B&lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       pla            &lt;br /&gt;
       jsr    $23FF   &lt;br /&gt;
       pha            &lt;br /&gt;
       inc    $2406   &lt;br /&gt;
       lda    $2406   &lt;br /&gt;
       cmp    #$FF    &lt;br /&gt;
       bne    LF48B   &lt;br /&gt;
&lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       jsr    $2412   &lt;br /&gt;
       jsr    $2412   &lt;br /&gt;
       lda    #$36    &lt;br /&gt;
       sta    $2409   &lt;br /&gt;
       lda    #$24    &lt;br /&gt;
       sta    $240A   &lt;br /&gt;
       dec    $2406   &lt;br /&gt;
LF4B3: jsr    $241B   &lt;br /&gt;
       pla            &lt;br /&gt;
       jsr    $23FF   &lt;br /&gt;
       pha            &lt;br /&gt;
       dec    $2406   &lt;br /&gt;
       lda    $2406   &lt;br /&gt;
       cmp    $EE     &lt;br /&gt;
       bcs    LF4B3   &lt;br /&gt;
       lda    #$60    &lt;br /&gt;
       sta    CTRL   &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
LF4CB: lda    $1800,X &lt;br /&gt;
       eor    $1850,X &lt;br /&gt;
       eor    $1888,X &lt;br /&gt;
       sta    $1A00,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF4CB   &lt;br /&gt;
       lda    $1A00   &lt;br /&gt;
       and    #$07    &lt;br /&gt;
       sta    $1A00   &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       ldx    #$04    &lt;br /&gt;
       sta    $1A00,X &lt;br /&gt;
       sta    $2000,X &lt;br /&gt;
       ldx    #$77         ; That was a lot, but we end up here, comparing&lt;br /&gt;
LF4EE: lda    $2000,X      ; two parts of memory.  If they match, then&lt;br /&gt;
       cmp    $1A00,X      ; go to 7800 mode....&lt;br /&gt;
       bne    LF4FC        ; otherwise go to 2600 mode.&lt;br /&gt;
       dex                 ; nop out above branch to allow user-written&lt;br /&gt;
       bpl    LF4EE        ; carts to run -- I think.&lt;br /&gt;
       jmp    $26B9        ; 7800 mode init&lt;br /&gt;
LF4FC: jmp    $26C2        ; 2600 mode init.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LF500 =  $F500             ; F500 is partway through the next opcode&lt;br /&gt;
       ldx    #$00         ; more authentication stuff all the way through&lt;br /&gt;
LF501: adc    $1800,X&lt;br /&gt;
       adc    LFF00,X &lt;br /&gt;
       tay            &lt;br /&gt;
       lda    $2DD5,Y &lt;br /&gt;
       sta    $1800,X &lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LF501   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
LF514: rol    $1800,X &lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LF514   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
;$241B&lt;br /&gt;
       php            &lt;br /&gt;
       dec    $F0     &lt;br /&gt;
       bpl    LF52C   &lt;br /&gt;
       lda    #$02    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
LF524: lda    $F0     &lt;br /&gt;
       bmi    LF524   &lt;br /&gt;
       lda    #$16    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
LF52C: plp            &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF52E: .byte $C7,$65,$AB,$CA,$EE,$F7,$83,$09&lt;br /&gt;
LF536: .byte $E1,$D0,$92,$67,$62,$B6,$72,$55,$8E,$91,$DC,$C5,$81,$BE,$78,$20&lt;br /&gt;
       .byte $59,$B7,$E6,$3D,$06,$45,$AF,$C8,$08,$31,$38,$D1,$FB,$73,$84,$A9&lt;br /&gt;
       .byte $17,$FC,$34,$87,$A3,$94,$FA,$90,$B8,$ED,$CE,$3B,$5B,$0A,$43,$D9&lt;br /&gt;
       .byte $F3,$53,$82,$B3,$0D,$6D,$5A,$60,$9D,$51,$A7,$B9&lt;br /&gt;
LF572: .byte $11,$10,$BC,$E4,$7F,$80,$41,$E7,$E3&lt;br /&gt;
LF57B: .byte $F6,$56,$26,$35,$EC,$D6,$DF,$0C,$7F,$F4,$9E,$AC,$52,$46,$EF,$CF&lt;br /&gt;
       .byte $BF,$A2,$3F,$A4,$13,$15,$97,$4A,$1C,$B0,$42,$8C,$B1,$05,$58,$80&lt;br /&gt;
       .byte $18,$77,$2B,$02,$3E,$A8,$49,$1A,$6A&lt;br /&gt;
LF5A4: .byte $CB,$6E,$0B,$8A,$EB,$F1,$4F,$14,$79,$8B,$D8,$9F,$9B,$57,$19,$F8&lt;br /&gt;
       .byte $2A,$2D,$76,$0E,$E8,$2E,$4B,$F9,$07,$03,$DE,$93,$16,$7E,$D4,$E5&lt;br /&gt;
       .byte $B2,$F0,$7D,$7A,$DA,$D2,$A1,$CC,$1D,$E0,$5E,$23,$A0,$95,$22,$1E&lt;br /&gt;
       .byte $36,$85,$FE,$1F,$39&lt;br /&gt;
LF5D9: .byte $AA,$89,$96,$AD,$0F,$2F,$C0,$47&lt;br /&gt;
LF5E1: .byte $27,$5D,$24,$EA,$C3,$A5,$F5,$21,$5F,$1B,$40,$8F,$AE,$74,$25,$DD&lt;br /&gt;
       .byte $C1,$7C,$CD,$A6,$70,$D7,$33,$7B,$2C,$75,$BB,$86,$99,$BD,$54&lt;br /&gt;
LF600: .byte $9A,$6C,$63,$32,$48,$4C,$8D,$BA&lt;br /&gt;
LF608: .byte $5C,$61,$C4,$4E,$29,$37,$12,$C6,$98,$9C,$D5,$69,$6B,$E2,$04,$4D&lt;br /&gt;
       .byte $E9,$C2,$88,$3A,$DB,$64,$01,$44,$6F,$B5,$F2,$30,$28,$FD,$50,$71&lt;br /&gt;
       .byte $3C,$B4,$66,$68,$C9,$D3,$CA,$83,$C7,$AB,$F7,$65,$09,$EE&lt;br /&gt;
&lt;br /&gt;
       ldx    #$77      ;($2536)&lt;br /&gt;
       stx    $E4     &lt;br /&gt;
       stx    $E5     &lt;br /&gt;
LF63C: lda    CartKey,X   ;Read Key&lt;br /&gt;
       sta    $1901,X           ;Store it&lt;br /&gt;
       sta    $2000,X           ;Store it again&lt;br /&gt;
       dex                      ;next byte of key&lt;br /&gt;
       bpl    LF63C             ;Continue&lt;br /&gt;
&lt;br /&gt;
       lda    #$02      ;&lt;br /&gt;
       sta    INPTCTRL  ;Disable cart &lt;br /&gt;
       jsr    LFB84     ;Init display&lt;br /&gt;
       jsr    $257B   &lt;br /&gt;
       dec    $F2     &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
       stx    $E4     &lt;br /&gt;
LF658: lda    LFED5,X &lt;br /&gt;
       sta    $1901,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF658   &lt;br /&gt;
       lda    $E1     &lt;br /&gt;
       sta    $E3     &lt;br /&gt;
       jsr    $25E1   &lt;br /&gt;
       dec    $F2     &lt;br /&gt;
LF66A: lda    $E0     &lt;br /&gt;
       sta    $2572   &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
LF671: lda    $1800,X &lt;br /&gt;
LF674: sta    $2000,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF671   &lt;br /&gt;
       rts            &lt;br /&gt;
    &lt;br /&gt;
       jsr    $2639   ;($257B)&lt;br /&gt;
       ldy    $E5     &lt;br /&gt;
       iny            &lt;br /&gt;
LF681: STY    $E1     &lt;br /&gt;
       TYA            &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    $E2     &lt;br /&gt;
       pha            &lt;br /&gt;
LF688: tax            &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       sta    $2671   &lt;br /&gt;
LF68E: sta    $1800,X &lt;br /&gt;
       dex            &lt;br /&gt;
LF692: bne    LF68E   &lt;br /&gt;
       sta    $1800   &lt;br /&gt;
LF697: iny            &lt;br /&gt;
       STY    $266E   &lt;br /&gt;
       STY    $2674   &lt;br /&gt;
       STY    $267C   &lt;br /&gt;
       STY    $2681   &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
LF6A6: dec    $266E   &lt;br /&gt;
LF6A9: dec    $2674   &lt;br /&gt;
LF6AC: dec    $267C   &lt;br /&gt;
       dec    $2681   &lt;br /&gt;
       dec    $E1     &lt;br /&gt;
       bmi    LF6D1   &lt;br /&gt;
LF6B6: ldy    $E1     &lt;br /&gt;
       lda    $2000,Y &lt;br /&gt;
       and    $25D9,X &lt;br /&gt;
       beq    LF6C9   &lt;br /&gt;
       lda    $2662,X &lt;br /&gt;
       sta    $2672   &lt;br /&gt;
       jsr    $266A   &lt;br /&gt;
LF6C9: inx            &lt;br /&gt;
       cpx    #$08    &lt;br /&gt;
       bmi    LF6B6   &lt;br /&gt;
       jmp    $25A4   &lt;br /&gt;
LF6D1: pla            &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       lda    #$01    &lt;br /&gt;
       sta    $E0     &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF6D9: .byte $01,$02,$04,$08,$10,$20,$40,$80&lt;br /&gt;
&lt;br /&gt;
       jsr    $2639&lt;br /&gt;
       lda    $E3     &lt;br /&gt;
       sec            &lt;br /&gt;
       sbc    $E4     &lt;br /&gt;
       sta    $E0     &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
       stx    $1800   &lt;br /&gt;
       stx    $268F   &lt;br /&gt;
       stx    $26AC   &lt;br /&gt;
       dex            &lt;br /&gt;
       stx    $26A9   &lt;br /&gt;
       stx    $268C   &lt;br /&gt;
       stx    $2692   &lt;br /&gt;
       stx    $269A   &lt;br /&gt;
       stx    $269F   &lt;br /&gt;
       ldx    #$07    &lt;br /&gt;
       inc    $26A9   &lt;br /&gt;
       inc    $268C   &lt;br /&gt;
       inc    $2692   &lt;br /&gt;
       inc    $269A   &lt;br /&gt;
       inc    $269F   &lt;br /&gt;
       dec    $E1     &lt;br /&gt;
       bmi    LF734   &lt;br /&gt;
LF71D: lda    $2662,X &lt;br /&gt;
       sta    $2690   &lt;br /&gt;
       sta    $26AD   &lt;br /&gt;
       jsr    $26A6   &lt;br /&gt;
       bcc    LF72E   &lt;br /&gt;
       jsr    $2688   &lt;br /&gt;
LF72E: dex            &lt;br /&gt;
       bpl    LF71D   &lt;br /&gt;
       jmp    $2608   &lt;br /&gt;
LF734: lda    $E3     &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
       ldx    $E4   ;($2639)&lt;br /&gt;
       inx            &lt;br /&gt;
       stx    $E2     &lt;br /&gt;
       ldy    #$00    &lt;br /&gt;
       STY    $1900   &lt;br /&gt;
LF743: lda    $2662,Y &lt;br /&gt;
       sta    $2655   &lt;br /&gt;
       iny            &lt;br /&gt;
       lda    $2662,Y &lt;br /&gt;
       sta    $2659   &lt;br /&gt;
       ldx    $E2     &lt;br /&gt;
       clc            &lt;br /&gt;
LF753: lda    $1900,X &lt;br /&gt;
       rol&lt;br /&gt;
       sta    $1900,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF753   &lt;br /&gt;
       cpy    #$07    &lt;br /&gt;
       bmi    LF743   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF762: .byte $19,$1A,$1B,$1C,$1D,$1E,$1F,$21&lt;br /&gt;
&lt;br /&gt;
       ldy    $E2&lt;br /&gt;
       clc            &lt;br /&gt;
LF76D: lda    $1800,Y &lt;br /&gt;
       adc    $1900,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       bpl    LF76D   &lt;br /&gt;
       bcc    LF787   &lt;br /&gt;
       lda    $1700,Y &lt;br /&gt;
       adc    #$00    &lt;br /&gt;
       sta    $1700,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       jmp    $2679   &lt;br /&gt;
LF787: rts            &lt;br /&gt;
&lt;br /&gt;
       ldy    $E2     &lt;br /&gt;
       sec            &lt;br /&gt;
LF78B: lda    $1800,Y &lt;br /&gt;
       sbc    $1900,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       bpl    LF78B   &lt;br /&gt;
       bcs    LF7A5   &lt;br /&gt;
       lda    $1700,Y &lt;br /&gt;
       sbc    #$00    &lt;br /&gt;
       sta    $1700,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       jmp    $2697   &lt;br /&gt;
LF7A5: rts            &lt;br /&gt;
&lt;br /&gt;
       ldy    #$00    &lt;br /&gt;
       lda    $1800,Y &lt;br /&gt;
       cmp    $1900,Y &lt;br /&gt;
       beq    LF7B1   &lt;br /&gt;
LF7B0: rts            &lt;br /&gt;
&lt;br /&gt;
LF7B1: cpy    $E2     &lt;br /&gt;
       beq    LF7B0   &lt;br /&gt;
       iny            &lt;br /&gt;
       jmp    $26A8   &lt;br /&gt;
&lt;br /&gt;
LF7B9:                    ; ($26B9) 7800 mode init&lt;br /&gt;
       ldx    #$16        ; finally, back to something important&lt;br /&gt;
       stx    INPTCTRL    ; switch out bios and use reset vector&lt;br /&gt;
       txs                ; on cart to start the game.&lt;br /&gt;
       SED            &lt;br /&gt;
       jmp (CartResetVectorLo)     &lt;br /&gt;
&lt;br /&gt;
; Enable 2600 mode&lt;br /&gt;
LF7C2:                    ; ($26C2) 2600 mode init&lt;br /&gt;
       lda    #$02        ; Enable memory/bios&lt;br /&gt;
       sta    INPTCTRL    ; &lt;br /&gt;
       ldx    #$7F&lt;br /&gt;
LF7C8: lda    LF7D4,X     ; again, copy code to ram....&lt;br /&gt;
       sta    $0480,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF7C8   &lt;br /&gt;
       jmp    $0480       ; execute it&lt;br /&gt;
&lt;br /&gt;
; code executed at $0480 (RIOT RAM)&lt;br /&gt;
&lt;br /&gt;
LF7D4: lda    #$00        ; &lt;br /&gt;
       tax                ; &lt;br /&gt;
       sta    INPTCTRL    ; Disable 7800 RAM&lt;br /&gt;
LF7D9: sta    RSYNC,X     ; Clear the TIA&lt;br /&gt;
       inx                ;&lt;br /&gt;
       cpx    #$2A        ;&lt;br /&gt;
       bne    LF7D9       ;&lt;br /&gt;
       sta    WSYNC       ; wait for sync&lt;br /&gt;
       lda    #$04        ;&lt;br /&gt;
       nop                ;&lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
       ldx    #$04    &lt;br /&gt;
LF7E9: dex            &lt;br /&gt;
       bpl    LF7E9   &lt;br /&gt;
       txs            &lt;br /&gt;
       sta    $0110   &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       sta    RESP1   &lt;br /&gt;
       sta    GRP0    &lt;br /&gt;
       sta    GRP1    &lt;br /&gt;
       sta    PF2     &lt;br /&gt;
       nop            &lt;br /&gt;
       sta    WSYNC   &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       nop            &lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
       bit    RSYNC   &lt;br /&gt;
       bmi    LF813   &lt;br /&gt;
LF80A: lda    #$02    &lt;br /&gt;
       sta    COLUBK  &lt;br /&gt;
       sta    LF112   &lt;br /&gt;
       bne    LF831   &lt;br /&gt;
LF813: bit    WSYNC   &lt;br /&gt;
       bmi    LF823   &lt;br /&gt;
       lda    #$02    &lt;br /&gt;
       sta    COLUP0  &lt;br /&gt;
       sta    LF118   &lt;br /&gt;
       sta    LF460   &lt;br /&gt;
       bne    LF831   &lt;br /&gt;
LF823: sta    DPPH   &lt;br /&gt;
       lda    #$08    &lt;br /&gt;
       sta    GRP0    &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       nop            &lt;br /&gt;
       bit    WSYNC   &lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
LF831: lda    #$FD    &lt;br /&gt;
       sta    COLUPF  &lt;br /&gt;
       jmp (CartResetVectorLo)        ; And use the reset vector on the cart to start&lt;br /&gt;
       nop                            ; the 2600 game.&lt;br /&gt;
&lt;br /&gt;
       ORG $F880&lt;br /&gt;
&lt;br /&gt;
LF880: lda    #$1D        ; this is called any time the self-test fails.&lt;br /&gt;
       sta    INPTCTRL    ; Eanble TIA/Cart/lock out INPTCTRL&lt;br /&gt;
&lt;br /&gt;
START:                    ; $F884 &lt;br /&gt;
       SEI                ; BIOS entry point.  Disable interrupts&lt;br /&gt;
       CLD                ; Clear decimal flag&lt;br /&gt;
       lda    #$02        ;&lt;br /&gt;
LF888: sta    INPTCTRL    ; Enable 7800 RAM&lt;br /&gt;
       lda    #$FB        ;&lt;br /&gt;
       sta    $F5         ;&lt;br /&gt;
       lda    #$12        ;&lt;br /&gt;
       sta    $F4         ; set nmi vector to FB12. (shares cleanup of irq)&lt;br /&gt;
       lda    #$7F        ;&lt;br /&gt;
       sta    CTRL        ; Turn off DMA&lt;br /&gt;
       lda    #$00        ;&lt;br /&gt;
       sta    BACKGRND    ; Background color&lt;br /&gt;
       ldx    #$05        ;&lt;br /&gt;
LF89C: lda    LF91D,X     ; looks icky, but it's just a ram test&lt;br /&gt;
       ldy    #$00        ;&lt;br /&gt;
LF8A1: sta    $2000,Y     ;&lt;br /&gt;
       cmp    $2000,Y     ;&lt;br /&gt;
       bne    LF8D0       ; Test failed&lt;br /&gt;
       sta    $2100,Y     ;&lt;br /&gt;
       cmp    $2100,Y     ;&lt;br /&gt;
       bne    LF8D0       ; Test failed&lt;br /&gt;
       dey                ;&lt;br /&gt;
       bne    LF8A1       ;&lt;br /&gt;
       dex                ;&lt;br /&gt;
       bpl    LF89C       ; and right down here, it passes&lt;br /&gt;
       lda    #$43        ; Check RAM 0 mirror&lt;br /&gt;
       sta    $2080       ; &lt;br /&gt;
       cmp    $80         ; &lt;br /&gt;
       bne    LF8CB       ; make sure they match. If not, fail selftest.&lt;br /&gt;
       sta    $2180       ; Check RAM 1 mirror&lt;br /&gt;
       cmp    $0180       ; &lt;br /&gt;
       bne    LF8CB       ; make sure they match. If not, fail selftest.&lt;br /&gt;
       jmp    LF938       ; continue selftest&lt;br /&gt;
LF8CB: ldy    #$04        ;&lt;br /&gt;
       jmp    LF880       ; selftest fail.&lt;br /&gt;
&lt;br /&gt;
LF8D0: sta    $1800       ; test store and compare&lt;br /&gt;
       cmp    $1800   &lt;br /&gt;
       bne    LF8E2       ; some kind of error code is being determined&lt;br /&gt;
LF8D8: ldy    #$01    &lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
LF8DD: ldy    #$02&lt;br /&gt;
       jmp    $F880&lt;br /&gt;
&lt;br /&gt;
LF8E2: ldy    #$03&lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
LF8E7: lda    #$00        ; this is a more comprehensive ram test than&lt;br /&gt;
       sta    $F0         ; the first routine, and it is called after&lt;br /&gt;
       sta    $F2         ; more of the selftest has completed.&lt;br /&gt;
       ldy    #$07    &lt;br /&gt;
       STY    $F4     &lt;br /&gt;
LF8F1: lda    LF923,Y &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       lda    LF92B,Y &lt;br /&gt;
       sta    $F3     &lt;br /&gt;
       ldx    #$05    &lt;br /&gt;
LF8FD: lda    LF91D,X &lt;br /&gt;
LF900: ldy    #$00    &lt;br /&gt;
LF902: sta    ($F0),Y &lt;br /&gt;
       cmp    ($F0),Y &lt;br /&gt;
       bne    LF8D8   &lt;br /&gt;
       sta    ($F2),Y &lt;br /&gt;
       cmp    ($F2),Y &lt;br /&gt;
       bne    LF8DD   &lt;br /&gt;
       dey            &lt;br /&gt;
       bne    LF902   &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF8FD   &lt;br /&gt;
       dec    $F4     &lt;br /&gt;
       ldy    $F4     &lt;br /&gt;
       bpl    LF8F1   &lt;br /&gt;
       jmp    LFB17       ; ram test passed, so jump in here.&lt;br /&gt;
&lt;br /&gt;
; ram test data&lt;br /&gt;
LF91D: .byte $00,$FF,$55,$AA,$69,$0F&lt;br /&gt;
LF923: .byte $22,$23,$24,$25,$26,$27,$22,$23&lt;br /&gt;
LF92B: .byte $18,$19,$1A,$1B,$1C,$1D,$1E,$1F&lt;br /&gt;
&lt;br /&gt;
LF933: ldy    #$00       ; local place for selftest fail branch target&lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
; 6502 CPU test&lt;br /&gt;
&lt;br /&gt;
LF938: lda    #$AA       ; test some flags and branches&lt;br /&gt;
       beq    LF933      ; test failed&lt;br /&gt;
       bpl    LF933      ; test failed&lt;br /&gt;
       bmi    LF943      ; test passed&lt;br /&gt;
       jmp    LF933      ; test failed&lt;br /&gt;
LF943: bne    LF948      ; test passed&lt;br /&gt;
       jmp    LF933      ; test failed&lt;br /&gt;
LF948: sta    $AA        ; store AA to 00AA&lt;br /&gt;
       cmp    $AA        ; compare it back&lt;br /&gt;
       bne    LF933      ; if it doesn't match, selftest fail&lt;br /&gt;
       lda    #$00       ; do some more flag tests&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       bmi    LF933      ;&lt;br /&gt;
       bpl    LF959      ; test passed&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF959: beq    LF95E      ; test passed&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF95E: cmp    #$00       ; test the compare instruction&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       bcc    LF933      ;&lt;br /&gt;
       bcs    LF969      ; test passed, since they're equal&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF969: cmp    #$01       ; compare it to 01&lt;br /&gt;
       bcs    LF933      ;&lt;br /&gt;
       bcc    LF972      ; A &amp;lt; 01, so carry is clear&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF972: ldx    #$55       ; test comparisons with the X register&lt;br /&gt;
       cpx    #$56       ;&lt;br /&gt;
       beq    LF933      ;&lt;br /&gt;
       stx    $01AA      ;&lt;br /&gt;
       cpx    $01AA      ;&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       ldy    $AA        ; and with the Y register.&lt;br /&gt;
       cpy    #$AB       ;&lt;br /&gt;
LF984: beq    LF933      ;&lt;br /&gt;
       STY    $0155      ; put some stuff in the stack area to test stack&lt;br /&gt;
       cpy    $0155      ; and then access this data in many diffeent ways&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       dex               ;&lt;br /&gt;
       txs               ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       pla               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       txa               ;&lt;br /&gt;
       pha               ;&lt;br /&gt;
       cpx    $0155      ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       TYA               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       tax               ;&lt;br /&gt;
       lda    $0100,X    ;&lt;br /&gt;
       tay               ;&lt;br /&gt;
       cpy    #$55       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    VSYNC,X    ;&lt;br /&gt;
       cmp    $AA        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       eor    #$FF       ;&lt;br /&gt;
       sta    $0000,Y    ;&lt;br /&gt;
       cmp    $55        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    $0100,Y    ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    $20AB,X    ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    #$20       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       lda    #$CC       ;&lt;br /&gt;
       sta    $F0        ;&lt;br /&gt;
       sta    ($46,X)    ;&lt;br /&gt;
       cmp    $CC        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       sta    ($F0),Y    ;&lt;br /&gt;
       cmp    $2121      ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    #$EE       ; test the indirect jump by setting up a jump&lt;br /&gt;
       sta    $F0        ; to F9EE&lt;br /&gt;
       lda    #$F9       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       jmp ($00F0)        ; and do it.&lt;br /&gt;
&lt;br /&gt;
LF9E8: jmp    $F9EB&lt;br /&gt;
&lt;br /&gt;
LF9EB: jmp    LF933&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LF9EE: lda    #$55       ; now test out the math functions.&lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$55    &lt;br /&gt;
       nop            &lt;br /&gt;
       bcs    LF9EB      ; test addition.&lt;br /&gt;
       bpl    LF9EB   &lt;br /&gt;
       beq    LF9EB   &lt;br /&gt;
       cmp    #$AA       ; make sure it worked&lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       adc    #$55       ; test addition again.&lt;br /&gt;
LFA00: nop            &lt;br /&gt;
       bcc    LF9EB   &lt;br /&gt;
       bmi    LF9EB   &lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       sbc    #$55       ; test subtraction&lt;br /&gt;
       bcs    LF9EB   &lt;br /&gt;
       bpl    LF9EB   &lt;br /&gt;
       beq    LF9EB   &lt;br /&gt;
       cmp    #$AB       ; make sure it worked&lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       clc            &lt;br /&gt;
       sbc    #$AA       ; test subtraction again&lt;br /&gt;
       bcc    LF9EB   &lt;br /&gt;
       bmi    LF9EB   &lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       lda    #$FF       ; set up a stack&lt;br /&gt;
       tax               ; and do all kinds of stuff in it for tests&lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dex            &lt;br /&gt;
       beq    LFA58   &lt;br /&gt;
       bpl    LFA58   &lt;br /&gt;
       cpx    #$FF    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       tay            &lt;br /&gt;
       iny            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dey            &lt;br /&gt;
       beq    LFA58      &lt;br /&gt;
       iny            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       inc    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       cpy    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dec    $F0     &lt;br /&gt;
       beq    LFA58   &lt;br /&gt;
       cmp    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       lda    #$AA    &lt;br /&gt;
       clc            &lt;br /&gt;
       rol               ; now we get onto the more complex math instrs&lt;br /&gt;
       rol&lt;br /&gt;
       rol&lt;br /&gt;
       cmp    #$52    &lt;br /&gt;
       bne    LFA58      ; make sure rotate left works.&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       cmp    #$AA    &lt;br /&gt;
       beq    LFA5B      ; test rotate right&lt;br /&gt;
LFA58: jmp    LF933      ; fail!&lt;br /&gt;
&lt;br /&gt;
LFA5B: asl               ; test arithmetic shift left&lt;br /&gt;
       bcc    LFA58   &lt;br /&gt;
       asl            &lt;br /&gt;
       bcs    LFA58   &lt;br /&gt;
       asl            &lt;br /&gt;
       cmp    #$50    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       eor    #$05    &lt;br /&gt;
       lsr               ; and logical shift right&lt;br /&gt;
       bcc    LFA58   &lt;br /&gt;
       lsr            &lt;br /&gt;
       bcs    LFA58   &lt;br /&gt;
       lsr            &lt;br /&gt;
       cmp    #$0A    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       lda    #$55       ; now test the ands and ors.&lt;br /&gt;
       ora    #$1B    &lt;br /&gt;
       cmp    #$5F    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       and    #$55    &lt;br /&gt;
       and    #$1B    &lt;br /&gt;
       cmp    #$11    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       ora    #$55    &lt;br /&gt;
       eor    #$1B       ; and the eors&lt;br /&gt;
       cmp    #$4E    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       jsr    LFA91      ; test jump subroutine instruction&lt;br /&gt;
       jmp    LFA58      ; if we return, fail&lt;br /&gt;
&lt;br /&gt;
LFA91: tsx               &lt;br /&gt;
       cpx    #$52       ; check stack pointer&lt;br /&gt;
       bne    LFA58      ; fail if not right&lt;br /&gt;
       pla            &lt;br /&gt;
       cmp    #$8D    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       pla            &lt;br /&gt;
       cmp    #$FA    &lt;br /&gt;
       bne    LFA58      ; get the old return address off the stack&lt;br /&gt;
       lda    #$F8    &lt;br /&gt;
       pha            &lt;br /&gt;
       lda    #$E6    &lt;br /&gt;
       pha               ; and make our own&lt;br /&gt;
       rts               ; and 'return' to F8E7&lt;br /&gt;
&lt;br /&gt;
       jmp    LFA58      ; another jump to catch a failure&lt;br /&gt;
&lt;br /&gt;
; Interrupt routine  NMI. &lt;br /&gt;
&lt;br /&gt;
LFAAA: txa          ;Save A&lt;br /&gt;
       pha          ;  &lt;br /&gt;
       lda    #$43  ;Setup control register  &lt;br /&gt;
       sta    CTRL  ; &lt;br /&gt;
       ldx    #$0F  ; Handle the color scrolling in the FUJI    &lt;br /&gt;
       lda    $EF     &lt;br /&gt;
       sta    P0C2&lt;br /&gt;
       bit    $F3     &lt;br /&gt;
       bvc    LFAC0   &lt;br /&gt;
       bpl    LFABE   &lt;br /&gt;
LFABC: sta    MWSYNC ;Wait for 3 scanlines &lt;br /&gt;
LFABE: sta    MWSYNC ;    &lt;br /&gt;
LFAC0: sta    MWSYNC ;   &lt;br /&gt;
       sec            &lt;br /&gt;
       sbc    #$10  &lt;br /&gt;
       cmp    #$10    &lt;br /&gt;
       bcs    LFACB   &lt;br /&gt;
       sbc    #$0F    &lt;br /&gt;
LFACB: sta    P0C2&lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LFABC   ;Branch to do next section of fuji&lt;br /&gt;
       ldx    #$40    ;set 160x2/160x4 mode&lt;br /&gt;
       stx    CTRL    ;  &lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$0E    ;set Palette 1 color 3&lt;br /&gt;
       sta    P1C3    ;&lt;br /&gt;
       lda    $EF     ;&lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$06    ;set Palette 1 color 1&lt;br /&gt;
       sta    P1C1    ;&lt;br /&gt;
       and    #$F0    &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$40    &lt;br /&gt;
       bcc    LFAEB   &lt;br /&gt;
       adc    #$0F    &lt;br /&gt;
LFAEB: ora    #$03   ;set Palette 1 color 2  &lt;br /&gt;
       sta    P1C2  &lt;br /&gt;
       dec    $F1     &lt;br /&gt;
       bpl    LFB0C   &lt;br /&gt;
       lda    $F3     &lt;br /&gt;
       adc    #$60    &lt;br /&gt;
       bcc    LFB0A   &lt;br /&gt;
       lda    $EF     &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$10    &lt;br /&gt;
       bcc    LFB02   &lt;br /&gt;
       adc    #$0F    &lt;br /&gt;
LFB02: sta    $EF     &lt;br /&gt;
       lda    $F2     &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
LFB0A: sta    $F3     &lt;br /&gt;
LFB0C: lda    #$02    &lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       pla            &lt;br /&gt;
       tax            &lt;br /&gt;
       pla            &lt;br /&gt;
       rti            &lt;br /&gt;
&lt;br /&gt;
LFB14: jmp    LFB14   &lt;br /&gt;
&lt;br /&gt;
LFB17: ldx    #$FF       ; selftest has passed, start system init&lt;br /&gt;
       txs               ; set up a stack&lt;br /&gt;
       lda    #$00       ; Clear TIA/Maria registers&lt;br /&gt;
       tax               ;&lt;br /&gt;
LFB1D: sta    $01,X ;    ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       cpx    #$2C       ;&lt;br /&gt;
       bne    LFB1D      ; &lt;br /&gt;
       lda    #$02       ;&lt;br /&gt;
       sta    INPTCTRL   ; Enable 7800 RAM &lt;br /&gt;
       ldx    #$00       ;&lt;br /&gt;
       stx    BACKGRND   ; Set background color &lt;br /&gt;
LFB2C: lda    LF400,X    ; copy the authentication and title screen to &lt;br /&gt;
       sta    $2300,X    ; ram&lt;br /&gt;
       lda    LF500,X    ;&lt;br /&gt;
       sta    $2400,X    ;&lt;br /&gt;
       lda    LF600,X    ;&lt;br /&gt;
       sta    $2500,X    ;&lt;br /&gt;
       lda    LF700,X    ;&lt;br /&gt;
       sta    $2600,X    ;&lt;br /&gt;
       lda    LF800,X    ;&lt;br /&gt;
       sta    $2700,X    ;&lt;br /&gt;
       lda    LFBBE,X    ;&lt;br /&gt;
       sta    $2200,X    ;&lt;br /&gt;
       cpx    #$00       ;&lt;br /&gt;
       bmi    LFB7E      ;&lt;br /&gt;
       lda    LFC4B,X     ;&lt;br /&gt;
       sta    $1F84,X     ;&lt;br /&gt;
       lda    LFCC6,X     ;&lt;br /&gt;
       sta    $1984,X     ;&lt;br /&gt;
       lda    LFD3D,X     ;&lt;br /&gt;
       sta    $1A84,X     ;&lt;br /&gt;
       lda    LFDB4,X     ;&lt;br /&gt;
       sta    $1B84,X     ;&lt;br /&gt;
       lda    LFE18,X     ;&lt;br /&gt;
       sta    $1C84,X     ;&lt;br /&gt;
       lda    LFE57,X     ;&lt;br /&gt;
       sta    $1D84,X     ;&lt;br /&gt;
       lda    LFE96,X     ;&lt;br /&gt;
       sta    $1E84,X     ;&lt;br /&gt;
LFB7E: dex                ;&lt;br /&gt;
       bne    LFB2C       ;&lt;br /&gt;
       jmp    $2306       ; and execute it&lt;br /&gt;
&lt;br /&gt;
;Start display of Atari logo&lt;br /&gt;
&lt;br /&gt;
LFB84: lda    CartKeyStartPage      ; Read ROM start byte from cart&lt;br /&gt;
       and    #$04       ; Is rom start greater then $4000?&lt;br /&gt;
       beq    LFBBD      ; Branch if not&lt;br /&gt;
       lda    #$03      &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       sta    $F2     &lt;br /&gt;
       lda    #$49    &lt;br /&gt;
       sta    $EF     &lt;br /&gt;
       lda    #$66       ;Palette 1 Color 1&lt;br /&gt;
       sta    P1C1       ;&lt;br /&gt;
       lda    #$56       ;Palette 1 Color 2&lt;br /&gt;
       sta    P1C2       ;&lt;br /&gt;
       lda    #$2E       ;Palette 1 Color 3&lt;br /&gt;
       sta    P1C3       ;&lt;br /&gt;
       lda    #$AA       ;Set NMI vector to FAAA&lt;br /&gt;
       sta    $F4        ;&lt;br /&gt;
       lda    #$FA       ;&lt;br /&gt;
       sta    $F5        ;&lt;br /&gt;
LFBA9: bit    MSTAT      ;Check VBLANK status&lt;br /&gt;
       bmi    LFBA9      ;Wait till end of VBLANK&lt;br /&gt;
LFBAD: bit    MSTAT      ;Check BLANK status&lt;br /&gt;
       bpl    LFBAD      ;Wait for start of next VBLANK&lt;br /&gt;
       lda    #$84       ;Set Display list pointer to $1f84&lt;br /&gt;
       sta    DPPL       ;&lt;br /&gt;
       lda    #$1F       ;&lt;br /&gt;
       sta    DPPH       ;&lt;br /&gt;
       lda    #$43       ;Maria mode = DMA on/320A or 320C&lt;br /&gt;
       sta    CTRL       ;&lt;br /&gt;
LFBBD: rts               ;&lt;br /&gt;
&lt;br /&gt;
; Graphics and Display List Data&lt;br /&gt;
&lt;br /&gt;
LFBBE:                                  ;$2200   Display Lists&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$1F,$19,$BB            ;$2200   Blank space&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$40,$19,$1F,$BB        ;$2206   First DL on screen&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $85,$1C,$19,$4A            ;$220D   Blank space before Fuji&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $89,$1C,$19,$4A            ;$2213   Fuji line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $8D,$1C,$19,$48            ;$2219   Fuji line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $91,$1B,$19,$46            ;$221F   Fuji line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $96,$19,$19,$42            ;$2225   Fuji line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $9D,$17,$19,$3E            ;$222B   Fuji line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $A6,$17,$19,$3E            ;$2231   Fuji line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1C,$00            ;$2237   Start of Atari&lt;br /&gt;
       .byte $AF,$2C,$1C,$50            ;        and between lines&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1D,$00            ;$2241   End of Atari&lt;br /&gt;
       .byte $AF,$2C,$1D,$50 &lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$19,$28            ;$224B    Atari line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$19,$28            ;$2251    Atari line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$19,$28            ;$2257     Atari line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
                                                   &lt;br /&gt;
       .byte $E8,$2D,$19,$28            ;$225D     Atari line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1A,$28            ;$2263     Atari line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1A,$28            ;$2269     Atari line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1A,$28            ;$226F     Atari line 7&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $E8,$2D,$1A,$28            ;$2275     Atari line 8&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1B,$28            ;$227B     Atari line 9&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1B,$28            ;$2281     Atari line 10&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1B,$28            ;$2287     Atari line 11&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
; $1F84  Display List List&lt;br /&gt;
&lt;br /&gt;
LFC4B: .byte $0F,$22,$06      ;Blank space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $03,$22,$00      ;&lt;br /&gt;
       .byte $85,$22,$0D      ;DLI&lt;br /&gt;
       .byte $05,$22,$13      ;Draw Fuji&lt;br /&gt;
       .byte $05,$22,$19      ;&lt;br /&gt;
       .byte $05,$22,$1F      ;&lt;br /&gt;
       .byte $05,$22,$25      ;&lt;br /&gt;
       .byte $05,$22,$2B      ;&lt;br /&gt;
       .byte $05,$22,$31      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank area&lt;br /&gt;
       .byte $01,$22,$37      ;Draw &amp;quot;ATARI&amp;quot;&lt;br /&gt;
       .byte $00,$22,$4B      ;Line 1 &lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$51      ;Line 2&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$57      ;Line 3&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$5D      ;Line 4&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$63      ;Line 5&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$69      ;Line 6&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$6F      ;Line 7&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$75      ;Line 8&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$7B      ;Line 9&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$81      ;Line 10&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$87      ;Line 11&lt;br /&gt;
       .byte $01,$22,$41&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank Space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
&lt;br /&gt;
LFCC6&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$fc,$7f,$8f,$c0,$1f,$87,$f8,$7e,$0f,$e0,$7f&lt;br /&gt;
LFCD6&lt;br /&gt;
    .byte $81,$fc,$07,$ff,$80,$7f,$80,$7f,$f8,$1f,$ff,$f0,$00,$7f,$80,$03&lt;br /&gt;
LFCE6&lt;br /&gt;
    .byte $ff,$fe,$1f,$00,$00,$00,$7f,$80,$00,$00,$3e,$00,$00,$0c,$00,$3f&lt;br /&gt;
LFCF6&lt;br /&gt;
    .byte $ff,$ff,$ff,$f0,$00,$c0,$00,$00,$3f,$ff,$ff,$00,$03,$fc,$00,$00&lt;br /&gt;
LFD06&lt;br /&gt;
    .byte $3f,$00,$3f,$ff,$ff,$ff,$f0,$03,$f0,$00,$00,$3f,$ff,$ff,$fc,$03&lt;br /&gt;
LFD16&lt;br /&gt;
    .byte $fc,$00,$00,$ff,$c0,$00,$03,$ff,$00,$00,$0f,$fc,$00,$00,$3f,$f0&lt;br /&gt;
LFD26&lt;br /&gt;
    .byte $03,$ff,$c3,$fc,$00,$03,$ff,$f0,$00,$03,$ff,$00,$00,$3f,$ff,$00&lt;br /&gt;
LFD36&lt;br /&gt;
    .byte $00,$3f,$f0,$00,$3f,$c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80&lt;br /&gt;
LFD46&lt;br /&gt;
    .byte $1f,$87,$f8,$7e,$0f,$f0,$7f,$83,$fc,$01,$ff,$80,$7f,$80,$7f,$e0&lt;br /&gt;
LFD56&lt;br /&gt;
    .byte $1f,$ff,$f8,$00,$7f,$80,$07,$ff,$fe,$1f,$f0,$00,$00,$7f,$80,$00&lt;br /&gt;
LFD66&lt;br /&gt;
    .byte $03,$fe,$00,$0f,$f3,$fc,$00,$03,$ff,$00,$00,$ff,$3f,$c0,$00,$3f&lt;br /&gt;
LFD76&lt;br /&gt;
    .byte $f0,$00,$ff,$c3,$fc,$00,$3f,$c0,$ff,$00,$03,$ff,$00,$03,$fc,$0f&lt;br /&gt;
LFD86&lt;br /&gt;
    .byte $f0,$00,$3f,$f0,$3f,$fc,$03,$fc,$00,$ff,$00,$3f,$c0,$03,$ff,$00&lt;br /&gt;
LFD96&lt;br /&gt;
    .byte $0f,$f0,$03,$fc,$00,$3f,$f0,$ff,$c0,$03,$fc,$03,$ff,$ff,$ff,$f0&lt;br /&gt;
LFDA6&lt;br /&gt;
    .byte $03,$ff,$00,$3f,$ff,$ff,$ff,$00,$3f,$f0,$3f,$f0,$03,$fc,$00,$7c&lt;br /&gt;
LFDB6&lt;br /&gt;
    .byte $7f,$8f,$80,$7c,$7f,$8f,$80,$1f,$87,$f8,$7e,$07,$f0,$7f,$83,$f8&lt;br /&gt;
LFDC6&lt;br /&gt;
    .byte $00,$ff,$c0,$7f,$80,$ff,$c0,$1f,$ff,$fc,$00,$7f,$80,$0f,$ff,$fe&lt;br /&gt;
LFDD6&lt;br /&gt;
    .byte $1f,$fc,$00,$00,$7f,$80,$00,$0f,$fe,$0f,$ff,$ff,$ff,$fc,$03,$ff&lt;br /&gt;
LFDE6&lt;br /&gt;
    .byte $00,$ff,$ff,$ff,$ff,$c0,$3f,$f0,$0f,$fc,$03,$fc,$3f,$f0,$00,$03&lt;br /&gt;
LFDF6&lt;br /&gt;
    .byte $ff,$03,$ff,$03,$ff,$00,$00,$3f,$f0,$3f&lt;br /&gt;
LFE00&lt;br /&gt;
    .byte $f0,$03,$ff,$03,$fc,$ff&lt;br /&gt;
LFE06&lt;br /&gt;
    .byte $c0,$00,$00,$ff,$c3,$ff,$0f,$fc,$00,$00,$0f,$fc,$3f,$f0,$00,$ff&lt;br /&gt;
LFE16&lt;br /&gt;
    .byte $c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$87,$f8,$7c,$07&lt;br /&gt;
LFE26&lt;br /&gt;
    .byte $f0,$7f,$83,$f8,$00,$7f,$c0,$7f,$80,$ff,$80,$1f,$ff,$fe,$00,$7f&lt;br /&gt;
LFE36&lt;br /&gt;
    .byte $80,$1f,$ff,$fe,$1f,$ff,$00,$00,$7f,$80,$00,$3f,$fe,$55,$55,$55&lt;br /&gt;
LFE46&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55&lt;br /&gt;
LFE56&lt;br /&gt;
    .byte $55,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f0&lt;br /&gt;
LFE66&lt;br /&gt;
    .byte $7f,$83,$f0,$00,$3f,$e0,$7f,$81,$ff,$00,$01,$ff,$fe,$00,$7f,$80&lt;br /&gt;
LFE76&lt;br /&gt;
    .byte $1f,$ff,$e0,$1f,$ff,$c0,$00,$7f,$80,$00,$ff,$fe,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE86&lt;br /&gt;
    .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE96&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f8,$7f&lt;br /&gt;
LFEA6&lt;br /&gt;
    .byte $87,$f0,$00,$1f,$e0,$7f,$81,$fe,$00,$00,$1f,$ff,$00,$7f,$80,$3f&lt;br /&gt;
LFEB6&lt;br /&gt;
    .byte $fe,$00,$1f,$ff,$e0,$00,$7f,$80,$01,$ff,$fe,$55,$55,$55,$55,$55&lt;br /&gt;
LFEC6&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$09&lt;br /&gt;
LFED6&lt;br /&gt;
    .byte $ca,$c9,$c6,$b4,$12,$08,$1b,$60,$58,$81,$4b,$86,$01,$d8,$bf,$d9&lt;br /&gt;
LFEE6&lt;br /&gt;
    .byte $25,$a0,$7b,$dc,$32,$79,$84,$3b,$7c,$bc,$2f,$e2,$e2,$fa,$8d,$0a&lt;br /&gt;
LFEF6&lt;br /&gt;
    .byte $00,$3b,$c5,$ec,$af,$2d,$8a,$cd,$06,$93&lt;br /&gt;
LFF00&lt;br /&gt;
    .byte $6a,$a5,$14,$46,$77,$c4&lt;br /&gt;
LFF06&lt;br /&gt;
    .byte $6a,$b2,$53,$36,$ef,$8c,$ce,$0c,$a2,$68,$71,$d3,$73,$e8,$f7,$6d&lt;br /&gt;
LFF16&lt;br /&gt;
    .byte $06,$b5,$20,$ef,$23,$47,$0c,$51,$55,$c8,$fe,$f4,$58,$c4,$3f,$20&lt;br /&gt;
LFF26&lt;br /&gt;
    .byte $a7,$67,$38,$b0,$76,$e2,$c4,$d8,$05,$63,$f8,$3c,$58,$3b,$2d,$22&lt;br /&gt;
LFF36&lt;br /&gt;
    .byte $cc,$88,$b3,$71,$8f,$1d,$80,$0a,$87,$bd,$a1,$59,$23,$e9,$70,$e2&lt;br /&gt;
LFF46&lt;br /&gt;
    .byte $d3,$ec,$46,$68,$80,$42,$39,$ea,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF56&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF66&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF76&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF86&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF96&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFA6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFB6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFC6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFD6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFE6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LFD3D = $FD3D&lt;br /&gt;
LFDB4 = $FDB4&lt;br /&gt;
LFDD5 = $FDD5&lt;br /&gt;
LFE18 = $FE18&lt;br /&gt;
LFE57 = $FE57  &lt;br /&gt;
LFE84 = $FE84&lt;br /&gt;
LFE96 = $FE96&lt;br /&gt;
LFED5 = $FED5&lt;br /&gt;
LFF00 = $FF00&lt;br /&gt;
&lt;br /&gt;
GccCopyright&lt;br /&gt;
       .byte $47,$43,$43,$28,$43,$29 ; 'GCC(C)'&lt;br /&gt;
       .byte $31,$39,$38,$34,$2D,$F7 ; '1984-'&lt;br /&gt;
&lt;br /&gt;
; Classic 6502 vectors. Called Cart* because they often&lt;br /&gt;
; are referenced when the game cart is switched in.&lt;br /&gt;
&lt;br /&gt;
CartNMIVectorLo&lt;br /&gt;
       .byte $00,$F0 ; system vector - nmi&lt;br /&gt;
CartResetVectorLo&lt;br /&gt;
       .word START   ; F884&lt;br /&gt;
CartIRQVectorLo&lt;br /&gt;
       .byte $33,$F9 ; system vector - irq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Main_Page&amp;diff=1257</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Main_Page&amp;diff=1257"/>
				<updated>2025-07-20T17:08:28Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Atari 7800 Development Wiki Home==&lt;br /&gt;
&lt;br /&gt;
Welcome to the &amp;lt;b&amp;gt;Atari 7800 Development wiki&amp;lt;/b&amp;gt;! This site aims to be the definitive source for accurate and up-to-date information on &amp;lt;b&amp;gt;programming the Atari 7800 console&amp;lt;/b&amp;gt;. If you're interested in &amp;lt;b&amp;gt;7800 homebrew&amp;lt;/b&amp;gt; programming, you've come to the right place!&lt;br /&gt;
&lt;br /&gt;
You can begin by checking out one of the links presented in the next section, or you may use the wiki search function to quickly find information on a specific topic.&lt;br /&gt;
&lt;br /&gt;
==Wiki Sections==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;The [[7800 Software Guide]] &lt;br /&gt;
:An updated version of the documentation originally produced by Atari and GCC. Several inaccuracies have been discovered and corrected, and new sections have been added.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800AsmDevKit]] &lt;br /&gt;
:A quick way to get started with programming the 7800 using assembly language. All the tools you need to create a game, cross-platform and available for multiple OSes. 7800.8bitdev.org is the official home of the 7800AsmDevKit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800basic]] &lt;br /&gt;
:A quick way to get started with programming the 7800 using a higher level language. 7800basic is a compiled language, designed for efficiency. 7800.8bitdev.org is the official home of 7800basic.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[7800 Tutorials and Guides]] &lt;br /&gt;
:Covers more advanced 7800 topics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[Emulators and Tools]] &lt;br /&gt;
:Covers information on tools useful to the 7800 developer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;[[Historic Documents]]&lt;br /&gt;
:Various Atari 7800 related historic documents.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1256</id>
		<title>7800 NTSC BIOS</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=7800_NTSC_BIOS&amp;diff=1256"/>
				<updated>2025-07-20T17:04:48Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: Created page with &amp;quot;==7800 NTSC BIOS==  This reverse engineered 7800 NTSC BIOS code contains helpful context-comments and builds a 1:1 with the released BIOS using DASM.   &amp;lt;pre&amp;gt; ; Disassembly of...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==7800 NTSC BIOS==&lt;br /&gt;
&lt;br /&gt;
This reverse engineered 7800 NTSC BIOS code contains helpful context-comments and builds a 1:1 with the released BIOS using DASM.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Disassembly of bios7800.bin&lt;br /&gt;
; Disassembled Sun Mar 08 20:30:38 1998&lt;br /&gt;
; Using DiStella v2.0&lt;br /&gt;
;&lt;br /&gt;
; Comments added by Keith Henrickson &amp;lt;flipper@phin.com&amp;gt;&lt;br /&gt;
; Further commented by Daniel Boris &amp;lt;dboris@home.com&amp;gt;&lt;br /&gt;
; Fixed to compile correctly with dasm, and additional comments by &lt;br /&gt;
; Mike Saarna. You can't have my email!&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
 processor 6502&lt;br /&gt;
&lt;br /&gt;
; some misc equates&lt;br /&gt;
LFD80 = $FD80&lt;br /&gt;
CartKey           = $FF80&lt;br /&gt;
CartRegion        = $FFF8&lt;br /&gt;
CartKeyStartPage  = $FFF9&lt;br /&gt;
CartResetVectorHi = $FFFD&lt;br /&gt;
LF112 = $F112&lt;br /&gt;
LF118 = $F118&lt;br /&gt;
LF460   =   $F460&lt;br /&gt;
LF700   =   $F700&lt;br /&gt;
LF800   =   $F800&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 7800 system&lt;br /&gt;
&lt;br /&gt;
INPTCTRL = $01&lt;br /&gt;
&lt;br /&gt;
; TIA&lt;br /&gt;
&lt;br /&gt;
VSYNC   =  $00&lt;br /&gt;
VBLANK  =  $01&lt;br /&gt;
WSYNC   =  $02&lt;br /&gt;
RSYNC   =  $03&lt;br /&gt;
COLUP0  =  $06&lt;br /&gt;
COLUPF  =  $08&lt;br /&gt;
COLUBK  =  $09&lt;br /&gt;
PF2     =  $0F&lt;br /&gt;
RESP1   =  $11&lt;br /&gt;
GRP0    =  $1B&lt;br /&gt;
GRP1    =  $1C&lt;br /&gt;
&lt;br /&gt;
;Maria&lt;br /&gt;
&lt;br /&gt;
BACKGRND =  $20&lt;br /&gt;
POC1     =  $21&lt;br /&gt;
P0C2     =  $22&lt;br /&gt;
POC3     =  $23&lt;br /&gt;
MWSYNC   =  $24&lt;br /&gt;
P1C1     =  $25&lt;br /&gt;
P1C2     =  $26&lt;br /&gt;
P1C3     =  $27&lt;br /&gt;
MSTAT    =  $28&lt;br /&gt;
DPPH     =  $2C&lt;br /&gt;
DPPL     =  $30&lt;br /&gt;
CTRL     =  $3C&lt;br /&gt;
&lt;br /&gt;
DLIAddr       =  $F4&lt;br /&gt;
ConsoleRegion = $FE&lt;br /&gt;
&lt;br /&gt;
       ORG $F000&lt;br /&gt;
&lt;br /&gt;
LF000: pha                ; This is the NMI routine.&lt;br /&gt;
       jmp (DLIAddr)      ; RAM NMI vector&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       ORG $F400&lt;br /&gt;
&lt;br /&gt;
; this code is designed to be executed while stored in ram at 2300.&lt;br /&gt;
LF400&lt;br /&gt;
SwitchTo2600Mode1&lt;br /&gt;
       jmp    $26C2                   ; Enter 2600 mode.&lt;br /&gt;
SwitchTo2600Mode2&lt;br /&gt;
       jmp    $26C2                   ; Enter 2600 mode.&lt;br /&gt;
&lt;br /&gt;
CartTest&lt;br /&gt;
       lda    #$16                    ; ($2306)&lt;br /&gt;
       sta    INPTCTRL                ; Switch in cart + enable Maria&lt;br /&gt;
&lt;br /&gt;
       ldy    #$FF                    ;&lt;br /&gt;
       ldx    #$7F                    ;&lt;br /&gt;
CartTestLoop&lt;br /&gt;
       lda    LFE00,X                 ; Compare same FE7F+ ROM with differing opcodes, &lt;br /&gt;
       cmp    LFD80,Y                 ;    to avoid false positives from a floating bus.&lt;br /&gt;
       bne    SwitchTo2600Mode1       ; Switch to 2600 mode&lt;br /&gt;
       dey                            ;&lt;br /&gt;
       dex                            ;&lt;br /&gt;
       bpl    CartTestLoop&lt;br /&gt;
&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       and    CartResetVectorHi       ;&lt;br /&gt;
       cmp    #$FF                    ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is FFFF, then go 2600.&lt;br /&gt;
       lda    CartResetVectorLo       ;&lt;br /&gt;
       ora    CartResetVectorHi       ;&lt;br /&gt;
       beq    SwitchTo2600Mode1       ; If RESET vector is 0000, then go 2600.&lt;br /&gt;
       lda    CartRegion              ; &amp;quot;Region verification&amp;quot;&lt;br /&gt;
       ora    #ConsoleRegion&lt;br /&gt;
       cmp    #$FF                    ; &lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low-bit of CartRegion=0, then go 2600.&lt;br /&gt;
       lda    CartRegion              ;&lt;br /&gt;
       eor    #$F0                    ; Invert high nibble&lt;br /&gt;
       and    #$F0                    ; Extract high nibble&lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If high nibble was not F, then go 2600.&lt;br /&gt;
       lda    CartKeyStartPage        ;&lt;br /&gt;
       and    #$0B                    ; &lt;br /&gt;
       cmp    #$03                    ; &lt;br /&gt;
       bne    SwitchTo2600Mode2       ; If low nibble FFF9 was not 3 or 7, go 2600.&lt;br /&gt;
       lda    CartKeyStartPage        ;&lt;br /&gt;
       and    #$F0                    ; Extract ROM start from high nibble&lt;br /&gt;
       sta    $EE                     ; Store it &lt;br /&gt;
       sta    $2406                   ; Store it a couple of places for auth. (whocares)&lt;br /&gt;
       cmp    #$40                    ;&lt;br /&gt;
       bcc    SwitchTo2600Mode2       ; If ROM start &amp;lt; than 4, then go 2600&lt;br /&gt;
       sbc    #$01                    ; Subtract 1.&lt;br /&gt;
       cmp    CartResetVectorHi       ; High byte of reset vector&lt;br /&gt;
       bcs    SwitchTo2600Mode2       ; If high-byte of start is &amp;gt;=, go 2600&lt;br /&gt;
       jsr    $2536                   ; Start the authentication process.&lt;br /&gt;
&lt;br /&gt;
       lda    #$00&lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       lda    #$16    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
       txa            &lt;br /&gt;
LF46D: sta    $1800,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bne    LF46D   &lt;br /&gt;
       pha            &lt;br /&gt;
       ldy    #$7F    &lt;br /&gt;
LF476: lda    LFF00,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       cpy    #$F8    &lt;br /&gt;
       bne    LF476   &lt;br /&gt;
       lda    #$2E    &lt;br /&gt;
       sta    $2409   &lt;br /&gt;
       lda    #$24    &lt;br /&gt;
       sta    $240A   &lt;br /&gt;
&lt;br /&gt;
LF48B&lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       pla            &lt;br /&gt;
       jsr    $23FF   &lt;br /&gt;
       pha            &lt;br /&gt;
       inc    $2406   &lt;br /&gt;
       lda    $2406   &lt;br /&gt;
       cmp    #$FF    &lt;br /&gt;
       bne    LF48B   &lt;br /&gt;
&lt;br /&gt;
       jsr    $241B   &lt;br /&gt;
       jsr    $2412   &lt;br /&gt;
       jsr    $2412   &lt;br /&gt;
       lda    #$36    &lt;br /&gt;
       sta    $2409   &lt;br /&gt;
       lda    #$24    &lt;br /&gt;
       sta    $240A   &lt;br /&gt;
       dec    $2406   &lt;br /&gt;
LF4B3: jsr    $241B   &lt;br /&gt;
       pla            &lt;br /&gt;
       jsr    $23FF   &lt;br /&gt;
       pha            &lt;br /&gt;
       dec    $2406   &lt;br /&gt;
       lda    $2406   &lt;br /&gt;
       cmp    $EE     &lt;br /&gt;
       bcs    LF4B3   &lt;br /&gt;
       lda    #$60    &lt;br /&gt;
       sta    CTRL   &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
LF4CB: lda    $1800,X &lt;br /&gt;
       eor    $1850,X &lt;br /&gt;
       eor    $1888,X &lt;br /&gt;
       sta    $1A00,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF4CB   &lt;br /&gt;
       lda    $1A00   &lt;br /&gt;
       and    #$07    &lt;br /&gt;
       sta    $1A00   &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       ldx    #$04    &lt;br /&gt;
       sta    $1A00,X &lt;br /&gt;
       sta    $2000,X &lt;br /&gt;
       ldx    #$77         ; That was a lot, but we end up here, comparing&lt;br /&gt;
LF4EE: lda    $2000,X      ; two parts of memory.  If they match, then&lt;br /&gt;
       cmp    $1A00,X      ; go to 7800 mode....&lt;br /&gt;
       bne    LF4FC        ; otherwise go to 2600 mode.&lt;br /&gt;
       dex                 ; nop out above branch to allow user-written&lt;br /&gt;
       bpl    LF4EE        ; carts to run -- I think.&lt;br /&gt;
       jmp    $26B9        ; 7800 mode init&lt;br /&gt;
LF4FC: jmp    $26C2        ; 2600 mode init.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LF500 =  $F500             ; F500 is partway through the next opcode&lt;br /&gt;
       ldx    #$00         ; more authentication stuff all the way through&lt;br /&gt;
LF501: adc    $1800,X&lt;br /&gt;
       adc    LFF00,X &lt;br /&gt;
       tay            &lt;br /&gt;
       lda    $2DD5,Y &lt;br /&gt;
       sta    $1800,X &lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LF501   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
LF514: rol    $1800,X &lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LF514   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
;$241B&lt;br /&gt;
       php            &lt;br /&gt;
       dec    $F0     &lt;br /&gt;
       bpl    LF52C   &lt;br /&gt;
       lda    #$02    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
LF524: lda    $F0     &lt;br /&gt;
       bmi    LF524   &lt;br /&gt;
       lda    #$16    &lt;br /&gt;
       sta    INPTCTRL  &lt;br /&gt;
LF52C: plp            &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF52E: .byte $C7,$65,$AB,$CA,$EE,$F7,$83,$09&lt;br /&gt;
LF536: .byte $E1,$D0,$92,$67,$62,$B6,$72,$55,$8E,$91,$DC,$C5,$81,$BE,$78,$20&lt;br /&gt;
       .byte $59,$B7,$E6,$3D,$06,$45,$AF,$C8,$08,$31,$38,$D1,$FB,$73,$84,$A9&lt;br /&gt;
       .byte $17,$FC,$34,$87,$A3,$94,$FA,$90,$B8,$ED,$CE,$3B,$5B,$0A,$43,$D9&lt;br /&gt;
       .byte $F3,$53,$82,$B3,$0D,$6D,$5A,$60,$9D,$51,$A7,$B9&lt;br /&gt;
LF572: .byte $11,$10,$BC,$E4,$7F,$80,$41,$E7,$E3&lt;br /&gt;
LF57B: .byte $F6,$56,$26,$35,$EC,$D6,$DF,$0C,$7F,$F4,$9E,$AC,$52,$46,$EF,$CF&lt;br /&gt;
       .byte $BF,$A2,$3F,$A4,$13,$15,$97,$4A,$1C,$B0,$42,$8C,$B1,$05,$58,$80&lt;br /&gt;
       .byte $18,$77,$2B,$02,$3E,$A8,$49,$1A,$6A&lt;br /&gt;
LF5A4: .byte $CB,$6E,$0B,$8A,$EB,$F1,$4F,$14,$79,$8B,$D8,$9F,$9B,$57,$19,$F8&lt;br /&gt;
       .byte $2A,$2D,$76,$0E,$E8,$2E,$4B,$F9,$07,$03,$DE,$93,$16,$7E,$D4,$E5&lt;br /&gt;
       .byte $B2,$F0,$7D,$7A,$DA,$D2,$A1,$CC,$1D,$E0,$5E,$23,$A0,$95,$22,$1E&lt;br /&gt;
       .byte $36,$85,$FE,$1F,$39&lt;br /&gt;
LF5D9: .byte $AA,$89,$96,$AD,$0F,$2F,$C0,$47&lt;br /&gt;
LF5E1: .byte $27,$5D,$24,$EA,$C3,$A5,$F5,$21,$5F,$1B,$40,$8F,$AE,$74,$25,$DD&lt;br /&gt;
       .byte $C1,$7C,$CD,$A6,$70,$D7,$33,$7B,$2C,$75,$BB,$86,$99,$BD,$54&lt;br /&gt;
LF600: .byte $9A,$6C,$63,$32,$48,$4C,$8D,$BA&lt;br /&gt;
LF608: .byte $5C,$61,$C4,$4E,$29,$37,$12,$C6,$98,$9C,$D5,$69,$6B,$E2,$04,$4D&lt;br /&gt;
       .byte $E9,$C2,$88,$3A,$DB,$64,$01,$44,$6F,$B5,$F2,$30,$28,$FD,$50,$71&lt;br /&gt;
       .byte $3C,$B4,$66,$68,$C9,$D3,$CA,$83,$C7,$AB,$F7,$65,$09,$EE&lt;br /&gt;
&lt;br /&gt;
       ldx    #$77      ;($2536)&lt;br /&gt;
       stx    $E4     &lt;br /&gt;
       stx    $E5     &lt;br /&gt;
LF63C: lda    CartKey,X   ;Read Key&lt;br /&gt;
       sta    $1901,X           ;Store it&lt;br /&gt;
       sta    $2000,X           ;Store it again&lt;br /&gt;
       dex                      ;next byte of key&lt;br /&gt;
       bpl    LF63C             ;Continue&lt;br /&gt;
&lt;br /&gt;
       lda    #$02      ;&lt;br /&gt;
       sta    INPTCTRL  ;Disable cart &lt;br /&gt;
       jsr    LFB84     ;Init display&lt;br /&gt;
       jsr    $257B   &lt;br /&gt;
       dec    $F2     &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
       stx    $E4     &lt;br /&gt;
LF658: lda    LFED5,X &lt;br /&gt;
       sta    $1901,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF658   &lt;br /&gt;
       lda    $E1     &lt;br /&gt;
       sta    $E3     &lt;br /&gt;
       jsr    $25E1   &lt;br /&gt;
       dec    $F2     &lt;br /&gt;
LF66A: lda    $E0     &lt;br /&gt;
       sta    $2572   &lt;br /&gt;
       ldx    #$77    &lt;br /&gt;
LF671: lda    $1800,X &lt;br /&gt;
LF674: sta    $2000,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF671   &lt;br /&gt;
       rts            &lt;br /&gt;
    &lt;br /&gt;
       jsr    $2639   ;($257B)&lt;br /&gt;
       ldy    $E5     &lt;br /&gt;
       iny            &lt;br /&gt;
LF681: STY    $E1     &lt;br /&gt;
       TYA            &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    $E2     &lt;br /&gt;
       pha            &lt;br /&gt;
LF688: tax            &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       sta    $2671   &lt;br /&gt;
LF68E: sta    $1800,X &lt;br /&gt;
       dex            &lt;br /&gt;
LF692: bne    LF68E   &lt;br /&gt;
       sta    $1800   &lt;br /&gt;
LF697: iny            &lt;br /&gt;
       STY    $266E   &lt;br /&gt;
       STY    $2674   &lt;br /&gt;
       STY    $267C   &lt;br /&gt;
       STY    $2681   &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
LF6A6: dec    $266E   &lt;br /&gt;
LF6A9: dec    $2674   &lt;br /&gt;
LF6AC: dec    $267C   &lt;br /&gt;
       dec    $2681   &lt;br /&gt;
       dec    $E1     &lt;br /&gt;
       bmi    LF6D1   &lt;br /&gt;
LF6B6: ldy    $E1     &lt;br /&gt;
       lda    $2000,Y &lt;br /&gt;
       and    $25D9,X &lt;br /&gt;
       beq    LF6C9   &lt;br /&gt;
       lda    $2662,X &lt;br /&gt;
       sta    $2672   &lt;br /&gt;
       jsr    $266A   &lt;br /&gt;
LF6C9: inx            &lt;br /&gt;
       cpx    #$08    &lt;br /&gt;
       bmi    LF6B6   &lt;br /&gt;
       jmp    $25A4   &lt;br /&gt;
LF6D1: pla            &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       lda    #$01    &lt;br /&gt;
       sta    $E0     &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF6D9: .byte $01,$02,$04,$08,$10,$20,$40,$80&lt;br /&gt;
&lt;br /&gt;
       jsr    $2639&lt;br /&gt;
       lda    $E3     &lt;br /&gt;
       sec            &lt;br /&gt;
       sbc    $E4     &lt;br /&gt;
       sta    $E0     &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       ldx    #$00    &lt;br /&gt;
       stx    $1800   &lt;br /&gt;
       stx    $268F   &lt;br /&gt;
       stx    $26AC   &lt;br /&gt;
       dex            &lt;br /&gt;
       stx    $26A9   &lt;br /&gt;
       stx    $268C   &lt;br /&gt;
       stx    $2692   &lt;br /&gt;
       stx    $269A   &lt;br /&gt;
       stx    $269F   &lt;br /&gt;
       ldx    #$07    &lt;br /&gt;
       inc    $26A9   &lt;br /&gt;
       inc    $268C   &lt;br /&gt;
       inc    $2692   &lt;br /&gt;
       inc    $269A   &lt;br /&gt;
       inc    $269F   &lt;br /&gt;
       dec    $E1     &lt;br /&gt;
       bmi    LF734   &lt;br /&gt;
LF71D: lda    $2662,X &lt;br /&gt;
       sta    $2690   &lt;br /&gt;
       sta    $26AD   &lt;br /&gt;
       jsr    $26A6   &lt;br /&gt;
       bcc    LF72E   &lt;br /&gt;
       jsr    $2688   &lt;br /&gt;
LF72E: dex            &lt;br /&gt;
       bpl    LF71D   &lt;br /&gt;
       jmp    $2608   &lt;br /&gt;
LF734: lda    $E3     &lt;br /&gt;
       sta    $E1     &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
       ldx    $E4   ;($2639)&lt;br /&gt;
       inx            &lt;br /&gt;
       stx    $E2     &lt;br /&gt;
       ldy    #$00    &lt;br /&gt;
       STY    $1900   &lt;br /&gt;
LF743: lda    $2662,Y &lt;br /&gt;
       sta    $2655   &lt;br /&gt;
       iny            &lt;br /&gt;
       lda    $2662,Y &lt;br /&gt;
       sta    $2659   &lt;br /&gt;
       ldx    $E2     &lt;br /&gt;
       clc            &lt;br /&gt;
LF753: lda    $1900,X &lt;br /&gt;
       rol&lt;br /&gt;
       sta    $1900,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF753   &lt;br /&gt;
       cpy    #$07    &lt;br /&gt;
       bmi    LF743   &lt;br /&gt;
       rts            &lt;br /&gt;
&lt;br /&gt;
LF762: .byte $19,$1A,$1B,$1C,$1D,$1E,$1F,$21&lt;br /&gt;
&lt;br /&gt;
       ldy    $E2&lt;br /&gt;
       clc            &lt;br /&gt;
LF76D: lda    $1800,Y &lt;br /&gt;
       adc    $1900,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       bpl    LF76D   &lt;br /&gt;
       bcc    LF787   &lt;br /&gt;
       lda    $1700,Y &lt;br /&gt;
       adc    #$00    &lt;br /&gt;
       sta    $1700,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       jmp    $2679   &lt;br /&gt;
LF787: rts            &lt;br /&gt;
&lt;br /&gt;
       ldy    $E2     &lt;br /&gt;
       sec            &lt;br /&gt;
LF78B: lda    $1800,Y &lt;br /&gt;
       sbc    $1900,Y &lt;br /&gt;
       sta    $1800,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       bpl    LF78B   &lt;br /&gt;
       bcs    LF7A5   &lt;br /&gt;
       lda    $1700,Y &lt;br /&gt;
       sbc    #$00    &lt;br /&gt;
       sta    $1700,Y &lt;br /&gt;
       dey            &lt;br /&gt;
       jmp    $2697   &lt;br /&gt;
LF7A5: rts            &lt;br /&gt;
&lt;br /&gt;
       ldy    #$00    &lt;br /&gt;
       lda    $1800,Y &lt;br /&gt;
       cmp    $1900,Y &lt;br /&gt;
       beq    LF7B1   &lt;br /&gt;
LF7B0: rts            &lt;br /&gt;
&lt;br /&gt;
LF7B1: cpy    $E2     &lt;br /&gt;
       beq    LF7B0   &lt;br /&gt;
       iny            &lt;br /&gt;
       jmp    $26A8   &lt;br /&gt;
&lt;br /&gt;
LF7B9:                    ; ($26B9) 7800 mode init&lt;br /&gt;
       ldx    #$16        ; finally, back to something important&lt;br /&gt;
       stx    INPTCTRL    ; switch out bios and use reset vector&lt;br /&gt;
       txs                ; on cart to start the game.&lt;br /&gt;
       SED            &lt;br /&gt;
       jmp (CartResetVectorLo)     &lt;br /&gt;
&lt;br /&gt;
; Enable 2600 mode&lt;br /&gt;
LF7C2:                    ; ($26C2) 2600 mode init&lt;br /&gt;
       lda    #$02        ; Enable memory/bios&lt;br /&gt;
       sta    INPTCTRL    ; &lt;br /&gt;
       ldx    #$7F&lt;br /&gt;
LF7C8: lda    LF7D4,X     ; again, copy code to ram....&lt;br /&gt;
       sta    $0480,X &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF7C8   &lt;br /&gt;
       jmp    $0480       ; execute it&lt;br /&gt;
&lt;br /&gt;
; code executed at $0480 (RIOT RAM)&lt;br /&gt;
&lt;br /&gt;
LF7D4: lda    #$00        ; &lt;br /&gt;
       tax                ; &lt;br /&gt;
       sta    INPTCTRL    ; Disable 7800 RAM&lt;br /&gt;
LF7D9: sta    RSYNC,X     ; Clear the TIA&lt;br /&gt;
       inx                ;&lt;br /&gt;
       cpx    #$2A        ;&lt;br /&gt;
       bne    LF7D9       ;&lt;br /&gt;
       sta    WSYNC       ; wait for sync&lt;br /&gt;
       lda    #$04        ;&lt;br /&gt;
       nop                ;&lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
       ldx    #$04    &lt;br /&gt;
LF7E9: dex            &lt;br /&gt;
       bpl    LF7E9   &lt;br /&gt;
       txs            &lt;br /&gt;
       sta    $0110   &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       sta    RESP1   &lt;br /&gt;
       sta    GRP0    &lt;br /&gt;
       sta    GRP1    &lt;br /&gt;
       sta    PF2     &lt;br /&gt;
       nop            &lt;br /&gt;
       sta    WSYNC   &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
       nop            &lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
       bit    RSYNC   &lt;br /&gt;
       bmi    LF813   &lt;br /&gt;
LF80A: lda    #$02    &lt;br /&gt;
       sta    COLUBK  &lt;br /&gt;
       sta    LF112   &lt;br /&gt;
       bne    LF831   &lt;br /&gt;
LF813: bit    WSYNC   &lt;br /&gt;
       bmi    LF823   &lt;br /&gt;
       lda    #$02    &lt;br /&gt;
       sta    COLUP0  &lt;br /&gt;
       sta    LF118   &lt;br /&gt;
       sta    LF460   &lt;br /&gt;
       bne    LF831   &lt;br /&gt;
LF823: sta    DPPH   &lt;br /&gt;
       lda    #$08    &lt;br /&gt;
       sta    GRP0    &lt;br /&gt;
       jsr    $04CB   &lt;br /&gt;
       nop            &lt;br /&gt;
       bit    WSYNC   &lt;br /&gt;
       bmi    LF80A   &lt;br /&gt;
LF831: lda    #$FD    &lt;br /&gt;
       sta    COLUPF  &lt;br /&gt;
       jmp (CartResetVectorLo)        ; And use the reset vector on the cart to start&lt;br /&gt;
       nop                            ; the 2600 game.&lt;br /&gt;
&lt;br /&gt;
       ORG $F880&lt;br /&gt;
&lt;br /&gt;
LF880: lda    #$1D        ; this is called any time the self-test fails.&lt;br /&gt;
       sta    INPTCTRL    ; Eanble TIA/Cart/lock out INPTCTRL&lt;br /&gt;
&lt;br /&gt;
START:                    ; $F884 &lt;br /&gt;
       SEI                ; BIOS entry point.  Disable interrupts&lt;br /&gt;
       CLD                ; Clear decimal flag&lt;br /&gt;
       lda    #$02        ;&lt;br /&gt;
LF888: sta    INPTCTRL    ; Enable 7800 RAM&lt;br /&gt;
       lda    #$FB        ;&lt;br /&gt;
       sta    $F5         ;&lt;br /&gt;
       lda    #$12        ;&lt;br /&gt;
       sta    $F4         ; set nmi vector to FB12. (shares cleanup of irq)&lt;br /&gt;
       lda    #$7F        ;&lt;br /&gt;
       sta    CTRL        ; Turn off DMA&lt;br /&gt;
       lda    #$00        ;&lt;br /&gt;
       sta    BACKGRND    ; Background color&lt;br /&gt;
       ldx    #$05        ;&lt;br /&gt;
LF89C: lda    LF91D,X     ; looks icky, but it's just a ram test&lt;br /&gt;
       ldy    #$00        ;&lt;br /&gt;
LF8A1: sta    $2000,Y     ;&lt;br /&gt;
       cmp    $2000,Y     ;&lt;br /&gt;
       bne    LF8D0       ; Test failed&lt;br /&gt;
       sta    $2100,Y     ;&lt;br /&gt;
       cmp    $2100,Y     ;&lt;br /&gt;
       bne    LF8D0       ; Test failed&lt;br /&gt;
       dey                ;&lt;br /&gt;
       bne    LF8A1       ;&lt;br /&gt;
       dex                ;&lt;br /&gt;
       bpl    LF89C       ; and right down here, it passes&lt;br /&gt;
       lda    #$43        ; Check RAM 0 mirror&lt;br /&gt;
       sta    $2080       ; &lt;br /&gt;
       cmp    $80         ; &lt;br /&gt;
       bne    LF8CB       ; make sure they match. If not, fail selftest.&lt;br /&gt;
       sta    $2180       ; Check RAM 1 mirror&lt;br /&gt;
       cmp    $0180       ; &lt;br /&gt;
       bne    LF8CB       ; make sure they match. If not, fail selftest.&lt;br /&gt;
       jmp    LF938       ; continue selftest&lt;br /&gt;
LF8CB: ldy    #$04        ;&lt;br /&gt;
       jmp    LF880       ; selftest fail.&lt;br /&gt;
&lt;br /&gt;
LF8D0: sta    $1800       ; test store and compare&lt;br /&gt;
       cmp    $1800   &lt;br /&gt;
       bne    LF8E2       ; some kind of error code is being determined&lt;br /&gt;
LF8D8: ldy    #$01    &lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
LF8DD: ldy    #$02&lt;br /&gt;
       jmp    $F880&lt;br /&gt;
&lt;br /&gt;
LF8E2: ldy    #$03&lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
LF8E7: lda    #$00        ; this is a more comprehensive ram test than&lt;br /&gt;
       sta    $F0         ; the first routine, and it is called after&lt;br /&gt;
       sta    $F2         ; more of the selftest has completed.&lt;br /&gt;
       ldy    #$07    &lt;br /&gt;
       STY    $F4     &lt;br /&gt;
LF8F1: lda    LF923,Y &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       lda    LF92B,Y &lt;br /&gt;
       sta    $F3     &lt;br /&gt;
       ldx    #$05    &lt;br /&gt;
LF8FD: lda    LF91D,X &lt;br /&gt;
LF900: ldy    #$00    &lt;br /&gt;
LF902: sta    ($F0),Y &lt;br /&gt;
       cmp    ($F0),Y &lt;br /&gt;
       bne    LF8D8   &lt;br /&gt;
       sta    ($F2),Y &lt;br /&gt;
       cmp    ($F2),Y &lt;br /&gt;
       bne    LF8DD   &lt;br /&gt;
       dey            &lt;br /&gt;
       bne    LF902   &lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LF8FD   &lt;br /&gt;
       dec    $F4     &lt;br /&gt;
       ldy    $F4     &lt;br /&gt;
       bpl    LF8F1   &lt;br /&gt;
       jmp    LFB17       ; ram test passed, so jump in here.&lt;br /&gt;
&lt;br /&gt;
; ram test data&lt;br /&gt;
LF91D: .byte $00,$FF,$55,$AA,$69,$0F&lt;br /&gt;
LF923: .byte $22,$23,$24,$25,$26,$27,$22,$23&lt;br /&gt;
LF92B: .byte $18,$19,$1A,$1B,$1C,$1D,$1E,$1F&lt;br /&gt;
&lt;br /&gt;
LF933: ldy    #$00       ; local place for selftest fail branch target&lt;br /&gt;
       jmp    LF880   &lt;br /&gt;
&lt;br /&gt;
; 6502 CPU test&lt;br /&gt;
&lt;br /&gt;
LF938: lda    #$AA       ; test some flags and branches&lt;br /&gt;
       beq    LF933      ; test failed&lt;br /&gt;
       bpl    LF933      ; test failed&lt;br /&gt;
       bmi    LF943      ; test passed&lt;br /&gt;
       jmp    LF933      ; test failed&lt;br /&gt;
LF943: bne    LF948      ; test passed&lt;br /&gt;
       jmp    LF933      ; test failed&lt;br /&gt;
LF948: sta    $AA        ; store AA to 00AA&lt;br /&gt;
       cmp    $AA        ; compare it back&lt;br /&gt;
       bne    LF933      ; if it doesn't match, selftest fail&lt;br /&gt;
       lda    #$00       ; do some more flag tests&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       bmi    LF933      ;&lt;br /&gt;
       bpl    LF959      ; test passed&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF959: beq    LF95E      ; test passed&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF95E: cmp    #$00       ; test the compare instruction&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       bcc    LF933      ;&lt;br /&gt;
       bcs    LF969      ; test passed, since they're equal&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF969: cmp    #$01       ; compare it to 01&lt;br /&gt;
       bcs    LF933      ;&lt;br /&gt;
       bcc    LF972      ; A &amp;lt; 01, so carry is clear&lt;br /&gt;
       jmp    LF933      ;&lt;br /&gt;
LF972: ldx    #$55       ; test comparisons with the X register&lt;br /&gt;
       cpx    #$56       ;&lt;br /&gt;
       beq    LF933      ;&lt;br /&gt;
       stx    $01AA      ;&lt;br /&gt;
       cpx    $01AA      ;&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       ldy    $AA        ; and with the Y register.&lt;br /&gt;
       cpy    #$AB       ;&lt;br /&gt;
LF984: beq    LF933      ;&lt;br /&gt;
       STY    $0155      ; put some stuff in the stack area to test stack&lt;br /&gt;
       cpy    $0155      ; and then access this data in many diffeent ways&lt;br /&gt;
       bne    LF933      ;&lt;br /&gt;
       dex               ;&lt;br /&gt;
       txs               ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       pla               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       txa               ;&lt;br /&gt;
       pha               ;&lt;br /&gt;
       cpx    $0155      ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       TYA               ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       tax               ;&lt;br /&gt;
       lda    $0100,X    ;&lt;br /&gt;
       tay               ;&lt;br /&gt;
       cpy    #$55       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    VSYNC,X    ;&lt;br /&gt;
       cmp    $AA        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    #$AA       ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       eor    #$FF       ;&lt;br /&gt;
       sta    $0000,Y    ;&lt;br /&gt;
       cmp    $55        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    $0100,Y    ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       cmp    $20AB,X    ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    #$20       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       lda    #$CC       ;&lt;br /&gt;
       sta    $F0        ;&lt;br /&gt;
       sta    ($46,X)    ;&lt;br /&gt;
       cmp    $CC        ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       sta    ($F0),Y    ;&lt;br /&gt;
       cmp    $2121      ;&lt;br /&gt;
       bne    LF9EB      ;&lt;br /&gt;
       lda    #$EE       ; test the indirect jump by setting up a jump&lt;br /&gt;
       sta    $F0        ; to F9EE&lt;br /&gt;
       lda    #$F9       ;&lt;br /&gt;
       sta    $F1        ;&lt;br /&gt;
       jmp ($00F0)        ; and do it.&lt;br /&gt;
&lt;br /&gt;
LF9E8: jmp    $F9EB&lt;br /&gt;
&lt;br /&gt;
LF9EB: jmp    LF933&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LF9EE: lda    #$55       ; now test out the math functions.&lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$55    &lt;br /&gt;
       nop            &lt;br /&gt;
       bcs    LF9EB      ; test addition.&lt;br /&gt;
       bpl    LF9EB   &lt;br /&gt;
       beq    LF9EB   &lt;br /&gt;
       cmp    #$AA       ; make sure it worked&lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       adc    #$55       ; test addition again.&lt;br /&gt;
LFA00: nop            &lt;br /&gt;
       bcc    LF9EB   &lt;br /&gt;
       bmi    LF9EB   &lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       sbc    #$55       ; test subtraction&lt;br /&gt;
       bcs    LF9EB   &lt;br /&gt;
       bpl    LF9EB   &lt;br /&gt;
       beq    LF9EB   &lt;br /&gt;
       cmp    #$AB       ; make sure it worked&lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       clc            &lt;br /&gt;
       sbc    #$AA       ; test subtraction again&lt;br /&gt;
       bcc    LF9EB   &lt;br /&gt;
       bmi    LF9EB   &lt;br /&gt;
       bne    LF9EB   &lt;br /&gt;
       lda    #$FF       ; set up a stack&lt;br /&gt;
       tax               ; and do all kinds of stuff in it for tests&lt;br /&gt;
       inx            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dex            &lt;br /&gt;
       beq    LFA58   &lt;br /&gt;
       bpl    LFA58   &lt;br /&gt;
       cpx    #$FF    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       tay            &lt;br /&gt;
       iny            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dey            &lt;br /&gt;
       beq    LFA58      &lt;br /&gt;
       iny            &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       inc    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       cpy    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       dec    $F0     &lt;br /&gt;
       beq    LFA58   &lt;br /&gt;
       cmp    $F0     &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       lda    #$AA    &lt;br /&gt;
       clc            &lt;br /&gt;
       rol               ; now we get onto the more complex math instrs&lt;br /&gt;
       rol&lt;br /&gt;
       rol&lt;br /&gt;
       cmp    #$52    &lt;br /&gt;
       bne    LFA58      ; make sure rotate left works.&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       ror&lt;br /&gt;
       cmp    #$AA    &lt;br /&gt;
       beq    LFA5B      ; test rotate right&lt;br /&gt;
LFA58: jmp    LF933      ; fail!&lt;br /&gt;
&lt;br /&gt;
LFA5B: asl               ; test arithmetic shift left&lt;br /&gt;
       bcc    LFA58   &lt;br /&gt;
       asl            &lt;br /&gt;
       bcs    LFA58   &lt;br /&gt;
       asl            &lt;br /&gt;
       cmp    #$50    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       eor    #$05    &lt;br /&gt;
       lsr               ; and logical shift right&lt;br /&gt;
       bcc    LFA58   &lt;br /&gt;
       lsr            &lt;br /&gt;
       bcs    LFA58   &lt;br /&gt;
       lsr            &lt;br /&gt;
       cmp    #$0A    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       lda    #$55       ; now test the ands and ors.&lt;br /&gt;
       ora    #$1B    &lt;br /&gt;
       cmp    #$5F    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       and    #$55    &lt;br /&gt;
       and    #$1B    &lt;br /&gt;
       cmp    #$11    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       ora    #$55    &lt;br /&gt;
       eor    #$1B       ; and the eors&lt;br /&gt;
       cmp    #$4E    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       jsr    LFA91      ; test jump subroutine instruction&lt;br /&gt;
       jmp    LFA58      ; if we return, fail&lt;br /&gt;
&lt;br /&gt;
LFA91: tsx               &lt;br /&gt;
       cpx    #$52       ; check stack pointer&lt;br /&gt;
       bne    LFA58      ; fail if not right&lt;br /&gt;
       pla            &lt;br /&gt;
       cmp    #$8D    &lt;br /&gt;
       bne    LFA58   &lt;br /&gt;
       pla            &lt;br /&gt;
       cmp    #$FA    &lt;br /&gt;
       bne    LFA58      ; get the old return address off the stack&lt;br /&gt;
       lda    #$F8    &lt;br /&gt;
       pha            &lt;br /&gt;
       lda    #$E6    &lt;br /&gt;
       pha               ; and make our own&lt;br /&gt;
       rts               ; and 'return' to F8E7&lt;br /&gt;
&lt;br /&gt;
       jmp    LFA58      ; another jump to catch a failure&lt;br /&gt;
&lt;br /&gt;
; Interrupt routine  NMI. &lt;br /&gt;
&lt;br /&gt;
LFAAA: txa          ;Save A&lt;br /&gt;
       pha          ;  &lt;br /&gt;
       lda    #$43  ;Setup control register  &lt;br /&gt;
       sta    CTRL  ; &lt;br /&gt;
       ldx    #$0F  ; Handle the color scrolling in the FUJI    &lt;br /&gt;
       lda    $EF     &lt;br /&gt;
       sta    P0C2&lt;br /&gt;
       bit    $F3     &lt;br /&gt;
       bvc    LFAC0   &lt;br /&gt;
       bpl    LFABE   &lt;br /&gt;
LFABC: sta    MWSYNC ;Wait for 3 scanlines &lt;br /&gt;
LFABE: sta    MWSYNC ;    &lt;br /&gt;
LFAC0: sta    MWSYNC ;   &lt;br /&gt;
       sec            &lt;br /&gt;
       sbc    #$10  &lt;br /&gt;
       cmp    #$10    &lt;br /&gt;
       bcs    LFACB   &lt;br /&gt;
       sbc    #$0F    &lt;br /&gt;
LFACB: sta    P0C2&lt;br /&gt;
       dex            &lt;br /&gt;
       bpl    LFABC   ;Branch to do next section of fuji&lt;br /&gt;
       ldx    #$40    ;set 160x2/160x4 mode&lt;br /&gt;
       stx    CTRL    ;  &lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$0E    ;set Palette 1 color 3&lt;br /&gt;
       sta    P1C3    ;&lt;br /&gt;
       lda    $EF     ;&lt;br /&gt;
       and    #$F0    ;&lt;br /&gt;
       ora    #$06    ;set Palette 1 color 1&lt;br /&gt;
       sta    P1C1    ;&lt;br /&gt;
       and    #$F0    &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$40    &lt;br /&gt;
       bcc    LFAEB   &lt;br /&gt;
       adc    #$0F    &lt;br /&gt;
LFAEB: ora    #$03   ;set Palette 1 color 2  &lt;br /&gt;
       sta    P1C2  &lt;br /&gt;
       dec    $F1     &lt;br /&gt;
       bpl    LFB0C   &lt;br /&gt;
       lda    $F3     &lt;br /&gt;
       adc    #$60    &lt;br /&gt;
       bcc    LFB0A   &lt;br /&gt;
       lda    $EF     &lt;br /&gt;
       clc            &lt;br /&gt;
       adc    #$10    &lt;br /&gt;
       bcc    LFB02   &lt;br /&gt;
       adc    #$0F    &lt;br /&gt;
LFB02: sta    $EF     &lt;br /&gt;
       lda    $F2     &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       lda    #$00    &lt;br /&gt;
LFB0A: sta    $F3     &lt;br /&gt;
LFB0C: lda    #$02    &lt;br /&gt;
       sta    $F0     &lt;br /&gt;
       pla            &lt;br /&gt;
       tax            &lt;br /&gt;
       pla            &lt;br /&gt;
       rti            &lt;br /&gt;
&lt;br /&gt;
LFB14: jmp    LFB14   &lt;br /&gt;
&lt;br /&gt;
LFB17: ldx    #$FF       ; selftest has passed, start system init&lt;br /&gt;
       txs               ; set up a stack&lt;br /&gt;
       lda    #$00       ; Clear TIA/Maria registers&lt;br /&gt;
       tax               ;&lt;br /&gt;
LFB1D: sta    $01,X ;    ;&lt;br /&gt;
       inx               ;&lt;br /&gt;
       cpx    #$2C       ;&lt;br /&gt;
       bne    LFB1D      ; &lt;br /&gt;
       lda    #$02       ;&lt;br /&gt;
       sta    INPTCTRL   ; Enable 7800 RAM &lt;br /&gt;
       ldx    #$00       ;&lt;br /&gt;
       stx    BACKGRND   ; Set background color &lt;br /&gt;
LFB2C: lda    LF400,X    ; copy the authentication and title screen to &lt;br /&gt;
       sta    $2300,X    ; ram&lt;br /&gt;
       lda    LF500,X    ;&lt;br /&gt;
       sta    $2400,X    ;&lt;br /&gt;
       lda    LF600,X    ;&lt;br /&gt;
       sta    $2500,X    ;&lt;br /&gt;
       lda    LF700,X    ;&lt;br /&gt;
       sta    $2600,X    ;&lt;br /&gt;
       lda    LF800,X    ;&lt;br /&gt;
       sta    $2700,X    ;&lt;br /&gt;
       lda    LFBBE,X    ;&lt;br /&gt;
       sta    $2200,X    ;&lt;br /&gt;
       cpx    #$00       ;&lt;br /&gt;
       bmi    LFB7E      ;&lt;br /&gt;
       lda    LFC4B,X     ;&lt;br /&gt;
       sta    $1F84,X     ;&lt;br /&gt;
       lda    LFCC6,X     ;&lt;br /&gt;
       sta    $1984,X     ;&lt;br /&gt;
       lda    LFD3D,X     ;&lt;br /&gt;
       sta    $1A84,X     ;&lt;br /&gt;
       lda    LFDB4,X     ;&lt;br /&gt;
       sta    $1B84,X     ;&lt;br /&gt;
       lda    LFE18,X     ;&lt;br /&gt;
       sta    $1C84,X     ;&lt;br /&gt;
       lda    LFE57,X     ;&lt;br /&gt;
       sta    $1D84,X     ;&lt;br /&gt;
       lda    LFE96,X     ;&lt;br /&gt;
       sta    $1E84,X     ;&lt;br /&gt;
LFB7E: dex                ;&lt;br /&gt;
       bne    LFB2C       ;&lt;br /&gt;
       jmp    $2306       ; and execute it&lt;br /&gt;
&lt;br /&gt;
;Start display of Atari logo&lt;br /&gt;
&lt;br /&gt;
LFB84: lda    CartKeyStartPage      ; Read ROM start byte from cart&lt;br /&gt;
       and    #$04       ; Is rom start greater then $4000?&lt;br /&gt;
       beq    LFBBD      ; Branch if not&lt;br /&gt;
       lda    #$03      &lt;br /&gt;
       sta    $F1     &lt;br /&gt;
       sta    $F2     &lt;br /&gt;
       lda    #$49    &lt;br /&gt;
       sta    $EF     &lt;br /&gt;
       lda    #$66       ;Palette 1 Color 1&lt;br /&gt;
       sta    P1C1       ;&lt;br /&gt;
       lda    #$56       ;Palette 1 Color 2&lt;br /&gt;
       sta    P1C2       ;&lt;br /&gt;
       lda    #$2E       ;Palette 1 Color 3&lt;br /&gt;
       sta    P1C3       ;&lt;br /&gt;
       lda    #$AA       ;Set NMI vector to FAAA&lt;br /&gt;
       sta    $F4        ;&lt;br /&gt;
       lda    #$FA       ;&lt;br /&gt;
       sta    $F5        ;&lt;br /&gt;
LFBA9: bit    MSTAT      ;Check VBLANK status&lt;br /&gt;
       bmi    LFBA9      ;Wait till end of VBLANK&lt;br /&gt;
LFBAD: bit    MSTAT      ;Check BLANK status&lt;br /&gt;
       bpl    LFBAD      ;Wait for start of next VBLANK&lt;br /&gt;
       lda    #$84       ;Set Display list pointer to $1f84&lt;br /&gt;
       sta    DPPL       ;&lt;br /&gt;
       lda    #$1F       ;&lt;br /&gt;
       sta    DPPH       ;&lt;br /&gt;
       lda    #$43       ;Maria mode = DMA on/320A or 320C&lt;br /&gt;
       sta    CTRL       ;&lt;br /&gt;
LFBBD: rts               ;&lt;br /&gt;
&lt;br /&gt;
; Graphics and Display List Data&lt;br /&gt;
&lt;br /&gt;
LFBBE:                                  ;$2200   Display Lists&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$1F,$19,$BB            ;$2200   Blank space&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $84,$40,$19,$1F,$BB        ;$2206   First DL on screen&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $85,$1C,$19,$4A            ;$220D   Blank space before Fuji&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $89,$1C,$19,$4A            ;$2213   Fuji line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $8D,$1C,$19,$48            ;$2219   Fuji line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $91,$1B,$19,$46            ;$221F   Fuji line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $96,$19,$19,$42            ;$2225   Fuji line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $9D,$17,$19,$3E            ;$222B   Fuji line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $A6,$17,$19,$3E            ;$2231   Fuji line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1C,$00            ;$2237   Start of Atari&lt;br /&gt;
       .byte $AF,$2C,$1C,$50            ;        and between lines&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2C,$1D,$00            ;$2241   End of Atari&lt;br /&gt;
       .byte $AF,$2C,$1D,$50 &lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$19,$28            ;$224B    Atari line 1&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$19,$28            ;$2251    Atari line 2&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$19,$28            ;$2257     Atari line 3&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
                                                   &lt;br /&gt;
       .byte $E8,$2D,$19,$28            ;$225D     Atari line 4&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1A,$28            ;$2263     Atari line 5&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1A,$28            ;$2269     Atari line 6&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1A,$28            ;$226F     Atari line 7&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $E8,$2D,$1A,$28            ;$2275     Atari line 8&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $AF,$2D,$1B,$28            ;$227B     Atari line 9&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $C2,$2D,$1B,$28            ;$2281     Atari line 10&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
       .byte $D5,$2D,$1B,$28            ;$2287     Atari line 11&lt;br /&gt;
       .byte $00,$00&lt;br /&gt;
&lt;br /&gt;
; $1F84  Display List List&lt;br /&gt;
&lt;br /&gt;
LFC4B: .byte $0F,$22,$06      ;Blank space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $03,$22,$00      ;&lt;br /&gt;
       .byte $85,$22,$0D      ;DLI&lt;br /&gt;
       .byte $05,$22,$13      ;Draw Fuji&lt;br /&gt;
       .byte $05,$22,$19      ;&lt;br /&gt;
       .byte $05,$22,$1F      ;&lt;br /&gt;
       .byte $05,$22,$25      ;&lt;br /&gt;
       .byte $05,$22,$2B      ;&lt;br /&gt;
       .byte $05,$22,$31      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank area&lt;br /&gt;
       .byte $01,$22,$37      ;Draw &amp;quot;ATARI&amp;quot;&lt;br /&gt;
       .byte $00,$22,$4B      ;Line 1 &lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$51      ;Line 2&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$57      ;Line 3&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$5D      ;Line 4&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$63      ;Line 5&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$69      ;Line 6&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$6F      ;Line 7&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$75      ;Line 8&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$7B      ;Line 9&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$81      ;Line 10&lt;br /&gt;
       .byte $02,$22,$37&lt;br /&gt;
       .byte $00,$22,$87      ;Line 11&lt;br /&gt;
       .byte $01,$22,$41&lt;br /&gt;
       .byte $0F,$22,$00      ;Blank Space&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
       .byte $0F,$22,$00      ;&lt;br /&gt;
&lt;br /&gt;
LFCC6&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$fc,$7f,$8f,$c0,$1f,$87,$f8,$7e,$0f,$e0,$7f&lt;br /&gt;
LFCD6&lt;br /&gt;
    .byte $81,$fc,$07,$ff,$80,$7f,$80,$7f,$f8,$1f,$ff,$f0,$00,$7f,$80,$03&lt;br /&gt;
LFCE6&lt;br /&gt;
    .byte $ff,$fe,$1f,$00,$00,$00,$7f,$80,$00,$00,$3e,$00,$00,$0c,$00,$3f&lt;br /&gt;
LFCF6&lt;br /&gt;
    .byte $ff,$ff,$ff,$f0,$00,$c0,$00,$00,$3f,$ff,$ff,$00,$03,$fc,$00,$00&lt;br /&gt;
LFD06&lt;br /&gt;
    .byte $3f,$00,$3f,$ff,$ff,$ff,$f0,$03,$f0,$00,$00,$3f,$ff,$ff,$fc,$03&lt;br /&gt;
LFD16&lt;br /&gt;
    .byte $fc,$00,$00,$ff,$c0,$00,$03,$ff,$00,$00,$0f,$fc,$00,$00,$3f,$f0&lt;br /&gt;
LFD26&lt;br /&gt;
    .byte $03,$ff,$c3,$fc,$00,$03,$ff,$f0,$00,$03,$ff,$00,$00,$3f,$ff,$00&lt;br /&gt;
LFD36&lt;br /&gt;
    .byte $00,$3f,$f0,$00,$3f,$c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80&lt;br /&gt;
LFD46&lt;br /&gt;
    .byte $1f,$87,$f8,$7e,$0f,$f0,$7f,$83,$fc,$01,$ff,$80,$7f,$80,$7f,$e0&lt;br /&gt;
LFD56&lt;br /&gt;
    .byte $1f,$ff,$f8,$00,$7f,$80,$07,$ff,$fe,$1f,$f0,$00,$00,$7f,$80,$00&lt;br /&gt;
LFD66&lt;br /&gt;
    .byte $03,$fe,$00,$0f,$f3,$fc,$00,$03,$ff,$00,$00,$ff,$3f,$c0,$00,$3f&lt;br /&gt;
LFD76&lt;br /&gt;
    .byte $f0,$00,$ff,$c3,$fc,$00,$3f,$c0,$ff,$00,$03,$ff,$00,$03,$fc,$0f&lt;br /&gt;
LFD86&lt;br /&gt;
    .byte $f0,$00,$3f,$f0,$3f,$fc,$03,$fc,$00,$ff,$00,$3f,$c0,$03,$ff,$00&lt;br /&gt;
LFD96&lt;br /&gt;
    .byte $0f,$f0,$03,$fc,$00,$3f,$f0,$ff,$c0,$03,$fc,$03,$ff,$ff,$ff,$f0&lt;br /&gt;
LFDA6&lt;br /&gt;
    .byte $03,$ff,$00,$3f,$ff,$ff,$ff,$00,$3f,$f0,$3f,$f0,$03,$fc,$00,$7c&lt;br /&gt;
LFDB6&lt;br /&gt;
    .byte $7f,$8f,$80,$7c,$7f,$8f,$80,$1f,$87,$f8,$7e,$07,$f0,$7f,$83,$f8&lt;br /&gt;
LFDC6&lt;br /&gt;
    .byte $00,$ff,$c0,$7f,$80,$ff,$c0,$1f,$ff,$fc,$00,$7f,$80,$0f,$ff,$fe&lt;br /&gt;
LFDD6&lt;br /&gt;
    .byte $1f,$fc,$00,$00,$7f,$80,$00,$0f,$fe,$0f,$ff,$ff,$ff,$fc,$03,$ff&lt;br /&gt;
LFDE6&lt;br /&gt;
    .byte $00,$ff,$ff,$ff,$ff,$c0,$3f,$f0,$0f,$fc,$03,$fc,$3f,$f0,$00,$03&lt;br /&gt;
LFDF6&lt;br /&gt;
    .byte $ff,$03,$ff,$03,$ff,$00,$00,$3f,$f0,$3f&lt;br /&gt;
LFE00&lt;br /&gt;
    .byte $f0,$03,$ff,$03,$fc,$ff&lt;br /&gt;
LFE06&lt;br /&gt;
    .byte $c0,$00,$00,$ff,$c3,$ff,$0f,$fc,$00,$00,$0f,$fc,$3f,$f0,$00,$ff&lt;br /&gt;
LFE16&lt;br /&gt;
    .byte $c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$87,$f8,$7c,$07&lt;br /&gt;
LFE26&lt;br /&gt;
    .byte $f0,$7f,$83,$f8,$00,$7f,$c0,$7f,$80,$ff,$80,$1f,$ff,$fe,$00,$7f&lt;br /&gt;
LFE36&lt;br /&gt;
    .byte $80,$1f,$ff,$fe,$1f,$ff,$00,$00,$7f,$80,$00,$3f,$fe,$55,$55,$55&lt;br /&gt;
LFE46&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55&lt;br /&gt;
LFE56&lt;br /&gt;
    .byte $55,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f0&lt;br /&gt;
LFE66&lt;br /&gt;
    .byte $7f,$83,$f0,$00,$3f,$e0,$7f,$81,$ff,$00,$01,$ff,$fe,$00,$7f,$80&lt;br /&gt;
LFE76&lt;br /&gt;
    .byte $1f,$ff,$e0,$1f,$ff,$c0,$00,$7f,$80,$00,$ff,$fe,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE86&lt;br /&gt;
    .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa&lt;br /&gt;
LFE96&lt;br /&gt;
    .byte $00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f8,$7f&lt;br /&gt;
LFEA6&lt;br /&gt;
    .byte $87,$f0,$00,$1f,$e0,$7f,$81,$fe,$00,$00,$1f,$ff,$00,$7f,$80,$3f&lt;br /&gt;
LFEB6&lt;br /&gt;
    .byte $fe,$00,$1f,$ff,$e0,$00,$7f,$80,$01,$ff,$fe,$55,$55,$55,$55,$55&lt;br /&gt;
LFEC6&lt;br /&gt;
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$09&lt;br /&gt;
LFED6&lt;br /&gt;
    .byte $ca,$c9,$c6,$b4,$12,$08,$1b,$60,$58,$81,$4b,$86,$01,$d8,$bf,$d9&lt;br /&gt;
LFEE6&lt;br /&gt;
    .byte $25,$a0,$7b,$dc,$32,$79,$84,$3b,$7c,$bc,$2f,$e2,$e2,$fa,$8d,$0a&lt;br /&gt;
LFEF6&lt;br /&gt;
    .byte $00,$3b,$c5,$ec,$af,$2d,$8a,$cd,$06,$93&lt;br /&gt;
LFF00&lt;br /&gt;
    .byte $6a,$a5,$14,$46,$77,$c4&lt;br /&gt;
LFF06&lt;br /&gt;
    .byte $6a,$b2,$53,$36,$ef,$8c,$ce,$0c,$a2,$68,$71,$d3,$73,$e8,$f7,$6d&lt;br /&gt;
LFF16&lt;br /&gt;
    .byte $06,$b5,$20,$ef,$23,$47,$0c,$51,$55,$c8,$fe,$f4,$58,$c4,$3f,$20&lt;br /&gt;
LFF26&lt;br /&gt;
    .byte $a7,$67,$38,$b0,$76,$e2,$c4,$d8,$05,$63,$f8,$3c,$58,$3b,$2d,$22&lt;br /&gt;
LFF36&lt;br /&gt;
    .byte $cc,$88,$b3,$71,$8f,$1d,$80,$0a,$87,$bd,$a1,$59,$23,$e9,$70,$e2&lt;br /&gt;
LFF46&lt;br /&gt;
    .byte $d3,$ec,$46,$68,$80,$42,$39,$ea,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF56&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF66&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF76&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF86&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFF96&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFA6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFB6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFC6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFD6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
LFFE6&lt;br /&gt;
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LFD3D = $FD3D&lt;br /&gt;
LFDB4 = $FDB4&lt;br /&gt;
LFDD5 = $FDD5&lt;br /&gt;
LFE18 = $FE18&lt;br /&gt;
LFE57 = $FE57  &lt;br /&gt;
LFE84 = $FE84&lt;br /&gt;
LFE96 = $FE96&lt;br /&gt;
LFED5 = $FED5&lt;br /&gt;
LFF00 = $FF00&lt;br /&gt;
&lt;br /&gt;
GccCopyright&lt;br /&gt;
       .byte $47,$43,$43,$28,$43,$29 ; 'GCC(C)'&lt;br /&gt;
       .byte $31,$39,$38,$34,$2D,$F7 ; '1984-'&lt;br /&gt;
&lt;br /&gt;
; Classic 6502 vectors. Called Cart* because they often&lt;br /&gt;
; are referenced when the game cart is switched in.&lt;br /&gt;
&lt;br /&gt;
CartNMIVectorLo&lt;br /&gt;
       .byte $00,$F0 ; system vector - nmi&lt;br /&gt;
CartResetVectorLo&lt;br /&gt;
       .word START   ; F884&lt;br /&gt;
CartIRQVectorLo&lt;br /&gt;
       .byte $33,$F9 ; system vector - irq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1255</id>
		<title>Historic Documents</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1255"/>
				<updated>2025-07-20T17:00:34Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Historic Technical Documents ==&lt;br /&gt;
&lt;br /&gt;
This collection of historical documents centers on the Atari 7800 and its hardware, with many originating from the late Atari historian Curt Vendel. Some materials were publicly available through his Atari Museum website, while others have been preserved from his private archives and are now being shared more widely.&lt;br /&gt;
&lt;br /&gt;
In reverse chronological order:&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_standards.pdf|7800_standards.pdf]] ===&lt;br /&gt;
''Atari's game development standards for programmers, covering items like game options and attract modes. (October 1987)&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_Maria_Specs.pdf|7800_Maria_Specs.pdf]] ===&lt;br /&gt;
''A five-page document outlining Maria's technical specs and architecture. This appears to be a high-level introduction to the Maria chip for customers. (October 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' Page 1 mentions a version of Maria (number 1722) intended for 680X0 series processors.&lt;br /&gt;
* '''Note 2:''' Page 5 notes that the CTRL register's test/forbidden DMA mode “Does not assert HALT,” a detail not known to be documented elsewhere.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_keyboard_programming.pdf|7800_keyboard_programming.pdf]] ===&lt;br /&gt;
''GCC's guide to programming the planned 7800 Prosystem keyboard peripheral. (June 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_ntsc_bios_source_code.pdf|7800_ntsc_bios_source_code.pdf]] ===&lt;br /&gt;
''A rough scan of the 7800's NTSC BIOS source code. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, you might wish to check out the [[7800_NTSC_BIOS]] page, which can build with modern assemblers.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:TIA-Maria_Gate-Level_Logic_Diagrams.pdf|TIA-Maria_Gate-Level_Logic_Diagrams.pdf]] ===&lt;br /&gt;
''This document contains gate level diagrams for the different sections of the planned TIA-Maria hybrid chip. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Gcc1702b_maria_specs.pdf|Gcc1702b_maria_specs.pdf]] ===&lt;br /&gt;
''The Maria Chip Specification acceptance form, meant for sign-off by VCC, GCC, and Atari. (March 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Minnie_Subsystem_Top-Level_Specification_-_GCC-1730_(MGspec_19840221_sjg).pdf|Minnie Subsystem Top-Level Specification – GCC-1730]] ===&lt;br /&gt;
''The top-level specification for the planned &amp;quot;Minnie&amp;quot; in-cart sound chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:MiniGumby_Sound_Synthesis_System,_Analog_Output_Section_Specification_-_GCC_1730_(analog_output_spec_19840203_sjg).pdf|MiniGumby Sound Synthesis – Analog Output Section Specification – GCC-1730]] ===&lt;br /&gt;
''The analog output section specification for the same planned &amp;quot;Minnie&amp;quot; chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_software.pdf|7800_software.pdf]] ===&lt;br /&gt;
''The 7800 Software Guide covers most programming aspects about the 7800.  (??? 1984)''&lt;br /&gt;
* '''Note 1:''' If you want this information for development purposes, check out the [[7800_Software_Guide]] page instead, which has supplementary information and corrections from the modern era.&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:3600_software_guide.pdf|3600_software_guide.pdf]] ===&lt;br /&gt;
''A document covering programming the 7800, before the 3600 was renamed to the 7800. (October 1983)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip|GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip]] ===&lt;br /&gt;
''The files in this archive appear to represent layout and mask preparation data from various development stages and regional variants of the MARIA chip, including what may be NTSC and PAL configurations. (August 1983)''&lt;br /&gt;
* '''Note 1:''' While some files use the `.GDS` extension, only the &amp;quot;example.gds&amp;quot; file conforms to the standard GDSII (Calma Stream) layout format. See the contained README.txt for more information.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:7800_ntsc_bios_source_code.pdf&amp;diff=1254</id>
		<title>File:7800 ntsc bios source code.pdf</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:7800_ntsc_bios_source_code.pdf&amp;diff=1254"/>
				<updated>2025-07-20T16:53:31Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1253</id>
		<title>Historic Documents</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=Historic_Documents&amp;diff=1253"/>
				<updated>2025-07-20T16:46:52Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Historic Technical Documents ==&lt;br /&gt;
&lt;br /&gt;
This collection of historical documents centers on the Atari 7800 and its hardware, with many originating from the late Atari historian Curt Vendel. Some materials were publicly available through his Atari Museum website, while others have been preserved from his private archives and are now being shared more widely.&lt;br /&gt;
&lt;br /&gt;
In reverse chronological order:&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_standards.pdf|7800_standards.pdf]] ===&lt;br /&gt;
''Atari's game development standards for programmers, covering items like game options and attract modes. (October 1987)&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_Maria_Specs.pdf|7800_Maria_Specs.pdf]] ===&lt;br /&gt;
''A five-page document outlining Maria's technical specs and architecture. This appears to be a high-level introduction to the Maria chip for customers. (October 1984)''&lt;br /&gt;
&lt;br /&gt;
* '''Note 1:''' Page 1 mentions a version of Maria (number 1722) intended for 680X0 series processors.&lt;br /&gt;
* '''Note 2:''' Page 5 notes that the CTRL register's test/forbidden DMA mode “Does not assert HALT,” a detail not known to be documented elsewhere.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_keyboard_programming.pdf|7800_keyboard_programming.pdf]] ===&lt;br /&gt;
''GCC's guide to programming the planned 7800 Prosystem keyboard peripheral. (June 1984)'''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:TIA-Maria_Gate-Level_Logic_Diagrams.pdf|TIA-Maria_Gate-Level_Logic_Diagrams.pdf]] ===&lt;br /&gt;
''This document contains gate level diagrams for the different sections of the planned TIA-Maria hybrid chip. (April 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Gcc1702b_maria_specs.pdf|Gcc1702b_maria_specs.pdf]] ===&lt;br /&gt;
''The Maria Chip Specification acceptance form, meant for sign-off by VCC, GCC, and Atari. (March 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:Minnie_Subsystem_Top-Level_Specification_-_GCC-1730_(MGspec_19840221_sjg).pdf|Minnie Subsystem Top-Level Specification – GCC-1730]] ===&lt;br /&gt;
''The top-level specification for the planned &amp;quot;Minnie&amp;quot; in-cart sound chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:MiniGumby_Sound_Synthesis_System,_Analog_Output_Section_Specification_-_GCC_1730_(analog_output_spec_19840203_sjg).pdf|MiniGumby Sound Synthesis – Analog Output Section Specification – GCC-1730]] ===&lt;br /&gt;
''The analog output section specification for the same planned &amp;quot;Minnie&amp;quot; chip. (February 1984)''&lt;br /&gt;
&lt;br /&gt;
→ See: [[The 7800 Minnie sound chip]]&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:7800_software.pdf|7800_software.pdf]] ===&lt;br /&gt;
''The 7800 Software Guide covers most programming aspects about the 7800. If you want this information for non-historic purposes, check out the [[7800_Software_Guide]] page instead, which has supplementary information and corrections from the modern era. (??? 1984)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:3600_software_guide.pdf|3600_software_guide.pdf]] ===&lt;br /&gt;
''A document covering programming the 7800, before the 3600 was renamed to the 7800. (October 1983)''&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== [[Media:GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip|GCC_MARIA_Chip_Layout_and_Netlist_Artifacts.zip]] ===&lt;br /&gt;
''The files in this archive appear to represent layout and mask preparation data from various development stages and regional variants of the MARIA chip, including what may be NTSC and PAL configurations. (August 1983)''&lt;br /&gt;
* '''Note 1:''' While some files use the `.GDS` extension, only the &amp;quot;example.gds&amp;quot; file conforms to the standard GDSII (Calma Stream) layout format. See the contained README.txt for more information.&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	<entry>
		<id>https://7800.8bitdev.org/index.php?title=File:7800_keyboard_programming.pdf&amp;diff=1252</id>
		<title>File:7800 keyboard programming.pdf</title>
		<link rel="alternate" type="text/html" href="https://7800.8bitdev.org/index.php?title=File:7800_keyboard_programming.pdf&amp;diff=1252"/>
				<updated>2025-07-20T16:42:43Z</updated>
		
		<summary type="html">&lt;p&gt;MSaarna: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>MSaarna</name></author>	</entry>

	</feed>