Page 1 of 1

Four bits, ten digits: how the 4004 does decimal without a “decimal mode”

Posted: 26 Apr 2026, 23:09
by Jaime Clot
The 4004 is often introduced as a “4-bit CPU.” That name is accurate, but it is easy to misread.

Those four bits are not a miniature byte waiting to grow up. They are the natural width for one decimal digit when you store numbers in BCD (Binary-Coded Decimal): one digit per nibble, values 0–9 in normal use.

The confusion starts when people assume the hardware therefore “is” decimal.

It is not.

At the silicon level it is binary addition in a 4-bit lane, plus a small set of instructions that let you enforce decimal rules in software.


Registers — what “Rx” means on the 4004

The 4004 exposes sixteen scratch registers, R0 through R15.

Each register holds one nibble (four bits, numeric range 0–15).

In BCD work you normally keep each decimal digit 0–9 in its own register (or in a selected RAM “character” after your bank/chip/register addressing setup).

The example below uses R4, R5, R6, and R7 as temporary storage for operand digits and partial results.

Any other Rx would work if you stay consistent.
ADD — the binary contract (and a small intuition)

ADD r performs binary addition:

A ← (A + Rr + CY) mod 16

CY is updated from overflow of that 4-bit sum (carry out of the nibble position).

ADM is the same contract against the currently selected RAM data character (after DCL/SRC context).

That is the whole contract.

If you place valid BCD digits in A and in Rr, the low nibble after ADD is still the binary sum until you apply decimal policy (typically DAA).

---

A small intuition first: 8 + 5 is 13 in ordinary decimal.

Important: the 4004 is not storing “13” as two BCD digits here.

Two decimal digits “1” and “3” would be two nibbles (for example tens=1, units=3).

What ADD leaves in A after 8 + 5 is a single 4-bit value whose numeric weight is thirteen. In hex that is often written D, because a nibble can only represent 0..15 as one place.

A single BCD digit is only allowed to be 0..9. So “thirteen in one nibble” is not a legal BCD digit encoding: it is an intermediate binary sum you must normalize.

DAA is the instruction that performs that normalization (and updates CY for decimal carry semantics when the correction crosses the nibble boundary).

---

The worked example later uses a sharper case: 1 + 9 in the units column, where the decimal truth is 10 and the tens column must observe a carry.
DAA — decimal normalization after a binary add

DAA (Decimal Adjust Accumulator) applies BCD normalization after a binary addition.

It inspects A and CY.

When the rules require it, it adds 6 to the accumulator path.

Why 6? A decimal digit lives in base 10, but a nibble carries in base 16. The “gap” between a completed decimal digit and the next binary wrap of a nibble is 16 − 10 = 6.

So if a binary sum has pushed you into the invalid BCD range (10..15 in one nibble), adding 6 forces the nibble to roll through 16 in exactly the right way: the low digit becomes the correct BCD digit (0..9) and the overflow bit becomes the decimal carry you expect for that digit position.

Concrete check: 9 + 9 = 18 decimal. Binary in one nibble is 2 with a binary carry out of the nibble (because 18 does not fit in 4 bits as a single value). DAA’s “+6” rule is how the architecture realigns those situations with decimal digit carry-out semantics.

It always operates on one digit position at a time.

There is no persistent “BCD mode” bit in the processor: each correction is an explicit instruction in the instruction stream.
Multi-digit sums — CY as the link between columns

Adding 21 + 29 is not a special opcode.

You still store each digit in its own nibble.

You still add the units column with ADD then DAA.

You still add the tens column with ADD (which includes the incoming CY) and DAA again.

The interesting part in this specific sum is the units column: 1 + 9 = 10.

So the units digit of the result is 0, and the tens column must include an extra +1 carried through CY.

The CPU still does not “know” it is adding 21.

It only sees nibbles and flags.

The meaning is entirely in your data layout and in the instruction choreography.
Worked listing — two-digit BCD add with decimal carry

Below is a compact listing for 21 + 29 → 50.

After the first DAA, CY should be 1 so the tens ADD evaluates as 2 + 2 + 1.

Code: Select all

        ORG 000H
; 2-digit BCD: 21 + 29 -> 50 (R7=tens, R5=units; CY carries to tens)
        CLB ; A and CY <- 0
        LDM 9 ; A <- 9 (units of 29)
        XCH R4 ; R4<-9, A<-0
        LDM 1 ; A <- 1 (units of 21)
        ADD R4 ; A <- 1+9+CY (binary 10)
        DAA ; units -> 0, CY<-1 (decimal carry)
        XCH R5 ; R5<-0 (result units)
        LDM 2 ; A <- 2 (tens of 29)
        XCH R6 ; R6<-2, A<-0
        LDM 2 ; A <- 2 (tens of 21)
        ADD R6 ; A <- 2+2+CY (uses CY=1)
        DAA ; tens digit ok
        XCH R7 ; R7<-5; BCD 50
STOP:   JUN STOP
        END
fourbits00.jpg
fourbits00.jpg (245.43 KiB) Viewed 14 times
Expected outcome — register story (static reasoning)

After the first column completes (ADD then DAA then XCH R5), R5 holds the units digit 0.

At that point CY is 1: that is the decimal carry into the tens column.

After the second column completes, R7 holds 5.

If you mentally force CY to 0 after the first column, the tens sum becomes 2 + 2 and you read 40 instead of 50.

So this example is really about the CY linkage between digit positions, not about memorizing another opcode.
Subtraction (one line)

Decimal subtraction on this family is usually structured with TCS paired with SUB / SBM in the documented sequences: binary core first, then decimal-aligning instructions.

Emulation / Quadium perspective

Emulation is most useful when behavior is predictable at the boundary between “binary nibble math” and “decimal digit policy.”

If you can read ADD, DAA, and CY as a joint contract, calculator-era firmware stops looking like mysticism and starts looking like a finite state machine with arithmetic primitives.

The instruction reference panel is enough company while stepping.

You do not need a separate “decimal mode” in the UI because the original chip never had one either.