From dd3f0b03435f02d029a32fe519c70d5b42b63ccc Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Mon, 15 Mar 2021 18:59:55 -0700 Subject: [PATCH 1/6] finished day 1 --- ls8/cpu.py | 61 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 9a307496e..8c95574a3 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -2,41 +2,66 @@ import sys +# opcodes +LDI = 0b10000010 +PRN = 0b01000111 +HLT = 0b00000001 + + class CPU: """Main CPU class.""" def __init__(self): """Construct a new CPU.""" - pass + self.pc = 0 + self.ram = [0] * 255 + self.register = [0] * 8 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 + 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 ram_read(self, ram_address): + return self.ram[ram_address] + + def ram_write(self, value, address): + self.ram[address] = value + + def PRN(self): + reg_index = self.ram[self.pc + 1] + print(self.register[reg_index]) + self.pc += 2 + + def LDI(self): + num = self.ram[self.pc + 1] + value = self.ram[self.pc + 2] + self.register[num] = value + self.pc += 3 + + def HLT(self): + running = False 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 +73,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) @@ -62,4 +87,20 @@ def trace(self): def run(self): """Run the CPU.""" - pass + running = True + while running: + # fetch + inst = self.ram[self.pc] + + # decode + if inst == LDI: + self.LDI() + + elif inst == PRN: + self.PRN() + + elif inst == HLT: + self.HLT() + + else: + print("Command not understood") From 3724c4f2f888b62a7cd471d8d610a1cde6e08665 Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Tue, 16 Mar 2021 20:48:08 -0700 Subject: [PATCH 2/6] mult.ls8 is running --- ls8/cpu.py | 92 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 18 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 8c95574a3..213e00236 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -6,6 +6,15 @@ LDI = 0b10000010 PRN = 0b01000111 HLT = 0b00000001 +CALL = 0b01010000 +CMP = 0b10100111 +MUL = 0b10100010 + +sys_file = "" +if len(sys.argv) < 2: + print("In terminal must provide: python3 ls8.py ") +else: + sys_file = sys.argv[1] class CPU: @@ -19,33 +28,68 @@ def __init__(self): def load(self): """Load a program into memory.""" + new_program = [] + if sys_file: + with open(sys_file) as new_file: + for line in new_file: + new_code = line.split('#')[0].strip() + # take out blank lines + if new_code == "": + continue + # change str to int + new_code_i = int(new_code, 2) + new_program.append(new_code_i) + print("new_program", new_program) + else: + quit() + print(FileNotFoundError) + 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: + for instruction in new_program: self.ram[address] = instruction address += 1 + # # 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 ram_read(self, ram_address): return self.ram[ram_address] def ram_write(self, value, address): self.ram[address] = value - def PRN(self): - reg_index = self.ram[self.pc + 1] - print(self.register[reg_index]) - self.pc += 2 + def CALL(self): + # I believe this is like a repeat: change self.pc = to the value in the next self.ram + ram_index = self.ram[self.pc + 1] + self.pc = ram_index + + def CMP(self): + index_a = self.ram[self.pc + 1] + index_b = self.ram[self.pc + 2] + value_a = self.register[index_a] + value_b = self.register[index_b] + if value_a < value_b: + self.ram[index_a] = self.ram[index_a] & 11111100 + elif value_a > value_b: + self.ram[index_a] = self.ram[index_a] & 11111010 + else: + self.ram[index_a] = self.ram[index_a] & 11111001 + self.pc += 3 + + def HLT(self): + running = False def LDI(self): num = self.ram[self.pc + 1] @@ -53,8 +97,17 @@ def LDI(self): self.register[num] = value self.pc += 3 - def HLT(self): - running = False + def MUL(self): + reg_index_a = self.ram[self.pc + 1] + reg_index_b = self.ram[self.pc + 2] + self.register[reg_index_a] = self.register[reg_index_a] * \ + self.register[reg_index_b] + self.pc += 3 + + def PRN(self): + reg_index = self.ram[self.pc + 1] + print(self.register[reg_index]) + self.pc += 2 def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -96,6 +149,9 @@ def run(self): if inst == LDI: self.LDI() + elif inst == MUL: + self.MUL() + elif inst == PRN: self.PRN() From 4f37969c8434fd1806bbedd1096c9145c91c8c4f Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Wed, 17 Mar 2021 13:42:47 -0700 Subject: [PATCH 3/6] push and pop are working --- ls8/cpu.py | 66 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 213e00236..0eacf0f03 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -3,12 +3,17 @@ import sys # opcodes -LDI = 0b10000010 -PRN = 0b01000111 -HLT = 0b00000001 CALL = 0b01010000 CMP = 0b10100111 +HLT = 0b00000001 +LDI = 0b10000010 MUL = 0b10100010 +POP = 0b01000110 +PUSH = 0b01000101 +PRN = 0b01000111 + +# Stack Pointer is the index for Register +SP = 7 sys_file = "" if len(sys.argv) < 2: @@ -25,6 +30,8 @@ def __init__(self): self.pc = 0 self.ram = [0] * 255 self.register = [0] * 8 + # Set starting stack location within ram to hexadecimal 244 + self.register[SP] = 0xf4 def load(self): """Load a program into memory.""" @@ -73,7 +80,7 @@ def ram_write(self, value, address): def CALL(self): # I believe this is like a repeat: change self.pc = to the value in the next self.ram ram_index = self.ram[self.pc + 1] - self.pc = ram_index + # self.pc = ram_index def CMP(self): index_a = self.ram[self.pc + 1] @@ -86,35 +93,40 @@ def CMP(self): self.ram[index_a] = self.ram[index_a] & 11111010 else: self.ram[index_a] = self.ram[index_a] & 11111001 - self.pc += 3 def HLT(self): running = False + sys.exit(0) def LDI(self): num = self.ram[self.pc + 1] value = self.ram[self.pc + 2] self.register[num] = value - self.pc += 3 - def MUL(self): - reg_index_a = self.ram[self.pc + 1] - reg_index_b = self.ram[self.pc + 2] - self.register[reg_index_a] = self.register[reg_index_a] * \ - self.register[reg_index_b] - self.pc += 3 + def PUSH(self, op_a): + # decrement the SP to point to open space in ram + self.register[SP] -= 1 + # at that location in ram save the value from reg[pc+1] + self.ram[self.register[SP]] = self.register[op_a] - def PRN(self): - reg_index = self.ram[self.pc + 1] - print(self.register[reg_index]) - self.pc += 2 + def POP(self, op_a): + # copy value from ram at the index stored in reg[SP] to reg at next index (op_a) + self.register[op_a] = self.ram[self.register[SP]] + # move the SP back up + self.register[SP] += 1 + def PRN(self, op_a): + print(self.register[op_a]) + + # Arithmetic Logic Unit def alu(self, op, reg_a, reg_b): """ALU operations.""" if op == "ADD": - self.reg[reg_a] += self.reg[reg_b] + self.register[reg_a] += self.register[reg_b] # elif op == "SUB": etc + elif op == "MUL": + self.register[reg_a] *= self.register[reg_b] else: raise Exception("Unsupported ALU operation") @@ -140,23 +152,39 @@ def trace(self): def run(self): """Run the CPU.""" + running = True while running: # fetch inst = self.ram[self.pc] + op_a = self.ram[self.pc + 1] + op_b = self.ram[self.pc + 2] + + # decode opcode size + opcode_size = (inst >> 6) + 1 # decode if inst == LDI: self.LDI() elif inst == MUL: - self.MUL() + self.alu("MUL", op_a, op_b) + + elif inst == POP: + self.POP(op_a) elif inst == PRN: - self.PRN() + self.PRN(op_a) + + elif inst == PUSH: + self.PUSH(op_a) elif inst == HLT: self.HLT() else: print("Command not understood") + running = False + # sys.exit(1) + + self.pc += opcode_size From c69a10618fa2fe2e3887235b4b299b454d1eed51 Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Thu, 18 Mar 2021 14:05:14 -0700 Subject: [PATCH 4/6] call.ls8 is working --- ls8/cpu.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 0eacf0f03..a81980327 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -3,6 +3,7 @@ import sys # opcodes +ADD = 0b10100000 CALL = 0b01010000 CMP = 0b10100111 HLT = 0b00000001 @@ -11,6 +12,7 @@ POP = 0b01000110 PUSH = 0b01000101 PRN = 0b01000111 +RET = 0b00010001 # Stack Pointer is the index for Register SP = 7 @@ -77,10 +79,14 @@ def ram_read(self, ram_address): def ram_write(self, value, address): self.ram[address] = value - def CALL(self): - # I believe this is like a repeat: change self.pc = to the value in the next self.ram - ram_index = self.ram[self.pc + 1] - # self.pc = ram_index + def CALL(self, op_a): + # decrement the stack pointer so we have an empty slot to store a value + self.register[SP] -= 1 + # Store the return address from reg[pc+2] in ram so that when the subroutine is done we can return back where we left off + self.ram[self.register[SP]] = self.pc+2 + # Go to subroutine reg[pc+1] + self.pc = self.register[op_a] + # Don't increment the pc!!! def CMP(self): index_a = self.ram[self.pc + 1] @@ -118,6 +124,12 @@ def POP(self, op_a): def PRN(self, op_a): print(self.register[op_a]) + def RET(self): + # set pc = to the return address + self.pc = self.ram[self.register[SP]] + # increment the SP because that value has been popped + self.register[SP] += 1 + # Arithmetic Logic Unit def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -167,6 +179,15 @@ def run(self): if inst == LDI: self.LDI() + elif inst == ADD: + self.alu("ADD", op_a, op_b) + + elif inst == CALL: + self.CALL(op_a) + + elif inst == HLT: + self.HLT() + elif inst == MUL: self.alu("MUL", op_a, op_b) @@ -179,12 +200,13 @@ def run(self): elif inst == PUSH: self.PUSH(op_a) - elif inst == HLT: - self.HLT() + elif inst == RET: + self.RET() else: print("Command not understood") running = False # sys.exit(1) - self.pc += opcode_size + if inst & 0b00010000 == 0: + self.pc += opcode_size From 3d56a4cb4d178ad4624b7e9407567f72a45c864c Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Fri, 19 Mar 2021 11:11:24 -0700 Subject: [PATCH 5/6] finished sprint challenge plus some stretch (OR, AND, XOR) --- ls8/cpu.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index a81980327..c0891cb2f 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -4,15 +4,21 @@ # opcodes ADD = 0b10100000 +AND = 0b10101000 CALL = 0b01010000 CMP = 0b10100111 HLT = 0b00000001 +JEQ = 0b01010101 +JMP = 0b01010100 +JNE = 0b01010110 LDI = 0b10000010 MUL = 0b10100010 +OR = 0b10101010 POP = 0b01000110 PUSH = 0b01000101 PRN = 0b01000111 RET = 0b00010001 +XOR = 0b10101011 # Stack Pointer is the index for Register SP = 7 @@ -34,6 +40,7 @@ def __init__(self): self.register = [0] * 8 # Set starting stack location within ram to hexadecimal 244 self.register[SP] = 0xf4 + self.fl = 0 def load(self): """Load a program into memory.""" @@ -88,22 +95,27 @@ def CALL(self, op_a): self.pc = self.register[op_a] # Don't increment the pc!!! - def CMP(self): - index_a = self.ram[self.pc + 1] - index_b = self.ram[self.pc + 2] - value_a = self.register[index_a] - value_b = self.register[index_b] - if value_a < value_b: - self.ram[index_a] = self.ram[index_a] & 11111100 - elif value_a > value_b: - self.ram[index_a] = self.ram[index_a] & 11111010 - else: - self.ram[index_a] = self.ram[index_a] & 11111001 - def HLT(self): running = False sys.exit(0) + def JEQ(self, op_a): + # check if the 2 values set the flag = equal + if self.fl == 0b00000001: + self.pc = self.register[op_a] + else: + self.pc += 2 + + def JMP(self, op_a): + self.pc = self.register[op_a] + + def JNE(self, op_a): + # check if the 2 values set the flag to not equal + if self.fl != 0b00000001: + self.pc = self.register[op_a] + else: + self.pc += 2 + def LDI(self): num = self.ram[self.pc + 1] value = self.ram[self.pc + 2] @@ -137,8 +149,35 @@ def alu(self, op, reg_a, reg_b): if op == "ADD": self.register[reg_a] += self.register[reg_b] # elif op == "SUB": etc + + elif op == "AND": + self.register[op_a] = self.register[op_a] & self.register[op_b] + + elif op == "CMP": + value_a = self.register[reg_a] + value_b = self.register[reg_b] + if value_a < value_b: + self.fl = 0b00000100 + elif value_a > value_b: + self.fl = 0b00000010 + else: + self.fl = 0b00000001 + elif op == "MUL": self.register[reg_a] *= self.register[reg_b] + + elif op == "OR": + self.register[reg_a] = self.register[reg_a] | self.register[reg_b] + + elif op == "XOR": + # exclusive or (one or other can be 1, but not both) + # find the AND between the two nums + and_result = self.register[reg_a] & self.register[reg_b] + # find the OR between the two nums + or_result = self.register[reg_a] | self.register[reg_b] + # combine those results with AND, then take the opposite + self.register[reg_a] = ~(and_result & or_result) + else: raise Exception("Unsupported ALU operation") @@ -182,15 +221,33 @@ def run(self): elif inst == ADD: self.alu("ADD", op_a, op_b) + elif inst == AND: + self.alu("AND", op_a, op_b) + elif inst == CALL: self.CALL(op_a) + elif inst == CMP: + self.alu("CMP", op_a, op_b) + elif inst == HLT: self.HLT() + elif inst == JEQ: + self.JEQ(op_a) + + elif inst == JMP: + self.JMP(op_a) + + elif inst == JNE: + self.JNE(op_a) + elif inst == MUL: self.alu("MUL", op_a, op_b) + elif inst == OR: + self.alu("OR", op_a, op_b) + elif inst == POP: self.POP(op_a) @@ -203,6 +260,9 @@ def run(self): elif inst == RET: self.RET() + elif inst == XOR: + self.alu("XOR", op_a, op_b) + else: print("Command not understood") running = False From 204c03ae599c52ad184dff408289aad92a8b8f51 Mon Sep 17 00:00:00 2001 From: Brian Kubes Date: Fri, 19 Mar 2021 11:14:21 -0700 Subject: [PATCH 6/6] fixed the code for XOR --- ls8/cpu.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index c0891cb2f..fb0544174 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -171,12 +171,7 @@ def alu(self, op, reg_a, reg_b): elif op == "XOR": # exclusive or (one or other can be 1, but not both) - # find the AND between the two nums - and_result = self.register[reg_a] & self.register[reg_b] - # find the OR between the two nums - or_result = self.register[reg_a] | self.register[reg_b] - # combine those results with AND, then take the opposite - self.register[reg_a] = ~(and_result & or_result) + self.register[reg_a] = self.register[reg_a] ^ self.register[reg_b] else: raise Exception("Unsupported ALU operation")