---
# System prepended metadata

title: CSPT10 Computer Architecture IV

---

# CSPT10 Computer Architecture IV
## CALL/RET
```
import sys

PRINT_HI = 1
HALT = 2
PRINT_NUM = 3
SAVE = 4 # save a value to a register
PRINT_REGISTER = 5 # prints the value of a register
ADD = 6 # adds values from two registers x, y and stores it in register x
PUSH = 7
POP = 8
CALL = 9
RET = 10
PRINT_SUBROUTINE_INSTRUCTION = 11

def loadMemory():
    memory = [
        PRINT_HI, # prints hi
        SAVE, # saves 7 into register 2
        7,
        2,
        CALL, # jump to the address stored in register 2
        2,
        HALT, # stop the program
        PRINT_SUBROUTINE_INSTRUCTION,
        SAVE,
        500,
        0,
        RET # jump back to address stored in the top of the stack (7, which is HALT)
    ]
    spaceForStack = 128 - len(memory)
    memory += [0] * spaceForStack
    return memory

memory = loadMemory()
SP = 7 # register number for stack pointer
pc = 0 # program counter - points to the instruction we're currently executing
running = True
registers = [0] * 8
registers[SP] = 127

while running:
    commandToExecute = memory[pc]

    if commandToExecute == PRINT_HI:
        print("hi")
        pc += 1
    elif commandToExecute == HALT:
        running = False
    elif commandToExecute == PRINT_NUM:
        numToPrint = memory[pc + 1]
        print(numToPrint)
        pc += 2
    elif commandToExecute == PRINT_REGISTER:
        reg = memory[pc + 1]
        print(registers[reg])
        pc += 2
    elif commandToExecute == SAVE:
        numToSave = memory[pc + 1]
        registerToSaveItIn = memory[pc + 2]
        registers[registerToSaveItIn] = numToSave
        pc += 3
    elif commandToExecute == ADD:
        regA = memory[pc + 1]
        regB = memory[pc + 2]
        sumOfRegisters = registers[regA] + registers[regB]
        registers[regA] = sumOfRegisters
        pc += 3
    elif commandToExecute == PUSH:
        registers[SP] -= 1
        registerToGetValueIn = memory[pc + 1]
        valueInRegister = registers[registerToGetValueIn]
        memory[registers[SP]] = valueInRegister
        pc += 2
    elif commandToExecute == POP:
        registerToPopValueIn = memory[pc + 1]
        registers[registerToPopValueIn] = memory[registers[SP]]
        registers[SP] += 1
        pc += 2
    elif commandToExecute == CALL:
        # store address of the next instruction onto the stack
        registers[SP] -= 1
        addressOfNextInstruction = pc + 2
        memory[registers[SP]] = addressOfNextInstruction
        # jump to the address stored in the given register
        registerToGetAddressFrom = memory[pc + 1]
        addressToJumpTo = registers[registerToGetAddressFrom]
        pc = addressToJumpTo
    elif commandToExecute == RET:
        # pop the topmost value in the stack
        addressToReturnTo = memory[registers[SP]]
        memory[registers[SP]] += 1
        # set the pc to that value
        pc = addressToReturnTo
    elif commandToExecute == PRINT_SUBROUTINE_INSTRUCTION:
        print("i'm in a subroutine")
        pc += 1
    else:
        print("ehh idk what to do")
        sys.exit(1)

print(registers)

```

## Guided Project Pt III
```
"""CPU functionality."""

import sys

HLT = 0b00000001
LDI = 0b10000010
PRN = 0b01000111
MULT = 0b10100010
PUSH = 0b01000101
POP = 0b01000110
SP = 7

class CPU:
    """Main CPU class."""

    def __init__(self):
        """Construct a new CPU."""
        self.pc = 0
        self.halted = False
        self.ram = [0] * 256
        self.reg = [0] * 8
        self.reg[7] = 0xF4

    def load(self, filename):
        """Load a program into memory."""
        address = 0
        with open(filename) as fp:
            for line in fp:
                comment_split = line.split("#")
                num = comment_split[0].strip()
                if num == '':  # ignore blanks
                    continue
                val = int(num, 2)
                self.ram_write(val, address)
                address += 1

    # Stores value in specified address in ram
    def ram_write(self, value, address):
        self.ram[address] = value

    # Returns value in ram stored in address
    def ram_read(self, address):
        return self.ram[address]

    def alu(self, op, reg_a, reg_b):
        """ALU operations."""

        if op == "ADD":
            self.reg[reg_a] += self.reg[reg_b]
        #elif op == "SUB": etc
        else:
            raise Exception("Unsupported ALU operation")

    def trace(self):
        """
        Handy function to print out the CPU state. You might want to call this
        from run() if you need help debugging.
        """

        print(f"TRACE: %02X | %02X %02X %02X |" % (
            self.pc,
            #self.fl,
            #self.ie,
            self.ram_read(self.pc),
            self.ram_read(self.pc + 1),
            self.ram_read(self.pc + 2)
        ), end='')

        for i in range(8):
            print(" %02X" % self.reg[i], end='')

        print()

    def run(self):
        """Run the CPU."""
        while not self.halted:
            # self.trace()
            instruction_to_execute = self.ram[self.pc]
            operand_a = self.ram[self.pc + 1]
            operand_b = self.ram[self.pc + 2]
            self.execute_instruction(instruction_to_execute, operand_a, operand_b)

    def execute_instruction(self, instruction, operand_a, operand_b):
        if instruction == HLT:
            self.halted = True
            self.pc += 1
        elif instruction == PRN:
            print(self.reg[operand_a])
            self.pc += 2
        elif instruction == LDI:
            self.reg[operand_a] = operand_b
            self.pc += 3
        elif instruction == MULT:
            self.reg[operand_a] *= self.reg[operand_b]
            self.pc += 3
        elif instruction == PUSH:
            # decrement the stack pointer
            self.reg[SP] -= 1
            # write the value stored in register onto the stack
            valueFromRegister = self.reg[operand_a]
            self.ram_write(valueFromRegister, self.reg[SP])
            self.pc += 2
        elif instruction == POP:
            # save the value on top of the stack onto the register given
            topmostValue = self.ram_read(self.reg[SP])
            self.reg[operand_a] = topmostValue
            # increment the stack pointer
            self.reg[SP] += 1
            self.pc += 2
        else:
            print("Idk this instruction. Exiting")
            sys.exit(1)

```
