Skip to content

P8X Instruction Set — Quick Reference (rev D)

Opcodes, mnemonics and cycle counts generated live from genucode.py (the microcode source of truth) — cannot drift from the hardware.

Operands: #imm immediate | addr 16-bit absolute | (Pn) ptr indirect | (Pn)+ post-increment | (no operand) implied. By=bytes, Cy=cycles (incl. fetch). Flags: C carry (active-high: ADD carry-out / SUB,CMP no-borrow A>=B), Z zero, N negative (bit7), V overflow; - = none. Signed branches test N^V / Z. Memory (rev E): $0000-17FF ROM (6K) | $1800-FEFF RAM | $FF00-FFFF I/O. P0=PC, P3=stack (empty-descending). JZ/JNZ/JC are aliases of BZ/BNZ/BCP.

System

Op Mnemonic By Cy Fl Description
$00 NOP 1 2 - No operation.
$01 HLT 1 2 - Halt clock; resume only by reset.
$72 CLC 1 2 C C:=0.
$73 SEC 1 2 C C:=1.

Interrupts (rev C)

Op Mnemonic By Cy Fl Description
$02 EI 1 2 - Enable maskable interrupts (IE:=1).
$03 DI 1 2 - Disable maskable interrupts (IE:=0).
$04 RTI 1 8 - Return from interrupt: pop flags then PC; re-enable IE.
$08 IRQ 1 10 - SW interrupt: push PC+flags, vector to $0808.

Load / store

Op Mnemonic By Cy Fl Description
$10 LDA #imm 2 2 ZN A:=immediate.
$11 LDB #imm 2 2 ZN B:=immediate.
$12 LDA addr 3 6 ZN A:=byte at addr (absolute).
$13 LDB addr 3 6 ZN B:=byte at addr (absolute).
$14 STA addr 3 6 - byte at addr:=A (absolute).
$15 LDA (P1)+ 1 2 ZN A:=[P1], P1++.
$16 LDA (P2)+ 1 2 ZN A:=[P2], P2++.
$17 LDA (P3)+ 1 2 ZN A:=[P3], P3++.
$19 STA (P1)+ 1 2 - [P1]:=A, P1++.
$1A STA (P2)+ 1 2 - [P2]:=A, P2++.
$1B STA (P3)+ 1 2 - [P3]:=A, P3++.
$1D STA (P1) 1 2 - [P1]:=A.
$1E STA (P2) 1 2 - [P2]:=A.
$1F STA (P3) 1 2 - [P3]:=A.
$51 LDA (P1) 1 2 ZN A:=[P1] (P1 kept).
$52 LDA (P2) 1 2 ZN A:=[P2] (P2 kept).
$53 LDA (P3) 1 2 ZN A:=[P3] (P3 kept).
$88 LDA (P1+d) 2 7 CZN A:=byte at P1+d (d unsigned 0..255). C from the address add, Z/N from A.
$89 LDA (P2+d) 2 7 CZN A:=byte at P2+d.
$8A LDA (P3+d) 2 7 CZN A:=byte at P3+d (a stack local).
$8C STA (P1+d) 2 9 CZN byte at P1+d:=A. A kept; flags clobbered by the address add.
$8D STA (P2+d) 2 9 CZN byte at P2+d:=A.
$8E STA (P3+d) 2 9 CZN byte at P3+d:=A (a stack local).

ALU (A,B -> A)

Op Mnemonic By Cy Fl Description
$20 ADD 1 2 CZN A:=A+B.
$21 SUB 1 2 CZN A:=A-B.
$22 AND 1 2 CZN A:=A AND B.
$23 OR 1 2 CZN A:=A OR B.
$24 XOR 1 2 CZN A:=A XOR B.
$25 CMP 1 2 CZN Flags from A-B; A unchanged.
$26 INC 1 2 CZN A:=A+1 (B unused).
$27 DEC 1 2 CZN A:=A-1 (B unused).
$28 SHL 1 2 CZN A:=A<<1, 0->bit0, out->C.
$29 SHR 1 2 CZN A:=A>>1, 0->bit7, out->C.
$2A ROL 1 2 CZN Rotate A left through carry.
$2B ROR 1 2 CZN Rotate A right through carry.

ALU with T (rev C; 2nd operand=T, B preserved)

Op Mnemonic By Cy Fl Description
$80 ADDT 1 2 CZN A:=A+T (B preserved).
$81 SUBT 1 2 CZN A:=A-T (B preserved).
$82 ANDT 1 2 CZN A:=A AND T (B preserved).
$83 ORT 1 2 CZN A:=A OR T (B preserved).
$84 XORT 1 2 CZN A:=A XOR T (B preserved).
$85 CMPT 1 2 CZN Flags from A-T; A,B unchanged.
$86 LDT #imm 2 2 - T:=immediate.
$87 LDT addr 3 6 - T:=byte at addr (absolute).

Stack

Op Mnemonic By Cy Fl Description
$70 PHA 1 2 - Push A onto P3 stack.
$71 PLA 1 3 ZN Pop A from P3 stack.

16-bit memory (rev D)

Op Mnemonic By Cy Fl Description
$74 PHW addr 3 9 - Push 16-bit word at addr (hi then lo: lies little-endian at P3+1).
$75 PLW addr 3 10 - Pop 16-bit word into addr (lo then hi).
$76 LPW1 addr 3 9 - P1 := 16-bit word at addr.
$77 LPW2 addr 3 9 - P2 := 16-bit word at addr.
$78 MOVW dst,src 5 13 - 16-bit mem->mem: word at src -> dst.
$79 LPW3 addr 3 9 - P3 := 16-bit word at addr (restore a saved SP).
$BD PHW (P1+d) 2 10 CZN Push the word at P1+d (hi then lo). A!; flags from the address add.
$BE PHW (P2+d) 2 10 CZN Push the word at P2+d. A!
$BF PHW (P3+d) 2 10 CZN Push the word at P3+d, d measured before the push (a local/arg onto the stack). A!

Tier A: C-compiler ISA (2026-09, pure microcode; A! = clobbers A)

Op Mnemonic By Cy Fl Description
$38 LDP1 #imm16 3 5 - P1:=imm16 (3 bytes; was the LPL1/LPH1 pair).
$39 LDP2 #imm16 3 5 - P2:=imm16.
$3A LDP3 #imm16 3 5 - P3:=imm16.
$3C ADDP3 #imm 2 6 CZN P3:=P3+imm8 (free a frame). A!; flags from the low byte.
$3D SUBP3 #imm 2 6 CZN P3:=P3-imm8 (allocate a frame). A!; flags from the low byte.
$90 LDW addr,(P1+d) 4 14 CZN word at addr:=word at P1+d. A!
$91 LDW addr,(P2+d) 4 14 CZN word at addr:=word at P2+d. A!
$92 LDW addr,(P3+d) 4 14 CZN word at addr:=word at P3+d (local -> memory word). A!
$94 STW (P1+d),addr 4 14 CZN word at P1+d:=word at addr. A!
$95 STW (P2+d),addr 4 14 CZN word at P2+d:=word at addr. A!
$96 STW (P3+d),addr 4 14 CZN word at P3+d:=word at addr (memory word -> local). A!
$98 LDW addr,#imm8 4 8 - word at addr:=imm8 zero-extended (4 bytes).
$99 LDW addr,#imm16 5 9 - word at addr:=imm16 (5 bytes).
$9A ADDW dst,src 5 15 CZNV word a:=a+b, 16-bit; C=carry out. A!; Z from the high byte only.
$9B SUBW dst,src 5 15 CZNV word a:=a-b, 16-bit; C=1 no borrow (a>=b unsigned). A!; Z high byte only.
$9C CMPW dst,src 5 15 CZNV flags from a-b (16-bit), memory unchanged: C=unsigned a>=b, BLT/BGE = signed. A!
$9E INCW addr 3 9 CZN word at addr += 1. A!; flags from the low byte.
$9F DECW addr 3 9 CZN word at addr -= 1. A!; flags from the low byte.
$A0 ADDW addr,#imm8 4 15 CZNV word a:=a+imm8 (zero-ext), 16-bit; C=carry out; Z of the FULL word. A!
$A1 SUBW addr,#imm8 4 15 CZNV word a:=a-imm8; C=1 no borrow; Z full word. A!
$A2 CMPW addr,#imm8 4 15 CZNV flags from a-imm8 (16-bit), memory unchanged; Z full word (a==imm). A!
$A4 LEAW addr,(P1+d) 4 14 CZN word at addr:=P1+d (the address of a frame local). A!
$A5 LEAW addr,(P2+d) 4 14 CZN word at addr:=P2+d. A!
$A6 LEAW addr,(P3+d) 4 14 CZN word at addr:=P3+d (address of a stack local). A!
$B1 ADDW addr,#imm16 5 15 CZNV word a:=a+imm16; C=carry out; Z full word. A!
$B2 SUBW addr,#imm16 5 15 CZNV word a:=a-imm16; C=1 no borrow; Z full word. A!
$B3 CMPW addr,#imm16 5 15 CZNV flags from a-imm16, memory unchanged: C=a>=imm unsigned, Z=a==imm, BLT/BGE signed. A!
$B4 ANDW dst,src 5 15 ZN word a:=a AND b; Z high byte only. A!
$B5 ORW dst,src 5 15 ZN word a:=a OR b; Z high byte only. A!
$B6 XORW dst,src 5 15 ZN word a:=a XOR b; Z high byte only. A!
$B7 ANDW addr,#imm8 4 15 ZN word a:=a AND imm8 (high byte cleared); Z full word: ANDW x,#1 / JZ tests a bit. A!
$B8 ORW addr,#imm8 4 15 ZN word a:=a OR imm8 (high byte kept); Z full word. A!
$B9 XORW addr,#imm8 4 15 ZN word a:=a XOR imm8 (high byte kept); Z full word. A!
$BA ANDW addr,#imm16 5 15 ZN word a:=a AND imm16; Z full word. A!
$BB ORW addr,#imm16 5 15 ZN word a:=a OR imm16; Z full word. A!
$BC XORW addr,#imm16 5 15 ZN word a:=a XOR imm16 (#$FFFF = bitwise NOT); Z full word. A!

Control flow

Op Mnemonic By Cy Fl Description
$40 JMP addr 3 4 - P0(PC):=addr.
$41 JSR (P1) 1 9 - Push return addr, P0:=P1.
$42 RTS 1 6 - Pop return addr from P3 into P0.
$43 JSR addr 3 10 - Push return addr, P0:=addr.
$48 BZ addr 3 4 - Branch if Z=1. (JZ alias.)
$49 BNZ addr 3 4 - Branch if Z=0. (JNZ alias.)
$4A BCP addr 3 4 - Branch if C=1 / A>=B unsigned. (JC alias.)
$4C JNC addr 3 4 - Branch if C=0 / A<B unsigned.
$A8 JMP rel8 2 9 CZNV P0:=P0+rel8 (2-byte jump). A! flags!; assembler .relax / JMP.R. Always-taken jumps are cheaper absolute (JMP.A, 3 steps).
$A9 BZ rel8 2 9 CZNV Branch rel8 if Z=1. Taken: A! flags!. (JZ.R alias.)
$AA BNZ rel8 2 9 CZNV Branch rel8 if Z=0. Taken: A! flags!. (JNZ.R alias.)
$AB BCP rel8 2 9 CZNV Branch rel8 if C=1. Taken: A! flags!. (JC.R alias.)
$AC JNC rel8 2 9 CZNV Branch rel8 if C=0. Taken: A! flags!.

Signed branches (rev C; after CMP)

Op Mnemonic By Cy Fl Description
$44 BLT addr 3 4 - Branch if signed A<B (N^V=1). After CMP.
$45 BGE addr 3 4 - Branch if signed A>=B (N^V=0). After CMP.
$46 BLE addr 3 4 - Branch if signed A<=B ((N^V)|Z). After CMP.
$47 BGT addr 3 4 - Branch if signed A>B. After CMP.
$AD BLT rel8 2 9 CZNV Branch rel8 if signed A<B (N^V). Taken: A! flags!.
$AE BGE rel8 2 9 CZNV Branch rel8 if signed A>=B. Taken: A! flags!.
$AF BLE rel8 2 9 CZNV Branch rel8 if signed A<=B. Taken: A! flags!.
$B0 BGT rel8 2 9 CZNV Branch rel8 if signed A>B. Taken: A! flags!.

Pointer registers

Op Mnemonic By Cy Fl Description
$31 LPL1 #imm 2 3 - P1 low byte:=imm.
$32 LPL2 #imm 2 3 - P2 low byte:=imm.
$33 LPL3 #imm 2 3 - P3 low byte:=imm.
$35 LPH1 #imm 2 3 - P1 high byte:=imm.
$36 LPH2 #imm 2 3 - P2 high byte:=imm.
$37 LPH3 #imm 2 3 - P3 high byte:=imm.
$54 INP1 1 2 - P1:=P1+1.
$55 INP2 1 2 - P2:=P2+1.
$56 INP3 1 2 - P3:=P3+1.
$58 DEP1 1 2 - P1:=P1-1.
$59 DEP2 1 2 - P2:=P2-1.
$5A DEP3 1 2 - P3:=P3-1.
$5E TAP1L 1 2 - P1 low:=A.
$5F TAP1H 1 2 - P1 high:=A.
$60 TAP2L 1 2 - P2 low:=A.
$61 TAP2H 1 2 - P2 high:=A.
$62 TAP3L 1 2 - P3 low:=A.
$63 TAP3H 1 2 - P3 high:=A.
$68 TPA1L 1 2 ZN A:=P1 low.
$69 TPA1H 1 2 ZN A:=P1 high.
$6A TPA2L 1 2 ZN A:=P2 low.
$6B TPA2H 1 2 ZN A:=P2 high.
$6C TPA3L 1 2 ZN A:=P3 low.
$6D TPA3H 1 2 ZN A:=P3 high.