I've designed and implemented a CPU architecture in one day. Of key architectural details: Processor is supposed to support updatable microcode, Architecture extensions and Is designed to be implemented sortof like a real CPU (at least in Logisim Evolution). As I was coding for speed, this 0.5 kiloline monster appeared to haunt me.
Is there a better way to implement the same functionality?
I have two programs built in. One counts the natural numbers, and the default one outputs the fibonacci sequence. To swap programs, replace pp(CPU(FIB))
with pp(CPU(COUNT))
, and vice-versa.
ISA:
ID | Opcode | Description |
---|---|---|
0 | ADD | A <-- A + B, overflow |
1 | JOTO | Jump if overflow, and toggle |
2 | LIT | B <-- Literal value following |
3 | LOAD | B <-- Mem[I] |
4 | STOR | Mem[I] <-- B |
5 | SWAP | Swap A and B registers |
6 | SWPI | Swap B and I registers |
7 | INC | A <-- A + 1, overflow |
8 | NOP | Clears overflow |
cpu.py
from enum import Enum, auto
from pprint import pp
from cpu_flags import (
ALU_ADD,
ALU_COMP,
ALU_INC,
ALU_LSH,
ALU_OUT,
ALU_REG_ENABLE,
ALU_REG_WRITE,
ALU_RSH,
ALU_XOR,
CLR_OV,
MEM_ENABLE,
MEM_WRITE,
MICRO_RESET,
PC_ENABLE,
PC_INC,
PC_WRITE,
REG_A_ENABLE,
REG_A_WRITE,
REG_B_ENABLE,
REG_B_WRITE,
REG_I_ENABLE,
REG_I_WRITE,
REG_IR_ENABLE,
REG_IR_WRITE,
SET_OV,
)
from cpu_inst import (
ADD,
AND,
CPU_INST,
INC,
JOTO,
LIT,
LOAD,
LSH,
NOP,
RSH,
STOR,
SWAP,
SWPI,
XOR,
)
from microcode import JOV_func, microcode
names = {
ADD: "ADD",
JOTO: "JOV",
LIT: "LIT",
LOAD: "LOAD",
STOR: "STOR",
SWAP: "SWAP",
SWPI: "SWPI",
INC: "INC",
NOP: "NOP",
XOR: "XOR",
AND: "AND",
LSH: "LSH",
RSH: "RSH",
}
class ISA_EXTS(Enum):
B = 1
S = 2
IO = 3
def generate_IA(extensions: set[ISA_EXTS]):
ia = {x for x in CPU_INST if x.value < 8}
if ISA_EXTS.B in extensions:
ia = ia.union((CPU_INST.XOR, CPU_INST.AND))
if ISA_EXTS.S in extensions:
ia = ia.union((CPU_INST.LSH, CPU_INST.RSH))
# if ISA_EXTS.IO in extensions:
# ia = ia.union((CPU_INST.IN, CPU_INST.OUT))
return sorted(ia)
MAX_VALUE = 1 << 300
isa_exts = {}
isa = generate_IA(isa_exts)
def CPU(MEM):
prog_counter = -1
reg_a = 0
reg_b = 0
reg_i = 0
reg_alu = 0
alu_out = 0
overflow = False
jumped = False
u = 0
instruction = NOP
new_instruction = NOP
old_bus = 0
bus = 0
flags = {}
inst_set = microcode[instruction]
while prog_counter < len(MEM):
# microcode[new_instruction]
old_bus = bus
bus = 0
# if prog_counter >= 18:
# print(u)
flags = inst_set[u]
# if u == 0:
# print(f"BUS:{bus}")
# print(
# f"pc:{prog_counter} {names[instruction]}, a:{reg_a}, b:{reg_b}, i:{reg_i}, o:{overflow}"
# )
# print(f"u:{u}, mem:{MEM[prog_counter - 2 : prog_counter + 3]}")
# print(flags)
if MICRO_RESET in flags:
u = 0
if not jumped:
instruction = new_instruction
else:
instruction = MEM[prog_counter]
inst_set = microcode[instruction]
if inst_set == JOV_func:
inst_set = JOV_func(overflow)
continue
if PC_INC in flags:
prog_counter += 1
if PC_ENABLE in flags:
bus = prog_counter
if REG_IR_ENABLE in flags:
bus = instruction
if MEM_ENABLE in flags:
# print(f"READMEM, mem:{MEM[old_bus - 2 : old_bus + 3]}")
bus = MEM[old_bus]
if REG_A_ENABLE in flags:
bus = reg_a
if REG_B_ENABLE in flags:
bus = reg_b
if REG_I_ENABLE in flags:
bus = reg_i
if ALU_REG_ENABLE in flags:
bus = reg_alu
if ALU_OUT in flags:
bus = alu_out
if PC_WRITE in flags:
# print("JUMP", bus)
jumped = True
prog_counter = bus
if REG_IR_WRITE in flags:
new_instruction = bus
if MEM_WRITE in flags:
MEM[old_bus] = bus
# print(f"WRITE MEM, mem:{MEM[old_bus - 2 : old_bus + 4]}")
if REG_A_WRITE in flags:
reg_a = bus
if REG_B_WRITE in flags:
reg_b = bus
if REG_I_WRITE in flags:
reg_i = bus
if ALU_REG_WRITE in flags:
reg_alu = bus
if ALU_ADD in flags:
b = reg_alu + bus
if b > MAX_VALUE:
overflow = True
b %= MAX_VALUE
alu_out = b
if ALU_XOR in flags:
alu_out = reg_alu ^ bus
if ALU_INC in flags:
alu_out = reg_alu + 1
if alu_out >= MAX_VALUE:
overflow = True
alu_out %= MAX_VALUE
if CLR_OV in flags:
overflow = False
if SET_OV in flags:
overflow = True
# ALU_COMP = CPU_FLAG.ALU_COMP
# ALU_AND = CPU_FLAG.ALU_AND
# ALU_LSH = CPU_FLAG.ALU_LSH
u += 1
return MEM
# Normal instruction
# FETCH, EXECUTE, INC
def create_prog(prog, length=1000):
return prog + (length - len(prog)) * [0]
# Fibonacci
FIB = create_prog(
[
LIT,
65,
SWPI, # 0, 0, 65
INC, # 1, 0
SWAP, # 0, 1
STOR,
SWAP, # 1, 0
LOAD, # 1, 1
ADD, # 2, 1, 64
SWAP, # 1, 2, 64
STOR, #
LIT,
28,
JOTO, # Terminate if overflow
NOP,
LOAD,
SWPI, # a + b, 64, b
SWAP, # 64, a + b, b
INC, # 65, a + b, b
SWAP,
SWPI, # a + b, b, 65
STOR, # Stored A+B at next I
LIT,
1000,
JOTO,
LIT,
7,
JOTO,
LIT,
0,
STOR,
LIT,
1000,
JOTO,
JOTO,
],
length=512,
)
COUNT = create_prog(
[
LIT,
24,
SWPI,
LIT,
0,
INC, # 1, 0, 16
SWAP, # 0, 1, 16
STOR, # Write to loc 16
SWPI, # 0, 16, 1
SWAP, # 16, 0, 1
INC, # 17, 0, 1
SWAP, # 0, 17, 1
SWPI, # 0, 1, 17
SWAP, # 1, 0, 17
LIT,
1000,
JOTO,
LIT,
3,
JOTO,
]
)
pp(CPU(FIB))
cpu_inst.py
from enum import Enum
class CPU_INST(Enum):
ADD = 0
JOV = 1
LIT = 2
LOAD = 3
STOR = 4
SWAP = 5
SWPI = 6
INC = 7
NOP = 8
XOR = 9
AND = 10
LSH = 11
RSH = 12
def __lt__(self, o):
return self.value < o.value
ADD = 0
JOTO = 1
LIT = 2
LOAD = 3
STOR = 4
SWAP = 5
SWPI = 6
INC = 7
NOP = 8
XOR = 9
AND = 10
LSH = 11
RSH = 12
# cpu_flags.py
from enum import Enum, auto
class CPU_FLAG(Enum):
MEM_ENABLE = auto()
MEM_WRITE = auto()
MICRO_RESET = auto()
PC_INC = auto()
PC_ENABLE = auto()
PC_WRITE = auto()
REG_IR_ENABLE = auto()
REG_IR_WRITE = auto()
REG_A_ENABLE = auto()
REG_A_WRITE = auto()
REG_B_ENABLE = auto()
REG_B_WRITE = auto()
REG_I_ENABLE = auto()
REG_I_WRITE = auto()
ALU_REG_ENABLE = auto()
ALU_REG_WRITE = auto()
ALU_COMP = auto()
ALU_ADD = auto()
ALU_AND = auto()
ALU_XOR = auto()
ALU_INC = auto()
ALU_LSH = auto()
ALU_RSH = auto()
ALU_OUT = auto()
CLR_OV = auto()
SET_OV = auto()
MEM_ENABLE = CPU_FLAG.MEM_ENABLE
MEM_WRITE = CPU_FLAG.MEM_WRITE
MICRO_RESET = CPU_FLAG.MICRO_RESET
PC_INC = CPU_FLAG.PC_INC
PC_ENABLE = CPU_FLAG.PC_ENABLE
PC_WRITE = CPU_FLAG.PC_WRITE
REG_IR_ENABLE = CPU_FLAG.REG_IR_ENABLE
REG_IR_WRITE = CPU_FLAG.REG_IR_WRITE
REG_A_ENABLE = CPU_FLAG.REG_A_ENABLE
REG_A_WRITE = CPU_FLAG.REG_A_WRITE
REG_B_ENABLE = CPU_FLAG.REG_B_ENABLE
REG_B_WRITE = CPU_FLAG.REG_B_WRITE
REG_I_ENABLE = CPU_FLAG.REG_I_ENABLE
REG_I_WRITE = CPU_FLAG.REG_I_WRITE
ALU_REG_ENABLE = CPU_FLAG.ALU_REG_ENABLE
ALU_REG_WRITE = CPU_FLAG.ALU_REG_WRITE
ALU_COMP = CPU_FLAG.ALU_COMP
ALU_ADD = CPU_FLAG.ALU_ADD
ALU_XOR = CPU_FLAG.ALU_XOR
ALU_AND = CPU_FLAG.ALU_AND
ALU_LSH = CPU_FLAG.ALU_LSH
ALU_RSH = CPU_FLAG.ALU_RSH
ALU_INC = CPU_FLAG.ALU_INC
ALU_OUT = CPU_FLAG.ALU_OUT
CLR_OV = CPU_FLAG.CLR_OV
SET_OV = CPU_FLAG.SET_OV
microcode.py
from cpu_flags import (
MEM_ENABLE,
MEM_WRITE,
MICRO_RESET,
PC_INC,
PC_ENABLE,
PC_WRITE,
REG_IR_ENABLE,
REG_IR_WRITE,
REG_A_ENABLE,
REG_A_WRITE,
REG_B_ENABLE,
REG_B_WRITE,
REG_I_ENABLE,
REG_I_WRITE,
ALU_REG_ENABLE,
ALU_REG_WRITE,
ALU_COMP,
ALU_ADD,
ALU_XOR,
ALU_INC,
ALU_LSH,
ALU_RSH,
ALU_OUT,
CLR_OV,
SET_OV,
)
from cpu_inst import (
ADD,
JOTO,
LIT,
LOAD,
STOR,
SWAP,
SWPI,
INC,
NOP,
XOR,
AND,
LSH,
RSH,
)
# Jump if overflow, toggle overflow
def JOV_func(overflow):
if overflow:
return [
{REG_B_ENABLE, PC_WRITE},
{CLR_OV},
{MICRO_RESET},
]
return [
# No Overflow {}
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE, SET_OV},
{MICRO_RESET},
]
# ADD operation
# FETCH, EXECUTE, STORE/INC
microcode = {
ADD: [
{REG_A_ENABLE, ALU_REG_WRITE, CLR_OV},
{REG_B_ENABLE, ALU_ADD},
{ALU_OUT, REG_A_WRITE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
JOTO: JOV_func,
LIT: [
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_B_WRITE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
LOAD: [
{REG_I_ENABLE},
{MEM_ENABLE, REG_B_WRITE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
STOR: [
{REG_I_ENABLE},
{MEM_WRITE, REG_B_ENABLE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
SWAP: [
{ALU_REG_WRITE, REG_A_ENABLE},
{REG_A_WRITE, REG_B_ENABLE},
{REG_B_WRITE, ALU_REG_ENABLE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
SWPI: [
{ALU_REG_WRITE, REG_B_ENABLE},
{REG_B_WRITE, REG_I_ENABLE},
{REG_I_WRITE, ALU_REG_ENABLE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
INC: [
{REG_A_ENABLE, ALU_REG_WRITE, CLR_OV},
{ALU_INC},
{ALU_OUT, REG_A_WRITE},
{PC_INC},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
NOP: [
{PC_INC, CLR_OV},
{PC_ENABLE},
{MEM_ENABLE, REG_IR_WRITE},
{MICRO_RESET},
],
}
1 Answer 1
This is a von Neumann machine, which is risky. It introduces the possibility of a whole category of bugs that by definition cannot exist on a Harvard machine. If you're able, rewrite to represent the latter.
If you're going for realism, it is not particularly realistic to have a CPU that represents 300-bit integers natively. For one, that's impractically large for the native word size; and also even if it were implemented, it would almost always be a power of 2 (i.e. 256 instead of 300).
You have namespace problems. The long lists of CPU flags and CPU instructions should not exist in the global namespace at any point.
Don't use pprint.pp
; it was a bad decision for Python to offer that alias in the first place. Just use pprint.pprint
.
names
is unused so delete it.
You need more spaces between class and function definitions; use a PEP8 linter.
You need more typehints, and some of your existing typehints are incorrect. For example, you set isa_exts = {}
to an empty dictionary but then later treat it as a set.
You have a lot of dead code in comments. This is what source control is for: commit old versions, and then delete (not comment) dead code; it will always be in the history for reference.
CPU
and MEM
(a function and parameter name, respectively) should both be lowercase. Again a PEP8 linter will help with this.
Representing the entire CPU state in a scattering of local variables in CPU()
is not a very convenient way to represent state. Consider instead a state class.
CPU()
should be broken up. Among other pieces, you could convert the repeated if in flags
to a loop over all possible flags and a lookup of callables.
Comments like this:
# Normal instruction
# FETCH, EXECUTE, INC
def create_prog(prog, length=1000):
need to be converted to docstrings:
def create_prog(prog: Memory, length: int = 1000) -> Memory:
"""Normal instruction
FETCH, EXECUTE, INC"""
Your program memory, by your current design, has mixed types - instruction enums, and integers. This is not a great idea. Go all-or-nothing: have either a sequence of instruction objects tied to their arguments (like Literal(65)
) and no bare integers in memory; or after a compilation step, have only integers in memory that represent the instruction opcodes and arguments, as would exist in real life.
Don't pp(CPU(FIB))
without a __main__
guard.
Suggested
This addresses some (certainly not all) of the above:
from enum import Enum, auto
from pprint import pprint
from typing import Callable
class CpuInst(Enum):
ADD = 0
JOV = 1
JOTO = JOV
LIT = 2
LOAD = 3
STOR = 4
SWAP = 5
SWPI = 6
INC = 7
NOP = 8
XOR = 9
AND = 10
LSH = 11
RSH = 12
def __lt__(self, o: 'CpuInst') -> bool:
return self.value < o.value
class CpuFlag(Enum):
MEM_ENABLE = auto()
MEM_WRITE = auto()
MICRO_RESET = auto()
PC_INC = auto()
PC_ENABLE = auto()
PC_WRITE = auto()
REG_IR_ENABLE = auto()
REG_IR_WRITE = auto()
REG_A_ENABLE = auto()
REG_A_WRITE = auto()
REG_B_ENABLE = auto()
REG_B_WRITE = auto()
REG_I_ENABLE = auto()
REG_I_WRITE = auto()
ALU_REG_ENABLE = auto()
ALU_REG_WRITE = auto()
ALU_COMP = auto()
ALU_ADD = auto()
ALU_AND = auto()
ALU_XOR = auto()
ALU_INC = auto()
ALU_LSH = auto()
ALU_RSH = auto()
ALU_OUT = auto()
CLR_OV = auto()
SET_OV = auto()
class IsaExts(Enum):
B = 1
S = 2
IO = 3
def generate_ia(extensions: set[IsaExts]) -> list[CpuInst]:
ia = {x for x in CpuInst if x.value < 8}
if IsaExts.B in extensions:
ia |= {CpuInst.XOR, CpuInst.AND}
if IsaExts.S in extensions:
ia |= {CpuInst.LSH, CpuInst.RSH}
return sorted(ia)
MAX_VALUE = 1 << 300
ISA_EXTS = set()
ISA = generate_ia(ISA_EXTS)
CpuFlagSets = tuple[set[CpuFlag], ...]
Memory = list[CpuInst | int]
def jov_func(overflow: bool) -> CpuFlagSets:
"""Jump if overflow, toggle overflow"""
f = CpuFlag
if overflow:
return (
{f.REG_B_ENABLE, f.PC_WRITE},
{f.CLR_OV},
{f.MICRO_RESET},
)
return (
# No Overflow {}
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE, f.SET_OV},
{f.MICRO_RESET},
)
def make_microcode() -> dict[
CpuInst,
CpuFlagSets | Callable[[bool], CpuFlagSets],
]:
i = CpuInst
f = CpuFlag
return {
i.ADD: (
{f.REG_A_ENABLE, f.ALU_REG_WRITE, f.CLR_OV},
{f.REG_B_ENABLE, f.ALU_ADD},
{f.ALU_OUT, f.REG_A_WRITE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.JOV: jov_func,
i.LIT: (
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_B_WRITE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.LOAD: (
{f.REG_I_ENABLE},
{f.MEM_ENABLE, f.REG_B_WRITE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.STOR: (
{f.REG_I_ENABLE},
{f.MEM_WRITE, f.REG_B_ENABLE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.SWAP: (
{f.ALU_REG_WRITE, f.REG_A_ENABLE},
{f.REG_A_WRITE, f.REG_B_ENABLE},
{f.REG_B_WRITE, f.ALU_REG_ENABLE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.SWPI: (
{f.ALU_REG_WRITE, f.REG_B_ENABLE},
{f.REG_B_WRITE, f.REG_I_ENABLE},
{f.REG_I_WRITE, f.ALU_REG_ENABLE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.INC: (
{f.REG_A_ENABLE, f.ALU_REG_WRITE, f.CLR_OV},
{f.ALU_INC},
{f.ALU_OUT, f.REG_A_WRITE},
{f.PC_INC},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
i.NOP: (
{f.PC_INC, f.CLR_OV},
{f.PC_ENABLE},
{f.MEM_ENABLE, f.REG_IR_WRITE},
{f.MICRO_RESET},
),
}
MICROCODE = make_microcode()
def cpu(mem: Memory) -> Memory:
prog_counter = -1
reg_a = 0
reg_b = 0
reg_i = 0
reg_alu = 0
alu_out = 0
overflow = False
jumped = False
u = 0
instruction = CpuInst.NOP
new_instruction = CpuInst.NOP
bus = 0
inst_set = MICROCODE[instruction]
f = CpuFlag
while prog_counter < len(mem):
old_bus = bus
bus = 0
flags = inst_set[u]
if f.MICRO_RESET in flags:
u = 0
if not jumped:
instruction = new_instruction
else:
instruction = mem[prog_counter]
inst_set = MICROCODE[instruction]
if inst_set == jov_func:
inst_set = jov_func(overflow)
continue
if f.PC_INC in flags:
prog_counter += 1
if f.PC_ENABLE in flags:
bus = prog_counter
if f.REG_IR_ENABLE in flags:
bus = instruction
if f.MEM_ENABLE in flags:
bus = mem[old_bus]
if f.REG_A_ENABLE in flags:
bus = reg_a
if f.REG_B_ENABLE in flags:
bus = reg_b
if f.REG_I_ENABLE in flags:
bus = reg_i
if f.ALU_REG_ENABLE in flags:
bus = reg_alu
if f.ALU_OUT in flags:
bus = alu_out
if f.PC_WRITE in flags:
jumped = True
prog_counter = bus
if f.REG_IR_WRITE in flags:
new_instruction = bus
if f.MEM_WRITE in flags:
mem[old_bus] = bus
if f.REG_A_WRITE in flags:
reg_a = bus
if f.REG_B_WRITE in flags:
reg_b = bus
if f.REG_I_WRITE in flags:
reg_i = bus
if f.ALU_REG_WRITE in flags:
reg_alu = bus
if f.ALU_ADD in flags:
b = reg_alu + bus
if b > MAX_VALUE:
overflow = True
b %= MAX_VALUE
alu_out = b
if f.ALU_XOR in flags:
alu_out = reg_alu ^ bus
if f.ALU_INC in flags:
alu_out = reg_alu + 1
if alu_out >= MAX_VALUE:
overflow = True
alu_out %= MAX_VALUE
if f.CLR_OV in flags:
overflow = False
if f.SET_OV in flags:
overflow = True
u += 1
return mem
def create_prog(prog: Memory, length: int = 1000) -> Memory:
"""Normal instruction
FETCH, EXECUTE, INC"""
return prog + (length - len(prog)) * [0]
def make_fibonacci() -> Memory:
i = CpuInst
return create_prog(
prog=[
i.LIT,
65,
i.SWPI, # 0, 0, 65
i.INC, # 1, 0
i.SWAP, # 0, 1
i.STOR,
i.SWAP, # 1, 0
i.LOAD, # 1, 1
i.ADD, # 2, 1, 64
i.SWAP, # 1, 2, 64
i.STOR, #
i.LIT,
28,
i.JOTO, # Terminate if overflow
i.NOP,
i.LOAD,
i.SWPI, # a + b, 64, b
i.SWAP, # 64, a + b, b
i.INC, # 65, a + b, b
i.SWAP,
i.SWPI, # a + b, b, 65
i.STOR, # Stored A+B at next I
i.LIT,
1000,
i.JOTO,
i.LIT,
7,
i.JOTO,
i.LIT,
0,
i.STOR,
i.LIT,
1000,
i.JOTO,
i.JOTO,
],
length=512,
)
def make_count() -> Memory:
i = CpuInst
return create_prog([
i.LIT,
24,
i.SWPI,
i.LIT,
0,
i.INC, # 1, 0, 16
i.SWAP, # 0, 1, 16
i.STOR, # Write to loc 16
i.SWPI, # 0, 16, 1
i.SWAP, # 16, 0, 1
i.INC, # 17, 0, 1
i.SWAP, # 0, 17, 1
i.SWPI, # 0, 1, 17
i.SWAP, # 1, 0, 17
i.LIT,
1000,
i.JOTO,
i.LIT,
3,
i.JOTO,
])
if __name__ == '__main__':
pprint(cpu(make_fibonacci()))
Explore related questions
See similar questions with these tags.
NOP
seems to be the wrong opcode name. Consider calling itCLRV
, for clear overflow. \$\endgroup\$