12

I recently completed a software disassembly of the 1980 coin-op arcade game Missile Command. I'm curious whether a feature of the hardware is unique or commonplace.

First, a bit of background: Missile Command uses a 256x231 indexed-color display. Most of the screen is 2 bits per pixel, packing 4 pixels per byte of memory. The bottom 32 lines use 3 bits per pixel, with the 3rd bit coming out of a separate area of RAM that packs 8 pixels per byte. The 2bpp RAM is linear, but the 3bpp RAM is creatively interleaved.

Most of Missile Command's animation code draws individual pixels. Even the planes and killer satellites that fly across the screen are drawn as a handful of pixels (leading edges drawn, trailing edges erased... very efficient). The 6502 only operates on whole bytes, so it would be helpful to have a way to access one pixel per byte.

The hardware designers implemented a scheme where a signal called MADSEL (Multiplexed Address Select) is asserted when a 6502 instruction with the bit pattern xxx00001 takes more than 5 cycles to execute. The signal causes the address space to function differently: a read or write to memory from $1900 to $ffff accesses a single 3bpp pixel value.

In practical terms, it means that LDA (zp,X) and STA (zp,X) instructions access memory in "MADSEL mode", one byte per pixel, while any other memory access instruction uses "normal mode".

My question: how common was this? Is this a standard trick, or something unique?

I nosed through a few MAME drivers. Most of the contemporary games for the 6502 were Atari vector or tile/sprite-based. (Missile Command is well suited to a plain framebuffer because it draws very little per frame, and it looks better with solid filled shapes.) I'm not sure if a scheme like this would be useful or possible on other CPUs.

4
  • Do you mean "this particular trick" or "interpret CPU instructions differently" or "some way to address pixels somehow differently"? The latter was common, one better known example is EGA with 4 planes that can act "in parallel". There's at least a handful of example of custom interpretation of CPU instructions.
    – dirkt
    Nov 30, 2021 at 4:25
  • 1
    @dirkt: It's really the "make specific instructions behave in unexpected ways" part that caught my attention. Remapping address spaces is a popular thing to do, but I hadn't seen anything that approached it this way before.
    – fadden
    Nov 30, 2021 at 4:40
  • 2
    I wouldn't really call that "unexpected behaviour". It's exactly why CPUs provide a SYNC (6502) or M1 (Z80) signal. It provides a hook for detection and decoding of instructions fetch to add instruction specific behaviour by external logic.
    – Raffzahn
    Nov 30, 2021 at 9:40
  • @Raffzahn: The usefulness of SYNC could have been enhanced if e.g. instead of providing an SO wire, the 6502 had interpreted all instructions whose bottom bits were 11 as a "branch if special-branch input is asserted at the end of the opcode-fetch cycle". That would have made it easy for a system to add up to 64 custom I/O instructions in whatever way would best fit the system designer's needs. Some instructions could be used as branches, some could be used to set and clear latches, some could trigger operations, etc. and the cost of a typical "I/O poll" sequence would drop from 7 to 3.
    – supercat
    Dec 2, 2021 at 19:15

1 Answer 1

7

make specific instructions behave in unexpected ways

As I wrote in the comment, I think there's at least a handful of examples that do this, unfortunately I didn't take notes when I encountered them, so I'll add them to this answer when I find them again.

KimClone

One example that takes the "let's reinterpret instructions" to the extreme is the KimKlone:

[...] logic capable of interpreting the instruction stream in tandem with the cpu. To the programmer they appear seamlessly as a super-65C02, a new branch on the 65xx tree. Undefined 65C02 opcodes are used to support 6 new registers and 44 new instructions.

The main feature is a 24-bit address space (similar to the WDC52C816) through four external bank or segment registers that get included when accessing memory, just as your MADSEL signal reinterprets the address.

PDP autoincrement

Going a bit back, many DEC PDPs and also the Data General Nova/Supernova had autoincrement addresses: As core memory needs to be written again after being read, and since the ALU was unused on indirect memory operations, using the internal "indirect operation" signal together with a partial address code (just like your MADSEL and the address range $1900 to $ffff) to gate the memory value through the ALU before writing it back is an operation that's cheap to implement.

3
  • The Apollo guidance computer had a number of those tricks up its sleeve, as example the CYR cycle right register. ibiblio.org/apollo/…
    – ghellquist
    Nov 30, 2021 at 15:09
  • @ghellquist See Transport triggered architecture for a generalization of this principle (the ALU/functional units are triggered on moving data, just like the CYR register). But this is different (because the whole architecture relies on this) compared to "let's add a few gates/ICs to make the instruction to something special".
    – dirkt
    Nov 30, 2021 at 18:59
  • 1
    The ZX80 video display logic is another exercise in making "specific instructions behave in unexpected ways". Dec 2, 2021 at 21:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .