<< Newer Article #132 Older >>

Thinking like hardware

System 32 is certainly a curious beast, and one of the most intriguing parts of the system is the mixer chip. The mixer chip is the bit that takes input from 8 different video sources — 4 tilemap layers, one text layer, one bitmap layer, one background layer, and one sprite layer — and determines which layer is visible for each pixel. Beyond that, it is also responsible for looking up the palette entry of that pixel and generating the final RGB values for it. Along the way, it has the capability to adjust the RGB values and perform some blending, along with a host of other wacky functions.

In short, it's a mess, and rather difficult to understand.

When faced with these kinds of situations in arcade hardware, it's best to try and "be the ball" — think like a piece of hardware, understand its capabilities, its inputs, its outputs, its clock speed, and try to come up with limitations on its behavior that can help explain what's going on.

For example. It's been known for a while that the System 32 mixer chip has an alpha blending feature. In order to perform alpha blending, you need to take the RGB values of one pixel, apply a multiplier, and add them to the RGB values of a second pixel, after applying the opposite multiplier.

It's also been known that you can turn on alpha blending for each layer, so that, say, two of the background layers are both alpha blended with the pixels underneath them. Now, if that's the case, then you should in theory be able to turn on alpha blending for all 8 layers if you wanted.

Ah, but wait. For each layer, in order to do alpha blending, you would have to know that layer's RGB values. How do you get the RGB values? Well, you have to look them up in palette RAM. Hmmmm. That's a memory access, which requires a clock to the RAM chips to fetch the data. If I had to do 8 palette RAM lookups, I would need to use 8 clocks to perform 8 separate reads from palette RAM.

But the input clock to the mixer is not fast enough to cram 8 memory accesses into it, especially given the maximum speed rating on the palette RAM memory chips. In fact, one memory access seems to be the most we can reasonably expect to get per pixel. So how can we even do alpha blending at all?

Well, looking at the board, palette RAM is 32k long, separated into two 16k banks. That's interesting. At the time the boards were produced, it was certainly possible to use larger RAM chips, so why did they use two banks of smaller chips instead of one bank of larger chips? Well, as it turns out, the busses for each bank of chips go to different parts of the mixer. So the mixer can apparently access separate entries in each half of palette RAM independently.

Okay, but how does this look from a software point of view? Tests have verified that I can read and write independent values across all 32k of palette RAM. Ah, but I hadn't enabled alpha blending! If I turn that bit on in the mixer, some interesting magic happens: I can read the full 32k of palette RAM normally, but all writes I make get automatically mirrored to the opposite 16k chunk. Which means that if I enable blending in the mixer, and then fill the low 16k of palette RAM, the upper 16k will automatically be filled with an exact copy. This means that the mixer can look up two pixel indexes and get their RGB values at the same time, by looking one up in the lower 16k and the other in the upper 16k.

So we now have an explanation for how we can get two palette lookups per pixel. How do we limit it to 2, given that each layer could result in an alpha blend? Well, thinking about things in the absence of alpha blending, the mixer needs to figure out which pixel is "on top" out of all the layers. Then it will look up the RGB value of that pixel and output the result.

It makes sense, then, that for alpha blending, it would figure out not only which layer's pixel is "on top", but also which layer's pixel is the 2nd from the top. Then, if alpha blending is enabled for the "on top" pixel, the mixer can alpha blend between the topmost and 2nd-to-topmost pixel. This isn't perfect, because it is assuming that the 2nd-to-topmost layer didn't also have alpha blending enabled, but in practice, this is exactly what the hardware does.

As a final point, it's actually even more complicated than this. Each layer specifies with a bitmask exactly which other layers it can alpha blend against. So when the mixer figures out which layer's pixel is on top, and which layer's pixel is 2nd-from-top, it then has to see if alpha blending is enabled between those two layers specifically. If it's not, then the topmost pixel is displayed normally; otherwise, the alpha blend takes place.