Friday, August 12, 2016

32k TI Carts

The folks over at AtariAge are going wild over 32kb cartridges, thanks to the "FlashROM99", which is a RAM-based cartridge that loads ROMs up to 32kb from SD card. One of the members attempted to convert my old Super Space Acer game (, but failed as the utility they used wasn't able to deal with numerous requirements of the program, like a loader that it required, or data files it used.

I decided to go ahead and take a stab at it myself... I found that there was a lot involved:

-The main program was 22.4k
-The sprite data was 3.75k
-The end program was 5k
-The title picture was 12k
-And the runtime library was 1.75kb

This was not going to fit in 32k, obviously, so the first task was compression. Some time ago I extracted the compression code from my VGM compressor ( in order to see if it worked standalone (and it did, though nowhere near as well as zip. However, it's much faster). I did a quick test, and found it could compress everything down from 45k to 27k. That seemed good enough.

After packing the files, I laid out my intention for the cartridge:

Every bank has a header through to >6040

Bank0 - >6000
    0040 boot, unpacker (1k)
    0440 SSE.pack to >A000, >13FA bytes
    14C0 SSD.pack to VDP >0800, >0F00 bytes

Bank1 - >6002
    0040 ssa.pack to >A000, >1FFA bytes
    14C0 acer_c.pack to VDP >2000, >1800 bytes
    1840  demq.pack to >2000, >066C bytes

Bank2 - >6004
    0040  ssb.pack to >BFFA, >1FFA bytes

Bank3 - >6006
    0040 ssc.pack to >DFF4, >1BFA bytes
    1330 acer_p.pack to VDP >0000, >1800 bytes

With the layout in place, I was able to create a quick script that would copy the files and pad as appropriate for the above structure. Then I wrote a quick set of functions to unpack each file into the correct place that it went.

The main catch, however, was dealing with the dynamically loaded files. I realized that all the loads ran through the runtime, a function called DSRLNK. I wrote a little replacement function that checked the calling address and then simply unpacked the appropriate data directly into memory, then returned. Since all but one of the files load at startup, it was pretty easy.

Getting the end loader was slightly trickier, but I just had to enable cheats, then enable overdrive on the emulator, and then get to the end of the game. ;)

 AORG >22B2

* on entry, WP is >209A
* copy return address to our workspace
  MOV R14,@>8300
  LWPI >8300
* now figure out who to call - there are 4 options
* R14    File    Vector
* A830 - SSD     2702
* DA0E - SSE     2704
* A656 - ACER_C  2706
* A638 - ACER_P  2708

 LI R1,>2702
  MOV *R2+,R3
  C R3,R0
  MOV *R1,R0
  BL *R0
* back to caller, remember to increment R14
  LWPI >209A
  INCT R14
  DATA >A830,>DA0E,>A656,>A638,>0000
In order for the unpacker to be able to run while switching banks on the cartridge, it needs to load to RAM. So the cartridge header (which is on all banks to ensure any startup state is okay) starts by copying the unpacker to RAM, then branching to it. The unpacker then unpacks the main program and the runtime, and jumps to THAT. The main program then requests the title screen and the sprites, and these requests are redirected to the appropriate routines in the unpack code.

Works pretty well, overall! and now it's time for bed. ;)

No comments:

Post a Comment