From f61b3bd3bacfa2bd75f3ee517ca7b832460f094f Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 2 Dec 2020 20:10:54 -0700 Subject: [PATCH 01/11] Update cpu.py --- ls8/cpu.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 9a307496e..351535cb0 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -1,3 +1,5 @@ +# cpu.py + """CPU functionality.""" import sys @@ -6,8 +8,17 @@ class CPU: """Main CPU class.""" def __init__(self): - """Construct a new CPU.""" - pass + # Set RAM + self.ram = [0] * 256 + # Create registers: R0 - R6 empty + self.reg = [0] * 8 + # R7 set to 0xF4 + self.reg[7] = 0xF4 + + # Set program counter to 0 + self.pc = 0 + # Set flags to 0 + self.fl = 0 def load(self): """Load a program into memory.""" @@ -40,6 +51,9 @@ def alu(self, op, reg_a, reg_b): else: raise Exception("Unsupported ALU operation") + def ram_read(self, pc): + return pc + def trace(self): """ Handy function to print out the CPU state. You might want to call this @@ -62,4 +76,4 @@ def trace(self): def run(self): """Run the CPU.""" - pass + self.trace() From 67297a0b63f2a06cde6a8f748b85d003335deae7 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 2 Dec 2020 20:31:51 -0700 Subject: [PATCH 02/11] Added ram_read() and ram_write(), started run() --- ls8/cpu.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 351535cb0..d89dda8d7 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -19,6 +19,10 @@ def __init__(self): self.pc = 0 # Set flags to 0 self.fl = 0 + # Memory Address Register, holds the memory address we're reading or writing + self.mar = 0 + #Memory Data Register, holds the value to write or the value just read + self.mdr = 0 def load(self): """Load a program into memory.""" @@ -51,8 +55,11 @@ def alu(self, op, reg_a, reg_b): else: raise Exception("Unsupported ALU operation") - def ram_read(self, pc): - return pc + def ram_read(self, mar): + return self.ram[mar] + + def ram_write(self, mar, mdr): + self.ram[mar] = mdr def trace(self): """ @@ -76,4 +83,14 @@ def trace(self): def run(self): """Run the CPU.""" + running = True + + while running: + command_to_execute = self.ram[self.pc] + + + self.trace() + +cpu = CPU() +cpu.run() From 610c045baa9c6d403e67a2f09b4eb2dcc1927483 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 2 Dec 2020 21:14:21 -0700 Subject: [PATCH 03/11] Completed run(self): --- ls8/cpu.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index d89dda8d7..18d717166 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -21,7 +21,7 @@ def __init__(self): self.fl = 0 # Memory Address Register, holds the memory address we're reading or writing self.mar = 0 - #Memory Data Register, holds the value to write or the value just read + # #Memory Data Register, holds the value to write or the value just read self.mdr = 0 def load(self): @@ -83,12 +83,32 @@ def trace(self): def run(self): """Run the CPU.""" + # Load tasks into RAM + self.load() + running = True + ldi = 0b10000010 + prn = 0b01000111 + hlt = 0b00000001 while running: - command_to_execute = self.ram[self.pc] - + print(self.pc) + command_to_execute = self.ram_read(self.pc) + if command_to_execute == ldi: + print("LDI executed") + self.reg[self.pc + 1] = self.pc + 2 + self.pc += 3 + elif command_to_execute == prn: + print("Print executed") + print(self.reg[self.pc + 1]) + self.pc += 2 + elif command_to_execute == hlt: + print("Halt executed") + running = False + else: + print(f"Unkown command: {command_to_execute}") + self.pc += 1 self.trace() From 6bef4b91f1b48065e249e5903efdb688b37d5a54 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 3 Dec 2020 21:02:06 -0700 Subject: [PATCH 04/11] Update ls8.py --- ls8/ls8.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ls8/ls8.py b/ls8/ls8.py index 74128d36b..90735d3bd 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -6,6 +6,5 @@ from cpu import * cpu = CPU() - -cpu.load() -cpu.run() \ No newline at end of file +cpu.load(fileNameFromCommandLine) +cpu.run() From 9fcaecc38b95a6628a88ea19f91db793619d2020 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 3 Dec 2020 21:37:56 -0700 Subject: [PATCH 05/11] Added ability to load file dynamically --- ls8/cpu.py | 45 ++++++++++++++++++++++++++++++++------------- ls8/ls8.py | 2 +- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 18d717166..e5a3bc147 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -3,6 +3,7 @@ """CPU functionality.""" import sys +import os class CPU: """Main CPU class.""" @@ -24,22 +25,42 @@ def __init__(self): # #Memory Data Register, holds the value to write or the value just read self.mdr = 0 - def load(self): + def load(self, file_name): """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 - ] + # program = [ + # # From print8.ls8 + # 0b10000010, # LDI R0,8 + # 0b00000000, + # 0b00001000, + # 0b01000111, # PRN R0 + # 0b00000000, + # 0b00000001, # HLT + # ] + + program = [] + + input_text = os.path.join(os.path.dirname(__file__), f"examples/{file_name}") + + try: + with open(input_text) as my_file: + for line in my_file: + comment_split = line.split('#') + possible_binary_number = comment_split[0] + + try: + x = int(possible_binary_number, 2) + program.append(x) + print("{:08b}: {:d}".format(x, x)) + except: + print(f"Failed to cast {possible_binary_number} to an int") + continue + except: + print(f"File: {file_name} not found...") for instruction in program: self.ram[address] = instruction @@ -84,7 +105,7 @@ def trace(self): def run(self): """Run the CPU.""" # Load tasks into RAM - self.load() + # self.load() running = True ldi = 0b10000010 @@ -112,5 +133,3 @@ def run(self): self.trace() -cpu = CPU() -cpu.run() diff --git a/ls8/ls8.py b/ls8/ls8.py index 90735d3bd..e426442bc 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -6,5 +6,5 @@ from cpu import * cpu = CPU() -cpu.load(fileNameFromCommandLine) +cpu.load("mult.ls8") #fileNameFromCommandLine cpu.run() From d3eda108178316aac3109dcc56f6352e6bc707fd Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 3 Dec 2020 22:03:31 -0700 Subject: [PATCH 06/11] Added support for mult.ls8 --- ls8/cpu.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index e5a3bc147..4693e6902 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -54,8 +54,8 @@ def load(self, file_name): try: x = int(possible_binary_number, 2) + # print("{:08b}: {:d}".format(x, x)) program.append(x) - print("{:08b}: {:d}".format(x, x)) except: print(f"Failed to cast {possible_binary_number} to an int") continue @@ -104,29 +104,38 @@ def trace(self): def run(self): """Run the CPU.""" - # Load tasks into RAM - # self.load() running = True ldi = 0b10000010 prn = 0b01000111 hlt = 0b00000001 + mul = 0b10100010 while running: print(self.pc) command_to_execute = self.ram_read(self.pc) + op_a = self.ram_read(self.pc + 1) + op_b = self.ram_read(self.pc + 2) if command_to_execute == ldi: print("LDI executed") - self.reg[self.pc + 1] = self.pc + 2 + # self.reg[self.pc + 1] = self.pc + 2 + self.reg[op_a] = self.pc + 2 self.pc += 3 elif command_to_execute == prn: print("Print executed") - print(self.reg[self.pc + 1]) + + # print(self.reg[self.pc + 1]) + print(self.reg[op_a]) self.pc += 2 elif command_to_execute == hlt: print("Halt executed") running = False + elif command_to_execute == mul: + print("Mult executed") + print(op_a, op_b) + self.reg[op_a] *= self.reg[op_b] + self.pc += 3 else: print(f"Unkown command: {command_to_execute}") self.pc += 1 From 33206efcf2bea99ec3e1546a334a0644bdf0ae87 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Fri, 4 Dec 2020 12:14:18 -0700 Subject: [PATCH 07/11] Added bit masking op to increment self.pc without hard coding --- ls8/cpu.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 4693e6902..7280f0df7 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -112,33 +112,33 @@ def run(self): mul = 0b10100010 while running: - print(self.pc) + # print(self.pc) command_to_execute = self.ram_read(self.pc) op_a = self.ram_read(self.pc + 1) op_b = self.ram_read(self.pc + 2) if command_to_execute == ldi: print("LDI executed") - # self.reg[self.pc + 1] = self.pc + 2 self.reg[op_a] = self.pc + 2 - self.pc += 3 + number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 + self.pc += number_of_times_to_increment_pc elif command_to_execute == prn: print("Print executed") - - # print(self.reg[self.pc + 1]) print(self.reg[op_a]) - self.pc += 2 - elif command_to_execute == hlt: - print("Halt executed") - running = False + number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 + self.pc += number_of_times_to_increment_pc elif command_to_execute == mul: print("Mult executed") print(op_a, op_b) self.reg[op_a] *= self.reg[op_b] - self.pc += 3 + number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 + self.pc += number_of_times_to_increment_pc + elif command_to_execute == hlt: + print("Halt executed") + running = False else: print(f"Unkown command: {command_to_execute}") - self.pc += 1 + number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 + self.pc += number_of_times_to_increment_pc self.trace() - From 4ed28450a53743814311976d371dec6c7bc8c3f0 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Fri, 4 Dec 2020 12:17:56 -0700 Subject: [PATCH 08/11] Refactored bit masking op --- ls8/cpu.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 7280f0df7..bf0836eab 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -120,25 +120,21 @@ def run(self): if command_to_execute == ldi: print("LDI executed") self.reg[op_a] = self.pc + 2 - number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 - self.pc += number_of_times_to_increment_pc + self.pc += ((command_to_execute >> 6) & 0b11) + 1 elif command_to_execute == prn: print("Print executed") print(self.reg[op_a]) - number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 - self.pc += number_of_times_to_increment_pc + self.pc += ((command_to_execute >> 6) & 0b11) + 1 elif command_to_execute == mul: print("Mult executed") print(op_a, op_b) self.reg[op_a] *= self.reg[op_b] - number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 - self.pc += number_of_times_to_increment_pc + self.pc += ((command_to_execute >> 6) & 0b11) + 1 elif command_to_execute == hlt: print("Halt executed") running = False else: print(f"Unkown command: {command_to_execute}") - number_of_times_to_increment_pc = ((command_to_execute >> 6) & 0b11) + 1 - self.pc += number_of_times_to_increment_pc + self.pc += ((command_to_execute >> 6) & 0b11) + 1 self.trace() From 7d0eb69251c29fbd491347bf4c96228d97fd004f Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 8 Dec 2020 10:02:26 -0700 Subject: [PATCH 09/11] Finished implementing stack functionality --- ls8/cpu.py | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index bf0836eab..54d702490 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -24,25 +24,15 @@ def __init__(self): self.mar = 0 # #Memory Data Register, holds the value to write or the value just read self.mdr = 0 + # Points to the register that contains address of stack pointer + self.sp = 7 def load(self, file_name): """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 - # ] - program = [] + self.reg[self.sp] = len(self.ram) - 1 input_text = os.path.join(os.path.dirname(__file__), f"examples/{file_name}") @@ -67,6 +57,7 @@ def load(self, file_name): address += 1 + def alu(self, op, reg_a, reg_b): """ALU operations.""" @@ -106,10 +97,12 @@ def run(self): """Run the CPU.""" running = True - ldi = 0b10000010 - prn = 0b01000111 - hlt = 0b00000001 - mul = 0b10100010 + ldi = 0b10000010 + prn = 0b01000111 + hlt = 0b00000001 + mul = 0b10100010 + push = 0b01000101 + pop = 0b01000110 while running: # print(self.pc) @@ -120,21 +113,34 @@ def run(self): if command_to_execute == ldi: print("LDI executed") self.reg[op_a] = self.pc + 2 - self.pc += ((command_to_execute >> 6) & 0b11) + 1 + self.pc += (command_to_execute >> 6) + 1 elif command_to_execute == prn: print("Print executed") print(self.reg[op_a]) - self.pc += ((command_to_execute >> 6) & 0b11) + 1 + self.pc += (command_to_execute >> 6) + 1 elif command_to_execute == mul: print("Mult executed") print(op_a, op_b) self.reg[op_a] *= self.reg[op_b] - self.pc += ((command_to_execute >> 6) & 0b11) + 1 + self.pc += (command_to_execute >> 6) + 1 elif command_to_execute == hlt: print("Halt executed") running = False + elif command_to_execute == push: + self.reg[self.sp] -= 1 + register_to_get_value_in = self.ram[self.pc + 1] + value_in_register = self.reg[register_to_get_value_in] + self.ram[self.reg[self.sp]] = value_in_register + print(f"Pushing: {value_in_register}") + self.pc += (command_to_execute >> 6) + 1 + elif command_to_execute == pop: + register_to_pop_value_in = self.ram[self.pc + 1] + self.reg[register_to_pop_value_in] = self.ram[self.reg[self.sp]] + self.reg[self.sp] += 1 + print(f"Popping: {self.reg[register_to_pop_value_in]}") + self.pc += (command_to_execute >> 6) + 1 else: print(f"Unkown command: {command_to_execute}") - self.pc += ((command_to_execute >> 6) & 0b11) + 1 + self.pc += (command_to_execute >> 6) + 1 self.trace() From 8de068c590e9d0a1895b0b66110bf11854a533da Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 8 Dec 2020 21:25:38 -0700 Subject: [PATCH 10/11] load up stack.ls8 --- ls8/ls8.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ls8/ls8.py b/ls8/ls8.py index e426442bc..396c8d1db 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -6,5 +6,5 @@ from cpu import * cpu = CPU() -cpu.load("mult.ls8") #fileNameFromCommandLine +cpu.load("stack.ls8") #fileNameFromCommandLine cpu.run() From eb1d980dfdb21be82558cda0aeba6c5f5d42aff2 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 10 Dec 2020 20:02:18 -0700 Subject: [PATCH 11/11] implemented call and ret --- ls8/cpu.py | 11 +++++++++++ ls8/ls8.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index 54d702490..b4b0025f1 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -103,6 +103,8 @@ def run(self): mul = 0b10100010 push = 0b01000101 pop = 0b01000110 + call = 0b01010000 + ret = 0b00010001 while running: # print(self.pc) @@ -139,6 +141,15 @@ def run(self): self.reg[self.sp] += 1 print(f"Popping: {self.reg[register_to_pop_value_in]}") self.pc += (command_to_execute >> 6) + 1 + elif command_to_execute == call: + self.reg[self.sp] -= 1 + address_of_next_instruction = self.pc + 2 + self.ram[self.reg[self.sp]] = address_of_next_instruction + register_to_get_address_from = self.ram[self.pc + 1] + self.pc = self.reg[register_to_get_address_from] + elif command_to_execute == ret: + self.pc = self.ram[self.reg[self.sp]] + self.reg[self.sp] += 1 else: print(f"Unkown command: {command_to_execute}") self.pc += (command_to_execute >> 6) + 1 diff --git a/ls8/ls8.py b/ls8/ls8.py index 396c8d1db..61ebaaf2c 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -6,5 +6,5 @@ from cpu import * cpu = CPU() -cpu.load("stack.ls8") #fileNameFromCommandLine +cpu.load("call.ls8") #fileNameFromCommandLine cpu.run()