We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.
8 digits, infinite digytes
8 digits, infinite digytes (also known as DPL-8) is another decimal assembly language designed by PSTF.
Terminology
- Digit: A decimal symbol (one of 0, 1, 2, 3, 4, 5, 6, 7, 8, or 9).
- Digyte: Four decimal digits.
- Word: Two digytes, that is, eight decimal digits.
All memory cells, data registers, and the ALU data bus are exactly one word wide.
Addresses, the Program Counter (PC), the Stack Pointer (SP), and the Index Register (X) are infinite‑precision decimal integers.
Core Feature
- There are a total of 7 registers: A, B, C, X, PC, SP, and SR.
- A, B, and C are general-purpose registers.
- X is an index register, which can be used to index memory cells.
- PC is the program counter.
- SP is the stack pointer. Unlike other assembly languages, the stack grows upwards.
- SR is the status register, showing the result of operations through whether each digit is 0 or 1 like below:
- digit 1 = Zero (Z)
- digit 2 = Negative (N)
- digit 3 = Carry/Borrow (C)
- digit 4 = Overflow (O)
- A, B, C, and SR are 8 digits wide, while X, PC, and SP have unlimited width.
Memory Model
- Infinite linear address space M[0], M[1], M[2], …
- Every cell stores exactly one word (8 digits).
- Addressing is word‑aligned (no byte or digyte addressing, though digyte extraction/insertion instructions let you modify halves).
- Since addresses are infinite, the CPU can access any cell as long as the address fits in the conceptual X register (which has no upper bound).
Instruction Set Architecture
DPL-8 uses a variable‑length instruction format. The first word always contains the opcode and an addressing‑mode specifier. Subsequent words may hold immediate operands or long address fragments.
Addressing Modes
Syntax Name Description #imm Immediate imm is an 8‑digit literal (e.g., #12345678). addr Direct Absolute addr is an 8‑digit absolute address (e.g., $87654321). Limited to 8 digits. [X] Indexed Address = value of X. [X+off] Indexed with Offset Address = X + off, where off is a 5‑digit literal (0–99999). @[X] Indirect Address = M[X] (the word at X is used as the final target address). LONG(n) Long Immediate The next n words (1 ≤ n ≤ 9) are concatenated to form an infinite address/immediate. @[X+off] Indirect with Offset Address = M[X+off].
Data Movements
Mnemonic Operand Effect LDA src A ← src STA dst dst ← A LDB src B ← src STB dst dst ← B LDC src C ← src STC dst dst ← C LDX src X ← src (src can be a long address) TAX – X ← A (zero‑extend A to infinite) TXA – A ← X mod 100000000 (truncate X to 8 digits)
Arithmetic (all decimal, modulo 100,000,000)
Mnemonic Operand Effect ADD src A ← (A + src) mod 10⁸; sets C/O flags SUB src A ← (A - src) mod 10⁸; sets C/B flags MUL src A ← (A × src) mod 10⁸; sets O flag if full product ≥ 10⁸ DIV src A ← A ÷ src (integer division; src ≠ 0) MOD src A ← A mod src INC reg Increment reg (A, B, C, or X) by 1 DEC reg Decrement reg by 1 NEG – A ← (10⁸ - A) mod 10⁸ (two's‑complement decimal negation)
Comparison & Branches
CMP src computes A - src and sets SR flags (Z, N, C, O) without modifying A.
All jump targets support addr, [X], [X+off], @[X], and LONG(n).
Mnemonic Condition Mnemonic Condition JMP Unconditional JZ Zero flag = 1 JNZ Zero flag = 0 JC Carry flag = 1 JNC Carry flag = 0 JO Overflow flag = 1 JA Above (unsigned, C=0 & Z=0) JB Below (unsigned, C=1) JG Greater (signed, Z=0 & N=O) JL Less (signed, N≠O)
Subroutine Handling
Mnemonic Operand Effect CALL target M[SP] ← PC; SP ← SP + 1; PC ← target RET – SP ← SP - 1; PC ← M[SP]
Stack Operations
Mnemonic Effect PUSH A / B / C M[SP] ← reg; SP ← SP + 1 POP A / B / C SP ← SP - 1; reg ← M[SP]
Digyte Manipulation (Word = 2 Digytes)
Let A = LLLLLLLL (digits: d1 d2 d3 d4 d5 d6 d7 d8). The left digyte is d1..d4, right digyte is d5..d8.
Mnemonic Effect SWAPD Swap left and right digytes in A (12345678 → 56781234) GETL B ← left_digyte (e.g., 00001234) GETR C ← right_digyte (e.g., 00005678) PUTL Insert B into left digyte of A, leaving right untouched PUTR Insert C into right digyte of A, leaving left untouched SHL Shift A one digit left (multiply by 10; sets O/C flags) SHR Shift A one digit right (divide by 10; drops remainder) ROTL / ROTR Rotate A left/right by one digit (9‑digit wrap inside 8‑digit space)
I/O
Mnemonic Effect INP Read exactly 8 decimal digits from standard input into A (leading zeros allowed). OUT Print A as an 8‑digit decimal number (e.g., 00000123 prints as 00000123). GETC Read a character encoded in UCS-4 from standard input into A. Because so far the largest Unicode code point is 0x10FFFF (1114111), which is less than 99999999, we can totally fit a character into a single word width. PUTC Print A as a character encoded in USC-4. Invalid characters will be printed as U+FFFD.
Syntax & Directives
A DPL‑8 source file consists of labels, instructions, and directives.
Label Definition
loop: ADD #1
CMP #100
JNZ loop
Directives
Directive Syntax Description .WORD .WORD 12345678 Reserve one word, initialised to the given 8‑digit value. .DIGYTE .DIGYTE 9999 Reserve one word, right‑aligned (stores 00009999). .ASCII .ASCII "HELLO" Store decimal digit codes word by word as UCS-4 encoding. .LONG .LONG 123456789012345 Reserve a sequence of words to store a multi‑word integer (big‑endian).
Long Address / Immediate Syntax
To load or jump to an address that exceeds 8 digits, use the LONG(n) pseudo‑instruction:
LDX LONG(3) ; X = concatenation of the next 3 words .WORD 12345678 .WORD 90123456 .WORD 78901234 ; X now equals 123456789012345678901234
The same syntax works for LDA, STA, JMP, CALL, etc.:
JMP LONG(2) ; Jump to address formed by next 2 words .WORD 87654321 .WORD 99999999 ; target = 8765432199999999
Example Program
Fibonacci (with Overflow check)
; ----------------------------------------------
; Fibonacci generator – stores terms at M[100000000 + i]
; ----------------------------------------------
START: LDX LONG(1) ; X = 100000000
.WORD 100000000
LDA #1
STA [X] ; F(0) = 1
INC X
STA [X] ; F(1) = 1
INC X
LDB #1 ; B = F(n-1) = 1 (initial)
LDC #1 ; C = F(n-2) = 1 (initial)
LOOP: LDA B ; A = F(n-1)
ADD C ; A = F(n) = F(n-1)+F(n-2)
JO DONE ; if overflow (> 99,999,999), stop
STA [X] ; store M[X] = F(n)
LDC B ; C = old F(n-1)
LDB A ; B = F(n)
INC X
JMP LOOP
DONE: OUT ; print last valid value
HALT ; (pseudo-instruction stops CPU)
Execution Semantics – How the CPU Runs
- Fetch: PC points to the current word. Read W = M[PC].
- Decode: The first 2 digits of W give the opcode. The 3rd digit gives the addressing mode.
- Resolve Operand:
- If immediate: parse following word(s).
- If indexed: read X (infinite) and add offset.
- If indirect: read the address from M[X+off].
- If LONG: read N successive words and concatenate their digit strings.
- Execute: ALU performs decimal arithmetic (base‑10, modulo 10⁸). Flags in SR are updated.
- Write‑back: Results are stored in registers or memory. PC advances by the number of words consumed (1 + extra words for LONG).
- Infinite Memory: The address bus is unbounded. When X or PC exceeds 8 digits, the CPU simply uses the full infinite‑precision value – no truncation occurs.
Why "Decimal" Works
Human‑readable arithmetic: No binary‑to‑decimal conversions; 99999999 + 1 yields 00000000 with carry, exactly as a human expects.
Digyte‑level control allows efficient packed‑decimal processing for financial or scientific applications.
Overflow detection is clean – the ALU knows exactly when a result exceeds 8 digits.
Summary
Decimalis / DPL‑8 delivers:
- Native decimal data path (8 digits, 108 states).
- Infinite address space via the X register and LONG addressing.
- Digyte operations for elegant manipulation of 4‑digit chunks.
A complete, consistent assembly language that feels like a real CPU – because it is.
The architecture is simple enough to be emulated on modern hardware, yet powerful enough to handle arbitrary‑precision memory layouts without artificial limits. All while keeping everything in decimal – the most primitive way humans developed for counting came from fingers and toes.