Zanac uses the UNROM PCB with 8 banks. To convert ROM offsets into addresses, subtract 0x10 (16 decimal) and then divide by 0x4000. This will give you the bank number from 0-7, with the remainder (a value from 0x0000 to 0x3FFF) as the offset into that bank. To turn that offset into a pointer in RAM, add 0xC000 to it if it is in bank 7 and 0x8000 to it otherwise.
The lower four banks are completely empty. Zanac is a 64KB game with a 128KB ROM chip.
Bank 4 (ROM offsets 10010-1400F) hold most of the pattern data for the entire game in a run-length-encoded format. A table of two-byte pointers at 10040-1004D points to seven tables of pattern data:
- 0: All sprite data except for the 8 sprites reserved for the "status box": 8x16 sprites, loaded into VRAM at 0000-0F7F.
- 1: Alternate graphics for the player's ship, accessible with a cheat code (hold A and B while pressing start). 8x16 sprites, loaded in VRAM at 0140-01FF.
- 2: Title screen tiles, including two fonts and the title logo. Loaded into VRAM at 1200-1A0F.
- 3: Ground features and enemy bases common to all levels. Loaded into VRAM at 17F0-1FFF during gameplay, but into 19F0-1FFF (with the overspill truncated by the nametable data) on the title screen.
- 4: Ground features and enemy bases for areas 1-4. Loaded into VRAM at 1000-153F.
- 5: Ground features and enemy bases for areas 5-8. Loaded into VRAM at 1000-17AF.
- 6: Ground features and enemy bases for areas 9-12. Loaded into VRAM at 1000-17CF.
The RLE-encoded data has the following format:
- The first two bytes are control codes that appear nowhere in the actual data. The second controls features of the decompressor that are not used by Bank 4 data and may be ignored; the second will be called "the control code."
- In uncompressed mode (where decoding starts), bytes are simply copied to the output until the control code is encountered.
- In compressed mode, bytes are read two at a time, with the first byte being the byte to copy and the second being the number of times to copy it. This continues until the control code is reached.
- The control code toggles between compressed and uncompressed mode.
- Two copies of the control code back to back end the data block.
Bank 5 (ROM offsets 14010-1800f) holds the map data. The specification of the map data is done in some highly compressed and possibly quasi-procedural form.
- ROM location 14040 holds a 13-entry table of words. Entry #0 is $0000, and the rest are the top-level pointers to map data for each of the 12 areas.
- That table is followed by three additional three-entry tables of 16-bit words, which seem to correspond to the first, middle, and final sets of four levels. These are used to build pointers but don't seem to point to useful data themselves (that is, when dereferenced the index never seems to be zero).
- Top level map data doesn't begin until offset 16421. Something about this is referring to data objects defined in the intervening 8KB or so of ROM.
Supplementary code and data. 18010-18039 hold some kind of vector table, as if there is a set of routines that are being "exported" from the ROM bank in a portable or switchable way.
A table at 189C1-189DC holds the remainder of the sprite pattern data. Each valid entry in this table describes 128 bytes of data to fill the tiles at PPU offsets 0F80-0FFF, and is generally a transient part of the UI:
- 0: Illegal data, never used
- 1: AREA
- 2: TIME
- 3: GAME OVER
- 4: BONUS
- 5: PONY INC logo
- 6: Empty sprite
The routine that does the copy here checks for any value between 06 and FF and will set all such values to 6. 0 does not seem to have this protection.
The graphics data is encoded in the same manner as the data in bank 4. The table, however, has four bytes per entry instead of two. The meaning of the remaining two bytes in each entry is presently unknown.
Core code section, including the main loop and all reset and interrupt vectors.
- 1C010-1C0A2 holds a table of "exported functions" much like bank 6. Following the links suggests that these are mostly general-purpose SDK-like functions.
- 1C108-1C10F are the memory locations used by the bankswitching logic to prevent UNROM bus conflicts and should not be touched.
- 2000A-2000F are the master interrupt vectors for the program as a whole.