Various motivations of differing importance will dictate the design, such as: fixed vs. variable length, how many registers does the CPU have, what can each register do, etc.
We will use a very simple-minded assembler code to illutsrate the CPU. Also, a simple assembler code will simplify the decoding process.
| Instruction code | Mnemonic | Instruction | Meaning |
|---|---|---|---|
| 0000xxxxxxxxxxxx | LODD | Load Direct | ac <- mem[x] |
| 0001xxxxxxxxxxxx | STOD | Store Direct | mem[x] <- mem[x] |
| 0010xxxxxxxxxxxx | ADDD | Add Direct | ac <- ac + mem[x] |
| 0011xxxxxxxxxxxx | SUBD | Subtract Direct | ac <- ac - mem[x] |
| 0100xxxxxxxxxxxx | JPOS | Jump positive | if ac > 0 then pc <- x |
| 0101xxxxxxxxxxxx | JZER | Jump zero | if ac = 0 then pc <- x |
| 0110xxxxxxxxxxxx | JUMP | Jump always | pc <- x |
| 0111xxxxxxxxxxxx | LODC | Load constant | ac <- x |
| 1000xxxxxxxxxxxx | LODL | Load local | ac <- mem[sp + x] |
| 1001xxxxxxxxxxxx | STOL | Store local | mem[sp + x] <- ac |
| 1010xxxxxxxxxxxx | ADDL | Add local | ac = ac + mem[sp + x] |
| 1011xxxxxxxxxxxx | SUBL | Subtract local | ac = ac - mem[sp + x] |
| 1100xxxxxxxxxxxx | JNEG | Jump negative | if ac < 0 then pc <- x |
| 1100xxxxxxxxxxxx | JNEG | Jump negative | if ac < 0 then pc <- x |
| 1101xxxxxxxxxxxx | JNZE | Jump nonzero | if ac != 0 then pc <- x |
| 1110xxxxxxxxxxxx | CALL | Call subroutine | sp <- sp-1; mem[sp] <- pc; pc <- x |
| 1111000000000000 | PUSHI | Push Indirect | sp <- sp-1; mem[sp] <- mem[ac] |
| 1111000100000000 | POPI | Pop Indirect | mem[ac] <- mem[sp]; sp <- sp+1; |
| 1111001000000000 | PUSH | Push on stack | sp <- sp-1; mem[sp] <- ac |
| 1111010000000000 | POP | Pop off stack | ac <- mem[sp]; sp <- sp+1; |
| 1111100000000000 | RET | Return from subroutine | pc <- mem[sp]; sp <- sp+1; |
| 1111101000000000 | SWAP | Swap ac and sp | tmp <- ac; ac <- sp; sp <- tmp |
| 11111100yyyyyyyy | INCSP | Increment sp | sp <- sp + y |
| 11111110yyyyyyyy | DECSP | Decrement sp | sp <- sp - y |