04.14.08
Three is a Magic Number
A bit of history to begin. One of the first attempts to support multiple layers in GTE was to allocate a large block of Bank $00 memory and draw the screen by alternative PEA and PEI instructions with the soft switches set to Bank $00 Read/Bank $01 Write. I was turned on to this method by one of Alex Eddy’s demos.
A severe downside to this method was that it used an enormous amount of precious Bank $00 memory. Also, there was no way to “wrap” the addressing around, so each line of data has to be duplicated. This meant that I could never support a full-screen second layer. I eventually abandoned this approach once I figure out how to use indirect addressing to place the second layer in any memory bank I chose. This solved the “wrapping” problem too, and I’ve never looked back.
Now that I’m considering generalizing the blitter to remove the three byte limit on instruction sequences, I’ve decided to revisit the Bank $00 approach in order to incorporate a limited third layer into the engine. Some Bank $00 memory is already in use for Animated Tiles, so one would have to chose one or the other, but not both.
Because Bank $00 memory must be conserved, the third layer is allocated such that it provides a horizontally repeating patters. The width of this layer must be a divisor of the BG0 field width — 84 words. In order to further optimize memory usage, the starting address of each line of the third layer can be set independently. This allows certain lines to be duplicated which is handy for vertically symmetric backgrounds like caves.
The blitter code fragment for a full BG0 + BG1 + BG2 blit becomes
lda 00,x
and [00],y
ora (00),y
and #MASK
ora #DATA
pha
which occupies 13 bytes. In order to support masking of BG1, we use a clever trick of packing the direct page with long addresses (3 bytes) that point to a mask buffer. The Data Bank register is set to the BG1 data bank, so the same direct page address will access the data or mask buffer depending on the addressing mode.
Also, the 13 byte code fragment is the worst case scenario. Typically BG0 will be either totally transparent or opaque. This is determined at run time when the tile is written to the BG0 code buffer and the code is optimized appropriately. It would be very useful to be able to optimize for an opaque/transparent BG1, but this cannot be computed at the time the tile is drawn and checking at runtime is cost prohibitive.
Once the tile compiler is finished, I’ll try and whip out a proof-of-concept.