~ajxs

μCOM-87: The Strangest Architecture You've Never Worked With

2025.12.31
A short article about NEC's strange and mostly forgotten μCOM-87 processor architecture, as well as the Casio CZ-101 synthesiser that it powers.
If you've stumbled across this page looking for practical information on how to work with NEC's μCOM-87 architecture today, skip straight to this section.

With most of the DX7's technical mysteries laid bare (for now), I've had some free time to poke around inside another 80s digital synth icon: the Casio CZ-101.

In 1983, Yamaha changed the music world forever with the release of the DX7. It used a new synthesis technique called FM synthesis to create a bold, futuristic sound that was radically different from everything else available. It wasn't just a commercial success; The DX7 was a tectonic shift that reshaped the entire landscape of popular music, and left Yamaha's competitors scrambling to get in on the action. The theory behind FM synthesis was simple, but Yamaha held the patent and were fiercely protective of their advantage. It would take Korg and Roland years to bring their own competitors to market, but Casio —a comparatively small player in the synth market— managed to thread the needle with the CZ-101's Phase Distortion Synthesis. If you closed your eyes you could almost pretend someone had shrunk a DX7. It had plucky basses, resonant bells, gritty metallic percussion... All without running afoul of the notoriously litigious Yamaha's FM patents. The CZ-101 was a lot of fun squeezed into a small package. It sold well, and still enjoys a cult status today.

Under the hood, the CZ-101 uses several NEC chips: The proprietary μPD933 tone generator 1, and the μPD7811G microcontroller. Unsurprisingly, no public documentation exists for the μPD933, and —despite having once been a commercial product— the situation for the μPD7811G isn't much better. When I started poking around in the firmware ROM, I struggled to find good resources online about the μCOM-87 architecture used in the μPD7811G... Despite appearing in some really important places there's surprisingly little written about it online. For that reason I decided to write my own account of its more baroque features.

In case anyone is interested, my (incomplete) disassembly of the CZ-101's v2 firmware ROM can be found here.

Background

uPD7810 IC
The NEC μPD7810G CPU. Image courtesy of CPU Graveyard.

In 1978 Japanese mega-corporation NEC 2 launched their first original 8-bit processor architecture: The μCOM-87. Until this point, NEC's 8-bit architectures had all been based on existing designs, such as the Intel 8080-compatible μCOM-8, and Zilog Z80-compatible μCOM-82.

NEC had clearly learned a few things from their American counterparts: The μCOM-87 architecture featured two parallel banks of 8080-like registers, which could be swapped between like in the similar Z80. The 8-bit B and C registers can also be 'paired' into a single 16-bit register (BC). Same with DE, and HL, similar to the 8080 and Z80 architectures.

μCOM-87 Register Set
NEC μCOM-87 Register Set.

Now I know what you're thinking: Yeah, yeah. 8080-compatible registers, register pairing, alternate banks... This is all pretty normal 8-bit stuff. Sure... But those are just about the only normal things about the μCOM-87 architecture. Let's take a look at a few of its more exotic features...

Instruction Skipping

Note: The assembly examples in this article follow Intel's format for hexadecimal literals, which is also used by NEC in their 87AD series relocatable assembler (RA87). i.e. 0ABCDh, rather than 0xABCD.

Instead of conventional comparing and branching instructions, control flow on the μCOM-87 works by conditionally skipping instructions.

; Read a byte from the serial interface into A.
; Clamp the value between 0xA - 0xF, then send back.
    MOV         A,RXB

; Skip the next instruction if A < 0x10.
    LTI         A,010h
; Clamp A at 0xF.
    MVI         A,0Fh

; Skip the next instruction if A > 0xA.
    GTI         A,0Ah
; Clamp A at 0xA.
    MVI         A,0Ah

    MOV         TXB,A

The above example reads a value from the serial interface, and clamps it between 0xA and 0xF. The LTI (Less Than Immediate) instruction skips the next instruction if the register is less than the immediate operand. Similarly, the GTI instruction skips if the register is higher than the immediate operand.

Instruction skipping is practically unheard of in modern architectures, but featured in a few other historic ones like the PDP-8, and Microchip's PIC architectures prior to PIC18.

The following table lists most of the μCOM-87's instructions which can trigger the next instruction to be skipped. Some nearly identical instructions have been omitted for brevity 3.

μCOM-87's Skipping Instructions
Instruction Description Skip Condition
ADDNC r, A Add A to Register. Skip if No Carry No carry generated
ADDNCX rpa Add Memory addressed by Register Pair to A. Skip if No Carry No carry generated
BIT bit, wa Bit Test Working Register V.wa[bit] != 0
DADDNC EA, rp3 Add Register Pair to EA. Skip if no Carry No carry generated
DEQ EA, rp3 Equal Register Pair with EA EA == rp3
DGT EA, rp3 Greater Than Register Pair EA > rp3
EQA A, r Equal Register with A A == r
EQAW wa Equal Working Register with A A == (V.wa)
EQI r, byte Equal Immediate with Register r == byte
EQIW wa, byte Equal Immediate with Working Register (V.wa) == byte
GTI r, byte Greater Than Immediate r > byte
GTIW wa, byte Greater Than Immediate (V.wa) > byte
LTI r, byte Less Than Immediate r < byte
NEA A, r Not Equal Register with A A ≠ r
NEAW wa Not Equal Working Register with A A ≠ (V.wa)
NEI r, byte Not Equal Immediate with Register r ≠ byte
NEIW wa, byte Not Equal Immediate with Working Register (V.wa) ≠ byte
OFFI r, byte Off-Test Immediate with Register A & byte == 0
OFFIW wa, byte Off-Test Immediate with Working Register (V.wa) & byte == 0
ONAX rpa On-Test Memory addressed by Register Pair with A A & rpa != 0
ONI r, byte On-Test Immediate with Register r & byte != 0
ONIW wa, byte On-Test Immediate with Working Register A & (V.wa) != 0
SK f Skip if Flag f == 1
SKN f Skip if No Flag f == 0
SKIT irf Skip if Interrupt irf == 1
SKNIT irf Skip if No Interrupt irf == 0
SUINB r, byte Subtract Immediate from Register. Skip if No Borrow No borrow generated
SUBNB r, A Subtract A from Register. Skip if No Borrow No borrow generated

Instruction Stacking

If multiple MVI (Move Immediate to Register) instructions with the same destination register are placed sequentially, only the first instruction will actually be executed. The rest will be processed as NOP operations (however the equivalent number of CPU cycles will still be used). The μCOM-87 architecture literature refers to this as 'instruction stacking'.

The following example takes advantage of instruction stacking to create a table of values to load into the A register, and send over the serial interface.

; Read a byte from the serial interface, and send a byte based on its contents.
    MOV         A,RXB

    NEI         A,1           ; Skip if A ≠ 1.
    JR          received_1

    NEI         A,2           ; Skip if A ≠ 2.
    JR          received_2

; Received any value other than 1 or 2.
    MVI         A,0Ah
received_1:
    MVI         A,0Bh
received_2:
    MVI         A,0Ch

    MOV         TXB,A

Because the stacked MVI instructions aren't executed, there's no need to jump to the final MOV instruction. By not needing any branching instructions this saves a few extra bytes, at the expense of a few processor cycles.

Working Vector Register

The μCOM-87 architecture features an index register mechanism similar to the Direct Page register in Motorola's 6809 architecture. The Working register vector register (V) allows a programmer to specify a base address, to which an immediate 1 byte offset is added to create a 16-bit address operand for certain instructions, rather than needing the full 2 bytes.

Consider the following example: Setting the V register to 0x40 lets us access the addresses 0x4000 to 0x40FF with only a single byte.

; Loads the byte at 0x4001, decrements it, and stores it at 0x4001 again.
; Total bytes = 9
    MOV         A,(4001h)
    DCR         A
    MOV         A,(4001h)


; Sets the vector pointer, then decrements the byte at 0x4000 + 0x1.
; Total bytes = 4
    MOV         V,40h
    DCRW        1

Most instructions have a working register equivalent, such as the DCR, and DCRW instructions shown in the example above.

Call Table

The μCOM-87 architecture has a vector table of 32 user-defined function pointers (at address 0x80), which can be called with the single byte CALT instruction, reducing the amount of bytes needed to encode a common function call. E.g., CALT 5 will store the return pointer on the stack, and jump to the function pointer at index 5 (0x80 + (5*2)) in the call table. Like many other μCOM-87 features, it prioritises code density over other concerns.

Working With μCOM-87 Today

Unfortunately there aren't a lot of tools available for working with the μCOM-87 architecture today. For assembling programs I use Alfred Arnold's Macro Assembler AS, which is probably the best option available. Unfortunately I haven't been able to track down a copy of NEC's own RA87 Relocatable Assembler, mentioned in their official technical literature. A version for MS-DOS was available, which could be run in an emulator if a copy was found.

For disassembling programs, I was fortunate that Github user depili had already put in the hard yards creating a Ghidra processor specification. I've picked up the torch with this Pull Request on the Ghidra project github, which is still open as of December 2025. Alternatively, there's MAME's Unidasm, and a few other bespoke disassemblers like dasm7810, or Nec78CDasm.

The best official reference material I've found for working with the μCOM-87 architecture is the μPD78C18 datasheet (A later member of the μCOM-87 family). It's available from Renesas Electronics, who took over NEC's semiconductor business in 2010.

The upd781x-series are emulated in MAME, so it's possible to build an emulator for debugging. The brilliant Devin Acker took advantage of this to build an amazing CZ-101 driver!

The information in this article was pieced together from a variety of odd sources. This page, in Japanese, was a huge help when I first started looking at the architecture. The MAME source code also provided a few helpful hints, like where to look for a modern datasheet. If you have any pointers, or helpful hints of your own, please get in touch!


  1. The μPD933 went on to appear in the rest of Casio's CZ line of synthesizers, and other 'non-synthesizer' products, such as the Casiotone CT-5000.
  2. By 1985 NEC had the highest annual revenue of any semiconductor company, a position it would retain amidst stiff competition until being overtaken in 1992 by Intel, who have held the title ever since. (Dataquest Incorporated. (1994). Semiconductors Core Binder, 483. [Link])

    Over time the semiconductor industry shifted towards American suppliers like Intel/Motorola, as the previously unstoppable Japanese economy began to decline, and the Japanese industry's less risk-averse Silicon Valley counterparts made great advances in processor design.

  3. The μCOM-87's instruction set has a lot of near-identical instructions, with different versions operating only on the A register, such as OFFI A, byte and OFFI r, byte. The variations of these instructions for the A register require less bytes to encode, and less CPU cycles to execute.