Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 136 additions & 19 deletions ls8/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,77 @@

import sys

HLT = 0b00000001
LDI = 0b10000010
PRN = 0b01000111
MULT = 0b10100010
ADD = 0b10100000
PUSH = 0b01000101
POP = 0b01000110
CALL = 0b01010000
RET = 0b00010001
JMP = 0b01010100
CMP = 0b10100111
JEQ = 0b01010101
JNE = 0b01010110
class CPU:
"""Main CPU class."""

def __init__(self):
"""Construct a new CPU."""
pass

self.ram = [0] * 256
self.reg = [0] * 8
self.pc = 0
self.sp = 0xF4
self.fl = 0b00000000

def load(self):
"""Load a program into memory."""

if len(sys.argv) != 2:
print("You must enter the ls8.py and then the name of the ls8 file.")
sys.exit()
address = 0

# For now, we've just hardcoded a program:

program = [
# From print8.ls8
0b10000010, # LDI R0,8
0b00000000,
0b00001000,
0b01000111, # PRN R0
0b00000000,
0b00000001, # HLT
]

for instruction in program:
self.ram[address] = instruction
address += 1
program = open(sys.argv[1], 'r')

try:
for instruction in program:
comment = False
insert = ""
for char in instruction:
if char == "#":
comment = True
if comment == True:
break
elif char == "\n":
pass
else:
insert += str(char)
if insert == "":
pass
else:
self.ram[address] = int(insert,2)
address += 1
except FileNotFoundError:
print ("file not found")
sys.exit()


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
self.ram[reg_a] += self.ram[reg_b]
elif op == "MULT":
self.ram[reg_a] *= self.ram[reg_b]
elif op == "CMP":
if self.ram[reg_a] == self.ram[reg_b]:
self.fl = 0b00000001
elif self.ram[reg_a] < self.ram[reg_b]:
self.fl = 0b00000100
elif self.ram[reg_a] > self.ram[reg_b]:
self.fl = 0b00000010
else:
raise Exception("Unsupported ALU operation")

Expand All @@ -60,6 +96,87 @@ def trace(self):

print()

def ram_read(self, address):
return self.ram[address]

def ram_write(self, address, value):
self.ram[address] = value
return

def stack(self, op, value = None):
if op == "PUSH":
self.sp -= 1
self.ram_write(self.sp, value)
return
elif op == "POP":
if self.sp < 0xF4:
pop_value = self.ram_read(self.sp)
# print(pop_value, " <-- Pop_value")
self.sp += 1
return pop_value
else:
print("ERROR: Stack is empty")
return


def run(self):
"""Run the CPU."""
while True:
ir = self.ram_read(self.pc)
byt_a = self.ram_read(self.pc + 1)
byt_b = self.ram_read(self.pc + 2)

if ir == HLT:
break
elif ir == LDI:
self.ram[byt_a] = byt_b
self.pc += 3
elif ir == PRN:
print(self.ram[byt_a], "\n")
self.pc += 2
elif ir == MULT:
self.alu("MULT", byt_a, byt_b)
self.pc += 3
elif ir == ADD:
self.alu("ADD", byt_a, byt_b)
self.pc += 3
elif ir == PUSH:
self.stack("PUSH", self.ram[byt_a])
# print(self.reg[byt_a], " <-- self.reg[byt_a]")
self.pc += 2
elif ir == POP:
value = self.stack("POP")
self.ram[byt_a] = value
self.pc += 2
elif ir == CALL:
self.stack("PUSH", self.pc+2)
sub_address = self.ram[byt_a]
self.pc = sub_address
elif ir == RET:
address = self.stack("POP")
self.pc = address
elif ir == JMP:
address = self.ram[byt_a]
self.pc = address
elif ir == CMP:
self.alu("CMP", byt_a, byt_b)
self.pc += 3
elif ir == JNE:
if self.fl != 0b00000001:
jmp_address = self.ram[byt_a]
self.pc = jmp_address
else:
self.pc += 2
elif ir == JEQ:
if self.fl == 0b00000001:
jmp_address = self.ram[byt_a]
self.pc = jmp_address
else:
self.pc += 2
else:
print(f"Unknown Instruction {ir}")
if self.pc < len(self.ram)-1:
self.pc += 1
else:
ir = HLT
pass