1
\$\begingroup\$

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},
    ],
}
\$\endgroup\$
4
  • \$\begingroup\$ Is your max value really 300 bits wide? \$\endgroup\$
    – Reinderien
    Sep 9, 2023 at 3:33
  • \$\begingroup\$ No, because python! \$\endgroup\$ Sep 9, 2023 at 3:39
  • \$\begingroup\$ Note: edits to the question may complain about unformatted code. Please, rollback my edit to the table to move forward. Additional information is available on Meta. \$\endgroup\$
    – Peilonrayz
    Sep 9, 2023 at 4:37
  • \$\begingroup\$ NOP seems to be the wrong opcode name. Consider calling it CLRV, for clear overflow. \$\endgroup\$
    – J_H
    Sep 9, 2023 at 17:49

1 Answer 1

2
\$\begingroup\$

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()))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.