# 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)
```