From 8b2150d3f43d1fdf4617a7ad38c08bc696ff498a Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Mon, 11 Nov 2019 15:03:49 +0100 Subject: [PATCH 1/6] add ram_read and ram_write mthd --- ls8/cpu.py | 24 ++++++++++++++++-------- ls8/ls8.py | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 9a307496e..84eb8ff11 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -2,12 +2,15 @@ import sys + class CPU: """Main CPU class.""" def __init__(self): """Construct a new CPU.""" - pass + self.ram = [0] * 25 + self.reg = [] + self.pc = 0 def load(self): """Load a program into memory.""" @@ -18,25 +21,24 @@ def load(self): program = [ # From print8.ls8 - 0b10000010, # LDI R0,8 + 0b10000010, # LDI R0,8 0b00000000, 0b00001000, - 0b01000111, # PRN R0 + 0b01000111, # PRN R0 0b00000000, - 0b00000001, # HLT + 0b00000001, # HLT ] for instruction in program: self.ram[address] = instruction address += 1 - 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 + # elif op == "SUB": etc else: raise Exception("Unsupported ALU operation") @@ -48,8 +50,8 @@ def trace(self): print(f"TRACE: %02X | %02X %02X %02X |" % ( self.pc, - #self.fl, - #self.ie, + # self.fl, + # self.ie, self.ram_read(self.pc), self.ram_read(self.pc + 1), self.ram_read(self.pc + 2) @@ -63,3 +65,9 @@ def trace(self): def run(self): """Run the CPU.""" pass + + def ram_read(self, address): + return self.ram[address] + + def ram_write(self, value, address): + pass diff --git a/ls8/ls8.py b/ls8/ls8.py index 74128d36b..b9bffd194 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -8,4 +8,4 @@ cpu = CPU() cpu.load() -cpu.run() \ No newline at end of file +cpu.run() From a95712b442d5995087645c22580a4d36659504bc Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Mon, 11 Nov 2019 16:50:09 +0100 Subject: [PATCH 2/6] update the run method --- ls8/cpu.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 84eb8ff11..a896d5d10 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -8,8 +8,8 @@ class CPU: def __init__(self): """Construct a new CPU.""" - self.ram = [0] * 25 - self.reg = [] + self.ram = [0] * 255 + self.reg = [0] * 8 self.pc = 0 def load(self): @@ -64,10 +64,27 @@ def trace(self): def run(self): """Run the CPU.""" - pass + IR = self.ram[self.pc] + running = True + LDI = 0b10000010 + PRN = 0b01000111 + HLT = 0b00000001 + while running: + IR = self.ram[self.pc] + operand_a = self.ram_read(self.pc+1) + operand_b = self.ram_read(self.pc+2) + + if IR == LDI: + self.reg[operand_a] = operand_b + self.pc += 3 + elif IR == PRN: + print(self.reg[operand_a]) + self.pc += 2 + elif IR == HLT: + running = False def ram_read(self, address): return self.ram[address] def ram_write(self, value, address): - pass + self.ram[address] = value From 217190c45b64df246a8cbc6b7f0b7e5a7e757958 Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Tue, 12 Nov 2019 13:57:33 +0100 Subject: [PATCH 3/6] implement multiply --- ls8/cpu.py | 63 +++++++++++++++++++++++++++++++++++++----------------- ls8/ls8.py | 3 ++- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index a896d5d10..9038c2fce 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -12,33 +12,34 @@ def __init__(self): self.reg = [0] * 8 self.pc = 0 - def load(self): - """Load a program into memory.""" + # def load(self): + # """Load a program into memory.""" - address = 0 + # address = 0 - # For now, we've just hardcoded a program: + # # For now, we've just hardcoded a program: - program = [ - # From print8.ls8 - 0b10000010, # LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, # PRN R0 - 0b00000000, - 0b00000001, # HLT - ] + # 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 + # for instruction in program: + # self.ram[address] = instruction + # address += 1 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 + elif op == "MUL": + self.reg[reg_a] *= self.reg[reg_b] else: raise Exception("Unsupported ALU operation") @@ -69,6 +70,7 @@ def run(self): LDI = 0b10000010 PRN = 0b01000111 HLT = 0b00000001 + MUL = 0b10100010 while running: IR = self.ram[self.pc] operand_a = self.ram_read(self.pc+1) @@ -76,15 +78,36 @@ def run(self): if IR == LDI: self.reg[operand_a] = operand_b - self.pc += 3 + self.pc += (IR >> 6) + 1 elif IR == PRN: print(self.reg[operand_a]) - self.pc += 2 + # mask IR to get the opcode + self.pc += (IR >> 6) + 1 + elif IR == MUL: + self.alu('MUL', operand_a, operand_b) + self.pc += (IR >> 6) + 1 elif IR == HLT: running = False + sys.exit(2) def ram_read(self, address): return self.ram[address] - def ram_write(self, value, address): + def ram_write(self, address, value): self.ram[address] = value + + def load(self, filename): + try: + address = 0 + with open(filename) as f: + for line in f: + comment_split = line.split("#") + num = comment_split[0].strip() + if len(num) == 0: + continue + value = int(num, 2) + self.ram[address] = value + address += 1 + except FileNotFoundError: + print(f"{sys.argv[0]}: {sys.argv[1]} not found") + sys.exit(2) diff --git a/ls8/ls8.py b/ls8/ls8.py index b9bffd194..571717910 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -7,5 +7,6 @@ cpu = CPU() -cpu.load() +# cpu.load() +cpu.load(sys.argv[1]) cpu.run() From a18b18a142934b1f438e74109d919d96dbdb401d Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Wed, 13 Nov 2019 15:09:46 +0100 Subject: [PATCH 4/6] implement stack --- ls8/cpu.py | 39 ++++++++++++++------------------------- ls8/examples/stack.ls8 | 1 + ls8/ls8.py | 1 + 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 9038c2fce..017ea9636 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -11,27 +11,8 @@ def __init__(self): self.ram = [0] * 255 self.reg = [0] * 8 self.pc = 0 + self.sp = 6 - # def load(self): - # """Load a program into memory.""" - - # 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 def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -71,6 +52,8 @@ def run(self): PRN = 0b01000111 HLT = 0b00000001 MUL = 0b10100010 + POP = 0b01000110 + PUSH = 0b01000101 while running: IR = self.ram[self.pc] operand_a = self.ram_read(self.pc+1) @@ -78,17 +61,23 @@ def run(self): if IR == LDI: self.reg[operand_a] = operand_b - self.pc += (IR >> 6) + 1 elif IR == PRN: print(self.reg[operand_a]) - # mask IR to get the opcode - self.pc += (IR >> 6) + 1 elif IR == MUL: self.alu('MUL', operand_a, operand_b) - self.pc += (IR >> 6) + 1 + elif IR == PUSH: + self.sp -= 1 + value = self.reg[operand_a] + self.ram_write(self.sp, value) + elif IR == POP: + stack_value = self.ram[self.sp] + self.reg[operand_a] = stack_value + self.sp += 1 elif IR == HLT: running = False - sys.exit(2) + self.pc = 0 + # mask IR to get the opcode + self.pc += (IR >> 6) + 1 def ram_read(self, address): return self.ram[address] diff --git a/ls8/examples/stack.ls8 b/ls8/examples/stack.ls8 index e7c6e6687..a5a7c8bae 100644 --- a/ls8/examples/stack.ls8 +++ b/ls8/examples/stack.ls8 @@ -29,3 +29,4 @@ 01000111 # PRN R1 00000001 00000001 # HLT + diff --git a/ls8/ls8.py b/ls8/ls8.py index 571717910..ca3139c51 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -10,3 +10,4 @@ # cpu.load() cpu.load(sys.argv[1]) cpu.run() + From 1cabf7f75f83f43d79c64d5a49180b8d816bd4e3 Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Thu, 14 Nov 2019 17:05:36 +0100 Subject: [PATCH 5/6] update with call --- ls8/cpu.py | 35 ++++++++++---- ls8/cpu2.py | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ls8/ls8.py | 3 ++ 3 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 ls8/cpu2.py diff --git a/ls8/cpu.py b/ls8/cpu.py index 017ea9636..6c6c20d4c 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -2,6 +2,16 @@ import sys +LDI = 0b10000010 +PRN = 0b01000111 +HLT = 0b00000001 +MUL = 0b10100010 +POP = 0b01000110 +PUSH = 0b01000101 +CALL = 0b01010000 +RET = 0b00010001 +ADD = 0b10100000 + class CPU: """Main CPU class.""" @@ -9,10 +19,10 @@ class CPU: def __init__(self): """Construct a new CPU.""" self.ram = [0] * 255 - self.reg = [0] * 8 + self.reg = [0] * 16 self.pc = 0 - self.sp = 6 - + self.sp = 7 + self.op_pc = False def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -48,13 +58,8 @@ def run(self): """Run the CPU.""" IR = self.ram[self.pc] running = True - LDI = 0b10000010 - PRN = 0b01000111 - HLT = 0b00000001 - MUL = 0b10100010 - POP = 0b01000110 - PUSH = 0b01000101 while running: + IR = self.ram[self.pc] operand_a = self.ram_read(self.pc+1) operand_b = self.ram_read(self.pc+2) @@ -65,6 +70,8 @@ def run(self): print(self.reg[operand_a]) elif IR == MUL: self.alu('MUL', operand_a, operand_b) + elif IR == ADD: + self.alu('ADD', operand_a, operand_b) elif IR == PUSH: self.sp -= 1 value = self.reg[operand_a] @@ -76,6 +83,16 @@ def run(self): elif IR == HLT: running = False self.pc = 0 + elif IR == CALL: + self.sp -= 1 + self.ram_write(self.sp, operand_b) + self.pc = self.reg[operand_a] + self.op_pc = True + elif IR == RET: + self.pc = self.ram[self.sp] + self.op_pc = True + running = False + # mask IR to get the opcode self.pc += (IR >> 6) + 1 diff --git a/ls8/cpu2.py b/ls8/cpu2.py new file mode 100644 index 000000000..24a5b0a04 --- /dev/null +++ b/ls8/cpu2.py @@ -0,0 +1,134 @@ +"""CPU functionality.""" + +import sys + + +LDI = 0b10000010 +PRN = 0b01000111 +HLT = 0b00000001 +MUL = 0b10100010 +POP = 0b01000110 +PUSH = 0b01000101 +ADD = 0b10100000 + + +class CPU: + """Main CPU class.""" + + def __init__(self): + """Construct a new CPU.""" + self.ram = [0] * 255 + self.reg = [0] * 16 + self.pc = 0 + self.sp = 6 + + self.branchtable = {} + self.branchtable[LDI] = self.ldi + self.branchtable[PRN] = self.prn + self.branchtable[HLT] = self.hlt + self.branchtable[MUL] = self.mul + self.branchtable[POP] = self.pop + self.branchtable[PUSH] = self.push + + def alu(self, op, reg_a, reg_b): + """ALU operations.""" + + if op == "ADD": + self.reg[reg_a] += self.reg[reg_b] + elif op == "MUL": + self.reg[reg_a] *= self.reg[reg_b] + else: + raise Exception("Unsupported ALU operation") + + def ldi(self, op_a, op_b): + self.reg[op_a] = op_b + self.pc += (self.ram[self.pc] >> 6) + 1 + print(':', self.pc) + + def prn(self, val): + print(self.reg[val]) + self.pc += (self.ram[self.pc] >> 6) + 1 + print(':', self.pc) + + def hlt(self): + sys.exit(2) + + def mul(self, op_a, op_b): + self.alu('MUL', op_a, op_b) + # print(op_a, op_b) + self.pc += (self.ram[self.pc] >> 6) + 1 + print(':', self.pc) + + def pop(self, val): + stack_value = self.ram[self.sp] + self.reg[val] = stack_value + self.sp += 1 + self.pc += (self.ram[self.pc] >> 6) + 1 + print(':', self.pc) + + def push(self, val): + self.sp -= 1 + value = self.reg[val] + self.ram_write(self.sp, value) + self.pc += (self.ram[self.pc] >> 6) + 1 + print(':', self.pc) + + 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.""" + IR = self.ram[self.pc] + running = True + while running: + IR = self.ram[self.pc] + operand_a = self.ram_read(self.pc+1) + operand_b = self.ram_read(self.pc+2) + + self.branchtable[LDI](operand_a, operand_b) + self.branchtable[PUSH](operand_a) + self.branchtable[POP](operand_a) + self.branchtable[MUL](operand_a, operand_b) + self.branchtable[PRN](operand_a) + self.branchtable[HLT]() + + # self.pc += (IR >> 6) + 1 + + def ram_read(self, address): + return self.ram[address] + + def ram_write(self, address, value): + self.ram[address] = value + + def load(self, filename): + try: + address = 0 + with open(filename) as f: + for line in f: + comment_split = line.split("#") + num = comment_split[0].strip() + if len(num) == 0: + continue + value = int(num, 2) + self.ram[address] = value + address += 1 + except FileNotFoundError: + print(f"{sys.argv[0]}: {sys.argv[1]} not found") + sys.exit(2) diff --git a/ls8/ls8.py b/ls8/ls8.py index ca3139c51..955c573af 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -10,4 +10,7 @@ # cpu.load() cpu.load(sys.argv[1]) cpu.run() +# for i in cpu.ram: +# if i != 0: +# print(i) From 0d4c4771742f4eceb608882f08e8d67b0200f93c Mon Sep 17 00:00:00 2001 From: Rexben001 Date: Thu, 14 Nov 2019 20:27:59 +0100 Subject: [PATCH 6/6] update project --- ls8/cpu.py | 180 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 119 insertions(+), 61 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 6c6c20d4c..fb69e1870 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -11,6 +11,10 @@ CALL = 0b01010000 RET = 0b00010001 ADD = 0b10100000 +JNE = 0b01010110 +JEQ = 0b01010101 +JMP = 0b01010100 +CMP = 0b10100111 class CPU: @@ -18,11 +22,103 @@ class CPU: def __init__(self): """Construct a new CPU.""" - self.ram = [0] * 255 - self.reg = [0] * 16 + self.ram = [0] * 256 + self.reg = [0] * 8 self.pc = 0 - self.sp = 7 - self.op_pc = False + self.sp = 0xF4 + self.flags = 0b00000000 + + self.branchtable = {} + self.branchtable[LDI] = self.ldi + self.branchtable[PRN] = self.prn + self.branchtable[HLT] = self.hlt + self.branchtable[MUL] = self.mul + self.branchtable[POP] = self.pop + self.branchtable[PUSH] = self.push + self.branchtable[CALL] = self.call + self.branchtable[RET] = self.ret + self.branchtable[ADD] = self.add + self.branchtable[JNE] = self.jne + self.branchtable[JEQ] = self.jeq + self.branchtable[JMP] = self.jmp + self.branchtable[CMP] = self.cmp + + """ START ALU function calls""" + + def ldi(self, operand_a, operand_b): + self.reg[operand_a] = operand_b + self.pc += 3 + + def prn(self, operand_a, operand_b): + print(self.reg[operand_a]) + self.pc += 2 + + def hlt(self, operand_a, operand_b): + sys.exit(1) + + def mul(self, operand_a, operand_b): + self.alu("MUL", operand_a, operand_b) + self.pc += 3 + + def add(self, operand_a, operand_b): + self.alu("ADD", operand_a, operand_b) + self.pc += 3 + + def cmp(self, operand_a, operand_b): + self.alu("CMP", operand_a, operand_b) + self.pc += 3 + + def pop(self, operand_a, operand_b): + value = self.ram[self.sp] + self.reg[operand_a] = value + self.pc += 2 + + def push(self, operand_a, operand_b): + self.sp -= 1 + value = self.reg[operand_a] + self.ram_write(self.sp, value) + self.pc += 2 + + def call(self, operand_a, operand_b): + self.sp -= 1 + value = self.pc + 2 + self.ram_write(self.sp, value) + self.pc = self.reg[operand_a] + + def ret(self, operand_a, operand_b): + value = self.ram[self.sp] + self.pc = value + + def jmp(self, operand_a, operand_b): + self.pc = self.reg[operand_a] + + def jeq(self, operand_a, operand_b): + if self.flags == 0b00000001: + self.pc = self.reg[operand_a] + else: + self.pc += 2 + + def jne(self, operand_a, operand_b): + if self.flags != 0b00000001: + self.pc = self.reg[operand_a] + else: + self.pc += 2 + + def load(self, filename): + try: + address = 0 + with open(filename) as f: + for line in f: + comment_split = line.split("#") + num = comment_split[0].strip() + if len(num) == 0: + continue + value = int(num, 2) + self.ram[address] = value + address += 1 + except FileNotFoundError: + print(f"{sys.argv[0]}: {sys.argv[1]} not found") + sys.exit(2) def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -31,6 +127,13 @@ def alu(self, op, reg_a, reg_b): self.reg[reg_a] += self.reg[reg_b] elif op == "MUL": self.reg[reg_a] *= self.reg[reg_b] + elif op == "CMP": + if self.reg[reg_a] > self.reg[reg_b]: + self.flags = 0b00000010 + elif self.reg[reg_a] < self.reg[reg_b]: + self.flags = 0b00000100 + else: + self.flags = 0b00000001 else: raise Exception("Unsupported ALU operation") @@ -54,66 +157,21 @@ def trace(self): print() - def run(self): - """Run the CPU.""" - IR = self.ram[self.pc] - running = True - while running: - - IR = self.ram[self.pc] - operand_a = self.ram_read(self.pc+1) - operand_b = self.ram_read(self.pc+2) - - if IR == LDI: - self.reg[operand_a] = operand_b - elif IR == PRN: - print(self.reg[operand_a]) - elif IR == MUL: - self.alu('MUL', operand_a, operand_b) - elif IR == ADD: - self.alu('ADD', operand_a, operand_b) - elif IR == PUSH: - self.sp -= 1 - value = self.reg[operand_a] - self.ram_write(self.sp, value) - elif IR == POP: - stack_value = self.ram[self.sp] - self.reg[operand_a] = stack_value - self.sp += 1 - elif IR == HLT: - running = False - self.pc = 0 - elif IR == CALL: - self.sp -= 1 - self.ram_write(self.sp, operand_b) - self.pc = self.reg[operand_a] - self.op_pc = True - elif IR == RET: - self.pc = self.ram[self.sp] - self.op_pc = True - running = False - - # mask IR to get the opcode - self.pc += (IR >> 6) + 1 - def ram_read(self, address): return self.ram[address] def ram_write(self, address, value): self.ram[address] = value - def load(self, filename): - try: - address = 0 - with open(filename) as f: - for line in f: - comment_split = line.split("#") - num = comment_split[0].strip() - if len(num) == 0: - continue - value = int(num, 2) - self.ram[address] = value - address += 1 - except FileNotFoundError: - print(f"{sys.argv[0]}: {sys.argv[1]} not found") - sys.exit(2) + def run(self): + """Run the CPU.""" + + while True: + IR = self.ram_read(self.pc) + operand_a = self.ram_read(self.pc + 1) + operand_b = self.ram_read(self.pc + 2) + + if IR not in self.branchtable: + sys.exit(1) + else: + self.branchtable[IR](operand_a, operand_b)