<< Newer Article #212 Older >>

The Universal Platform, Part 2

In the previous article, I described how the Galaxian video hardware was designed around the concepts of a tilemap and sprites. This article goes into more details about how the hardware renders the tilemap, and where column scrolling fits in.

To recap: a tilemap is a two-dimensional array of memory that describes how the video system displays the screen. Each "tile" in a tilemap is a fixed size (traditionally 8x8 pixels) and so to cover a 256x256 pixel screen, you need an array of 32x32 tiles.

Now, on the Galaxian video hardware, the visible area of the screen is actually smaller than 256x256 — some of the top and bottom pixels are "blanked" to reduce the overall screen height to 224 pixels. This doesn't affect the underlying tilemap, which is still 32x32 tiles. But it does mean that some of those tiles are not visible.

Now think about how the video signal is transmitted to the monitor. First, keep in mind that the video signal is generated one row at a time from top to bottom, left to right, in order. This means that in order to make the tilemap visible on the screen, the video hardware must, at each pixel location, look up which tile is specified by the tilemap RAM corresponding to that pixel (this is known as the tile index). Once it knows which tile index to display, it then must look up the actual tile graphics data in the tile ROMs, and output the appropriate pixel from the 8x8 tile graphics.

This sounds like a lot of work, and it is. In fact, it's too much work to really do all of that on each pixel. So the hardware was optimized to be able to do it in realtime, by making some fundamental assumptions.

On Galaxian hardware, each pixel of each tile can be one of four colors, requiring two bits of ROM data. The data for graphics can be stored in many different ways, but on Galaxian, they opted for a logical arrangement where each bit is stored in a separate ROM, and the bits are ordered in the same left-to-right, top-to-bottom order that the screen is rendered. The advantage of storing the graphics this way is that each row of tile graphics (remember, the tiles are 8x8 pixels) is exactly 8 bits wide, or one byte. And you can read one byte from a ROM all at once.

Thus, on each scanline, the Galaxian tilemap hardware gets away with only looking up the tile index from the 32x32 tilemap RAM once every 8 pixels. It then uses that tile index to look up the appropriate row of tile graphics data once every 8 pixels, reading an entire row of data from the tile ROMs in one operation. Then, over the course of the next 8 pixels, it spools the data out one bit at a time from an internal data store. While it is doing that, it is also taking the time to figure out which tile is coming next so that it can immediately start outputting that tile once the current tile is finished.

So, we are down to only needing to read tilemap RAM once every 8 pixels as we work our way across a given scanline. Further, we only need to look up the tile graphics once every 8 pixels as well. In order to do this, we compute which entry in tilemap RAM to look up by dividing the X and Y coordinates by 8 and rounding down, so that we fetch the tilemap entry at (X/8, Y/8). Once we read the tile index from RAM, we then need to look up the tile graphics from the appropriate row in the tile ROMs. The row number is just the remainder from dividing Y by 8. For example, if we are at pixel location (48, 17), then we would fetch the tilemap entry at (48/8, 17/8), or (6, 2). And we would fetch tile graphics from row number (remainder(17/8)) = 1 of the tile.

Because of the way this works, the hardware designers realized that it was very easy to allow you to specify a number (let's call it the vertical scroll value) to be added to the value of Y before looking up the tile index and tile graphics. Doing this adds just a little bit of hardware, but gives you the ability to control the vertical scrolling of the tilemap. Take the example above again, but this time, let's add a vertical scroll value of 1 to all the Y coordinates. We are still at pixel location (48, 17) on the screen, but we will add 1 to 17 and use Y=18 in our calculations. So we look up the tilemap entry at (48/8, 18/8), or (6, 2) yet again — same as last time. But when we compute the remainder of 18/8, we get 2 instead of 1, meaning that we will display row 2 of the tile. This has effectively produced a scrolling effect of shifting that tile upwards by 1 pixel.

The first question you might ask is, what happens when you have Y=255 and you add 1? You will end up with Y=256 and then where will you access the data for the tilemap? Without going into the finer details, the answer is that the value of 256 "wraps" around back to 0. Thus, if you slowly increase the vertical scroll value by 1 each frame, the screen will scroll upwards one pixel each frame and you will eventually see what used to be at the top of the screen appear at the bottom. This is due to the wrapping effect, where values above 256 have 256 subtracted from them. Because of this wrapping, it is often true that you don't want to have the entire tilemap visible, because once you scroll, you will immediately see the top appear at the bottom. This is why it is nice to have the extra non-visible tiles in the blanked out region of the screen.

Now, having a vertical scroll value for the whole tilemap is pretty nifty, but on Galaxian they went a step further, and allowed you to specify a different vertical scroll value for each group of 8 pixels across. The reason this works well is clear if you look once again at what the video hardware is doing. It has to look up a new tilemap index and new tile graphics for each 8 pixel group as it scans horizontally across as scanline. Since it has to do these computations each time anyway, it doesn't add much complexity to pick a different vertical scroll value for each group, and it gives you a lot of flexibility. This is called "column scroll" because each column of the tilemap can have its own independent scroll value.

However, even column scroll on a tilemap doesn't really provide enough flexibility for a complete game. So, in part 3 of this article, I'll dive into the sprites.