B board · 85605-B-1 · six sheets

How sprites work

An entire circuit board, 103 chips, doing one job: getting up to twenty-four moving objects onto each scanline of a screen that will not wait for them.

The problem, stated honestly

A raster monitor draws one line at a time, left to right, and it does not stop. At 6MHz the beam crosses a pixel every 167 nanoseconds and a whole line in 64 microseconds. Whatever is going to appear on a line has to be ready before the beam gets there, every line, fifteen thousand times a second.

Now add the actual requirement. Commando has soldiers, jeeps, bullets, explosions and a player, all at different places, some overlapping, some mirrored, some half off the edge of the screen. The game code knows where they all are. The screen needs to know which of them touch line 137 specifically, in the sixty-four microseconds before line 137 is drawn.

Capcom's answer takes a whole board, and it is worth saying up front that the answer is not clever mathematics. It is a search. The hardware simply looks at every object, every line, and asks each one "are you on this line?". Ninety-six questions, fifteen thousand times a second, in dedicated logic that does nothing else.

Ninety-six, and where that number comes from

The number is not folklore. Capcom lettered it on the drawing: sheet 1/6 of the B board is titled 96 OBJECTS DATA RAM and sheet 2/6 is 24/96 OBJECT CONTROLLER. Both limits are in the engineers' own handwriting.

It falls out of the memory arithmetic. Each object is described by four bytes, and the sprite table occupies FE00 to FF7F - 384 bytes, which is exactly 96 records. MAME's driver walks the same region in the same four-byte steps, so the emulator and the drawing agree on the number without either having been derived from the other.

The four bytes are miserly and every bit is doing something. Byte 0 is the picture number. Byte 2 is Y and byte 3 is X. Byte 1 is where the parsimony shows: two bits choose a ROM bank, two choose a colour set, two are the horizontal and vertical mirror flags, one is unused, and the last one is the ninth bit of X, borrowed because a sprite needs to be able to sit partly off the left-hand edge and 256 positions are not enough for a 256-pixel screen plus overhang.

CODEbyte 0which picture, low 8 bitsATTRbyte 1bank, colour, flips, X bit 8Ybyte 2vertical positionXbyte 3horizontal position, low 8 bitsATTR unpacked7bank6bank5colour4colour3flip Y2flip X1unused0X bit 896 objects x 4 bytes = 384 bytes, living at FE00-FF7F in the A board's own work RAM

The object record, four bytes wide. The single most telling number on this diagram is 384: the sprite table is exactly 96 records long, which is why Capcom lettered sheet 1/6 96 OBJECTS DATA RAM. Note bit 0 of the attribute byte doing duty as the ninth bit of X. That one bit is what lets a sprite sit partly off the left edge.

Twenty-four, and why a limit has to exist at all

The second number is a confession. The engine cannot draw an unlimited number of sprites on one line because it only has sixty-four microseconds, and drawing costs time per sprite. So a ceiling is designed in: twenty-four per line, and the twenty-fifth is silently dropped.

The counting is done by 7D and 8D, a pair of '161 counters that number the slots as matching sprites are filed. When the count reaches twenty-four, 9D raises the flag and no further sprites are stored on that line. Objects are scanned in table order, so the casualty is always whatever sits latest in the list.

The search half of the line ends the same way. 8B watches the object counter and calls a halt at ninety-six, and the '74 at 9B is what divides each scanline into its two halves in the first place: hunt first, then play back what was found.

This limit is real hardware behaviour that MAME does not reproduce - its draw loop renders all ninety-six with no per-line ceiling. On the actual board, crowd a line and sprites vanish from it. That difference is worth knowing if you ever compare a real board against an emulator and wonder why the flicker is missing.

ONE SCANLINE (384 dot clocks at 6MHz, 64 microseconds)SEARCHwalk all 96 objects, keep up to 24PLAYBACKdraw those 24 into the line buffercounters 7A / 7B / 7C step the list/MATCH decides keep or discardslot counters 7D / 8D replay the hitspixels shifted out by 7J - 10J9B '74 splits the line into these two halves (24/96TM)while all this happensthe OTHER buffer is on screen

Every scanline is used twice over. In the first half the engine reads the whole 96-entry object list and works out which sprites touch the next line; in the second half it draws them. Meanwhile the buffer filled during the previous line is being read out to the screen, which is why a sprite appears on exactly the line it was chosen for.

How one object is tested against one line

The test is a subtraction, done in hardware, once per object per line. If the beam is on line V and a sprite's top edge is at Y, then the sprite covers this line when V minus Y comes out between 0 and 15 - because every sprite is sixteen pixels tall.

That is what the '283 adders at 2C and 3C are for, working on the scanline number after 2B and 3B have added a fixed vertical offset to it. The result goes into 2E, a '20 NAND, which produces a single signal: /MATCH. Yes or no. On the screen this line, or not.

The fixed offset is a small, satisfying detail. MAME draws every sprite at sy + 6, a constant fudge that has sat in the driver for years. On the board that constant is physical: it is what the adders at 2B and 3B add. The emulator's magic number is this pair of chips.

Screen flip is folded into the same arithmetic rather than handled separately. 5A and 4A exclusive-OR the scanline count before the subtraction, so in a cocktail cabinet the second player gets an upside-down screen for the cost of two '86 packages and no extra work anywhere else.

Two buffers, and the trick that makes it all fit

Found sprites are not drawn to the screen. They are drawn into a strip of memory one scanline long, and there are two such strips, on sheets 5/6 and 6/6 - a near-perfect mirror image of each other, which is why those two drawings look so alike.

While one buffer is being filled with the sprites for the next line, the other is being read out to the monitor for the current one. At the end of every line they swap. The signal that does the swapping is LV1, which is nothing more exotic than the bottom bit of the scanline counter: odd lines use one buffer, even lines the other.

This is what buys the engine its time. It never has to keep up with the beam, only stay one line ahead of it, and one line is sixty-four microseconds of breathing room.

LV1 (the scanline's odd / even bit) swaps these over every lineLINE BUFFER 13K / 4K sheet 5/6LINE BUFFER 29L / 9M sheet 6/6BEING FILLED24 sprites written in, one at a timeBEING SHOWNread out pixel by pixel to the screennext lineline after2L / 2M '257the mux that decides which one you see

Two identical strips of memory, each one scanline long. One is being written while the other is being read, and they swap roles every line. This is the whole reason sprites can be assembled at leisure and still appear at exactly the right moment: the engine is always working one line ahead of the beam.

Placing a sprite, and getting clipping for nothing

A sprite's X byte is not compared against anything. It is loaded into a counter - 5L, 5M and 5K on the first buffer - which then counts upward as the sprite's sixteen pixels are written. The sprite lands where the counter started.

The counter is nine bits wide, and this is the part worth pausing on. The ninth bit, held by 5K, is not compared or tested by any logic. It is wired straight to the chip-enable of the buffer RAM. When the count runs past 255 that bit flips, the memory switches off, and the remaining pixels are written nowhere at all.

A sprite walking off the right-hand edge of the screen is therefore clipped perfectly, pixel by pixel, by a wire. There is no comparator, no boundary check and no special case in the design. Someone noticed that the carry out of a counter is already exactly the condition "we have gone too far", and connected it to the one pin that acts on it. This is the single most economical idea on the board.

Who wins when two sprites overlap

Sprites collide constantly, so something has to decide which is in front. Commando decides it without a priority encoder, a depth value or a sort.

Each buffer is wiped clean before its line is filled, and "clean" means every pixel set to pen 15. As a sprite is written, each pixel takes a lap through 1L, a '20 NAND wired to answer one question: are all four bits of what is already here still high? If yes, the slot is untouched and the new pixel may be written. If not, somebody got there first and the existing value is written straight back unchanged.

The muxes at 1K and 2K are what perform that choice, selecting between the incoming sprite pixel and the buffer's current contents. Every pixel is read, judged and written back, at pixel rate, for every sprite on the line.

So priority is simply first come, first served, in object-table order. The game controls layering by choosing where in the list to put things. And pen 15 doing double duty as both "transparent" and "empty" is confirmed from the other direction too: MAME's draw call passes 15 as the transparent pen.

RAMwhat is already there1L '20is it still empty?1K / 2K '257keep it, or replacepixelyes / nowritten back to the same addressreadempty = all four bits high = pen 15the same pen 15 MAME passes to transpen() when it draws a sprite

A read-modify-write loop running once per pixel. The buffer is wiped to pen 15 before the line starts, so "still 15" means "nobody has claimed this pixel yet". A sprite may only write where that is true, which means the first sprite to reach a pixel keeps it. Priority is not computed anywhere; it falls out of the order the objects are scanned in.

Where the pixels actually come from

The picture data lives in six 27128 EPROMs on sheet 4/6, arranged as three banks of two. Each sprite pixel is four bits deep, and those four bits are split across two chips: 7E, 8E and 9E supply two colour layers, 7H, 8H and 9H the other two, read at the same instant so all four bits of a pixel arrive together.

Eight pixels are fetched at once and pushed out one at a time by four '194 shift registers at 7J to 10J. Horizontal mirroring is done here, and done almost for free: a '194 can shift either direction, so a flipped sprite is the same artwork clocked out backwards. 10K picks which end of the registers to listen to. No second copy of any graphic is stored for a left-facing soldier.

There is a fourth bank that does not exist. 7K decodes two attribute bits into four bank selects, and the sockets for the fourth pair, 10E and 10H, are on the board and wired - but empty. Capcom designed the capacity and never used it. MAME arrives at the same conclusion from the software side: its draw loop simply skips any sprite whose bank is 3. An empty socket on the board and a conditional in the emulator, describing the same absent chips.

The whole sequence, one line at a time

Put together, every one of the 262 scanlines runs the same cycle:

1. The line buffer due to be filled is wiped to pen 15. 2. The object counters reset and the engine reads all ninety-six records out of the A board's memory, four bytes at a time. 3. Each one is tested against the next scanline; matches are filed into slots, up to twenty-four. 4. The line's second half replays those matches, fetching pixels from the picture ROMs and writing them into the buffer, first-come-first-served. 5. The buffers swap, and the one just filled is read out to the colour mixer over the ribbon cable while the next line begins the whole thing again.

None of this involves the CPU. The game code writes an object list into its own memory and the B board comes and reads it - which is a story in itself, and it is on the bus-sharing page.

The drawings behind this story

Each one opens the interactive schematic, where every chip and every net on the sheet can be traced pin by pin.

Every chip in this story

103 chips across 6 sheets. Click any of them to open the schematic with that chip selected. A few appear on more than one drawing, because Capcom split some packages across sheets.

96 OBJECTS DATA RAM — sheet 1/6
24/96 OBJECT CONTROLLER — sheet 2/6
OBJECT DATA CONTROL — sheet 3/6
OBJECT ROM — sheet 4/6
LINE BUFFER 1 — sheet 5/6
LINE BUFFER 2 — sheet 6/6
← back to the dashboard