From ca56059fe678a29d53f800683e1b5ca910f0fb78 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 1 Dec 2020 20:35:57 -0800 Subject: [PATCH 01/11] Inventory of files --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 20c417457..ebb2bb771 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,10 @@ ### Day 1: Get `print8.ls8` running -- [ ] Inventory what is here +- [ X ] Inventory what is here + - cpu.py - Defines a CPU class this is where the program is ran and commands listed out + - ls8.py - Uses a CPU instance to run a program + - ls8-spec.md - A list of the program specs - [ ] Implement the `CPU` constructor - [ ] Add RAM functions `ram_read()` and `ram_write()` - [ ] Implement the core of `run()` From 172ec9e93850ad38b8523c809e63e4b0ed384b09 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 1 Dec 2020 20:54:52 -0800 Subject: [PATCH 02/11] Added the constructor to cpu.py --- README.md | 2 +- ls8/cpu.py | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebb2bb771..607051b3d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ### Day 1: Get `print8.ls8` running -- [ X ] Inventory what is here +- [x] Inventory what is here - cpu.py - Defines a CPU class this is where the program is ran and commands listed out - ls8.py - Uses a CPU instance to run a program - ls8-spec.md - A list of the program specs diff --git a/ls8/cpu.py b/ls8/cpu.py index 9a307496e..671fa7063 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -7,7 +7,31 @@ class CPU: def __init__(self): """Construct a new CPU.""" - pass + #Add list properties to the `CPU` class to hold 256 bytes of memory + self.ram = [0] * 256 + # and 8 general-purpose registers. + #R0 + #R1 + #R2 + #R3 + #R4 + #R5 reserved as the interrupt mask (IM) + #R6 reserved as the interrupt status (IS) + #R7 reserved as the stack pointer (SP) + self.reg = [0] * 8 + self.reg[7] = 0xF4 + + #Internal Registers + #PC: Program Counter, address of the currently executing instruction + self.pc = 0 + #IR: Instruction Register, contains a copy of the currently executing instruction + self.ir = 0 + #MAR: Memory Address Register, holds the memory address we're reading or writing + self.mar = 0 + #MDR: Memory Data Register, holds the value to write or the value just read + self.mdr = 0 + #FL: Flags, see below + self.fl = 0 def load(self): """Load a program into memory.""" From 8605070ce133b522de15a52a2754609340e079b0 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 1 Dec 2020 20:57:05 -0800 Subject: [PATCH 03/11] Added RAM Functions --- README.md | 2 +- ls8/cpu.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 607051b3d..8ebf61d56 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - cpu.py - Defines a CPU class this is where the program is ran and commands listed out - ls8.py - Uses a CPU instance to run a program - ls8-spec.md - A list of the program specs -- [ ] Implement the `CPU` constructor +- [x] Implement the `CPU` constructor - [ ] Add RAM functions `ram_read()` and `ram_write()` - [ ] Implement the core of `run()` - [ ] Implement the `HLT` instruction handler diff --git a/ls8/cpu.py b/ls8/cpu.py index 671fa7063..18c5a57e0 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -33,6 +33,14 @@ def __init__(self): #FL: Flags, see below self.fl = 0 + #`ram_read()` should accept the address to read and return the value stored there. + def ram_read(self, address): + return self.ram[address] + + #`ram_write()` should accept a value to write, and the address to write it to. + def ram_write(self, address, val): + self.ram[address] = val + def load(self): """Load a program into memory.""" From be453c2faaeb7366096adeb8bd68347c1ca88e9b Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 1 Dec 2020 21:22:32 -0800 Subject: [PATCH 04/11] Implemented run() --- README.md | 4 ++-- ls8/cpu.py | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8ebf61d56..b10eff0fe 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ - ls8.py - Uses a CPU instance to run a program - ls8-spec.md - A list of the program specs - [x] Implement the `CPU` constructor -- [ ] Add RAM functions `ram_read()` and `ram_write()` -- [ ] Implement the core of `run()` +- [x] Add RAM functions `ram_read()` and `ram_write()` +- [x] Implement the core of `run()` - [ ] Implement the `HLT` instruction handler - [ ] Add the `LDI` instruction - [ ] Add the `PRN` instruction diff --git a/ls8/cpu.py b/ls8/cpu.py index 18c5a57e0..8dc1053e3 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -10,6 +10,8 @@ def __init__(self): #Add list properties to the `CPU` class to hold 256 bytes of memory self.ram = [0] * 256 # and 8 general-purpose registers. + self.reg = [0] * 8 + self.reg[7] = 0xF4 #R0 #R1 #R2 @@ -18,8 +20,6 @@ def __init__(self): #R5 reserved as the interrupt mask (IM) #R6 reserved as the interrupt status (IS) #R7 reserved as the stack pointer (SP) - self.reg = [0] * 8 - self.reg[7] = 0xF4 #Internal Registers #PC: Program Counter, address of the currently executing instruction @@ -32,6 +32,8 @@ def __init__(self): self.mdr = 0 #FL: Flags, see below self.fl = 0 + # Running + self.running = True #`ram_read()` should accept the address to read and return the value stored there. def ram_read(self, address): @@ -40,7 +42,7 @@ def ram_read(self, address): #`ram_write()` should accept a value to write, and the address to write it to. def ram_write(self, address, val): self.ram[address] = val - + def load(self): """Load a program into memory.""" @@ -94,4 +96,21 @@ def trace(self): def run(self): """Run the CPU.""" - pass + while self.running: + command_to_execute = self.ram_read(self.pc) + + if command_to_execute == 0b10000010: # LDI + operation_1 = self.ram_read(self.pc + 1) + operation_2 = self.ram_read(self.pc + 2) + + self.reg[operation_1] = operation_2 + self.pc += 3 + if command_to_execute == 0b01000111: # PRN + operation_1 = self.ram_read(self.pc + 1) + print(self.reg[operation_1]) + self.pc += 2 + if command_to_execute == 0b00000001: # HLT + self.running = False + self.pc += 1 + + From fab53280275ae03e81e77e27e003bcc34f67dcde Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 1 Dec 2020 21:25:24 -0800 Subject: [PATCH 05/11] Day 1 MVP Complete --- README.md | 6 +++--- ls8/cpu.py | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b10eff0fe..a736cff12 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ - [x] Implement the `CPU` constructor - [x] Add RAM functions `ram_read()` and `ram_write()` - [x] Implement the core of `run()` -- [ ] Implement the `HLT` instruction handler -- [ ] Add the `LDI` instruction -- [ ] Add the `PRN` instruction +- [x] Implement the `HLT` instruction handler +- [x] Add the `LDI` instruction +- [x] Add the `PRN` instruction ### Day 2: Add the ability to load files dynamically, get `mult.ls8` running diff --git a/ls8/cpu.py b/ls8/cpu.py index 8dc1053e3..b5accca47 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -2,6 +2,10 @@ import sys +HLT = 0b00000001 +LDI = 0b10000010 +PRN = 0b01000111 + class CPU: """Main CPU class.""" @@ -99,17 +103,17 @@ def run(self): while self.running: command_to_execute = self.ram_read(self.pc) - if command_to_execute == 0b10000010: # LDI + if command_to_execute == LDI: operation_1 = self.ram_read(self.pc + 1) operation_2 = self.ram_read(self.pc + 2) self.reg[operation_1] = operation_2 self.pc += 3 - if command_to_execute == 0b01000111: # PRN + if command_to_execute == PRN: operation_1 = self.ram_read(self.pc + 1) print(self.reg[operation_1]) self.pc += 2 - if command_to_execute == 0b00000001: # HLT + if command_to_execute == HLT: self.running = False self.pc += 1 From dac57877206cb05355fb182b13ed98d0d20c8fef Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Thu, 3 Dec 2020 19:07:58 -0800 Subject: [PATCH 06/11] Lecture Refactoring --- ls8/cpu.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index b5accca47..f676f7ea3 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -102,19 +102,22 @@ def run(self): """Run the CPU.""" while self.running: command_to_execute = self.ram_read(self.pc) + operation_1 = self.ram_read(self.pc + 1) + operation_2 = self.ram_read(self.pc + 2) - if command_to_execute == LDI: - operation_1 = self.ram_read(self.pc + 1) - operation_2 = self.ram_read(self.pc + 2) - - self.reg[operation_1] = operation_2 - self.pc += 3 - if command_to_execute == PRN: - operation_1 = self.ram_read(self.pc + 1) - print(self.reg[operation_1]) - self.pc += 2 - if command_to_execute == HLT: - self.running = False - self.pc += 1 + self.execute_instruction(command_to_execute, operation_1, operation_2) + def execute_instruction(self, instruction, operation_1, operation_2): + if instruction == LDI: + self.reg[operation_1] = operation_2 + self.pc += 3 + elif instruction == PRN: + print(self.reg[operation_1]) + self.pc += 2 + elif instruction == HLT: + self.running = False + self.pc += 1 + else: + print("I don't know what to do.") + pass From bbfef65430a5553d9b59ac7fc5f5394ba2526523 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 8 Dec 2020 18:52:46 -0800 Subject: [PATCH 07/11] Un-hardcode the machine code --- ls8/cpu.py | 30 ++++++++++++------------------ ls8/ls8.py | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index f676f7ea3..af0b0eb74 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -47,28 +47,22 @@ def ram_read(self, address): def ram_write(self, address, val): self.ram[address] = val - def load(self): + def load(self, filename): """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 - - + with open(filename) as fp: + for line in fp: + comment_split = line.split("#") + num = comment_split[0].strip() + # ignore blanks + if num == "" : + continue + val = int(num, 2) + self.ram_write(val, address) + address += 1 + def alu(self, op, reg_a, reg_b): """ALU operations.""" diff --git a/ls8/ls8.py b/ls8/ls8.py index 74128d36b..f6af1337f 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -5,7 +5,19 @@ import sys from cpu import * -cpu = CPU() +def main(argv): + cpu = CPU() + # cpu.load() -cpu.load() -cpu.run() \ No newline at end of file + if len(argv) != 2: + print(f"usage: {argv[0]} filename", file=sys.stderr) + return 1 + + cpu.load(argv[1]) + + cpu.run() + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv)) \ No newline at end of file From 22441d5554cf1ef56724cea9816cc4be3b945b68 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Tue, 8 Dec 2020 18:55:38 -0800 Subject: [PATCH 08/11] Implement a Multiply instruction --- README.md | 6 +++--- ls8/cpu.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a736cff12..56c73b248 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ ### Day 2: Add the ability to load files dynamically, get `mult.ls8` running -- [ ] Un-hardcode the machine code -- [ ] Implement the `load()` function to load an `.ls8` file given the filename +- [x] Un-hardcode the machine code +- [x] Implement the `load()` function to load an `.ls8` file given the filename passed in as an argument -- [ ] Implement a Multiply instruction (run `mult.ls8`) +- [x] Implement a Multiply instruction (run `mult.ls8`) ### Day 3: Stack diff --git a/ls8/cpu.py b/ls8/cpu.py index af0b0eb74..dbe9c96f2 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -5,6 +5,7 @@ HLT = 0b00000001 LDI = 0b10000010 PRN = 0b01000111 +MULT = 0b10100010 class CPU: """Main CPU class.""" @@ -111,6 +112,9 @@ def execute_instruction(self, instruction, operation_1, operation_2): elif instruction == HLT: self.running = False self.pc += 1 + elif instruction == MULT: + self.reg[operation_1] *= self.reg[operation_2] + self.pc += 3 else: print("I don't know what to do.") pass From caf23a18d8a355de78b1676fbad3f0ba979d308e Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Wed, 9 Dec 2020 17:20:22 -0800 Subject: [PATCH 09/11] moved commands to ALU --- ls8/cpu.py | 46 +++++++++++++++++++++++++++++++++------------- ls8/ls8.py | 18 ++++-------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/ls8/cpu.py b/ls8/cpu.py index dbe9c96f2..c72a151d3 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -5,7 +5,7 @@ HLT = 0b00000001 LDI = 0b10000010 PRN = 0b01000111 -MULT = 0b10100010 +MUL = 0b10100010 class CPU: """Main CPU class.""" @@ -53,22 +53,40 @@ def load(self, filename): address = 0 - with open(filename) as fp: - for line in fp: + # 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 + + # open the file + with open(filename) as my_file: + # go through each line to parse and get + # the instruction + for line in my_file: + # try and get the instruction/operand in the line comment_split = line.split("#") - num = comment_split[0].strip() - # ignore blanks - if num == "" : + maybe_binary_number = comment_split[0] + try: + x = int(maybe_binary_number, 2) + #print("{:08b}: {:d}".format(x, x)) + self.ram_write(x, address) + address += 1 + except: continue - val = int(num, 2) - self.ram_write(val, address) - address += 1 def alu(self, op, reg_a, reg_b): """ALU operations.""" - if op == "ADD": - self.reg[reg_a] += self.reg[reg_b] + if op == MUL: + self.reg[reg_a] *= self.reg[reg_b] #elif op == "SUB": etc else: raise Exception("Unsupported ALU operation") @@ -103,6 +121,7 @@ def run(self): self.execute_instruction(command_to_execute, operation_1, operation_2) def execute_instruction(self, instruction, operation_1, operation_2): + print(instruction) if instruction == LDI: self.reg[operation_1] = operation_2 self.pc += 3 @@ -112,10 +131,11 @@ def execute_instruction(self, instruction, operation_1, operation_2): elif instruction == HLT: self.running = False self.pc += 1 - elif instruction == MULT: - self.reg[operation_1] *= self.reg[operation_2] + elif instruction == MUL: + self.alu(instruction, operation_1, operation_2) self.pc += 3 else: print("I don't know what to do.") + sys.exit(1) pass diff --git a/ls8/ls8.py b/ls8/ls8.py index f6af1337f..cbdff7a30 100755 --- a/ls8/ls8.py +++ b/ls8/ls8.py @@ -5,19 +5,9 @@ import sys from cpu import * -def main(argv): +if len(sys.argv) != 2: + print("Wrong number of arguments passed in") +else: cpu = CPU() - # cpu.load() - - if len(argv) != 2: - print(f"usage: {argv[0]} filename", file=sys.stderr) - return 1 - - cpu.load(argv[1]) - + cpu.load(sys.argv[1]) cpu.run() - - return 0 - -if __name__ == "__main__": - sys.exit(main(sys.argv)) \ No newline at end of file From af6d56f0cca4a7580a80873fe151222cc7c2b164 Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Wed, 9 Dec 2020 18:50:33 -0800 Subject: [PATCH 10/11] Implement the CALL and RET instructions --- ls8/cpu.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ls8/cpu.py b/ls8/cpu.py index c72a151d3..d9db56bab 100644 --- a/ls8/cpu.py +++ b/ls8/cpu.py @@ -6,6 +6,10 @@ LDI = 0b10000010 PRN = 0b01000111 MUL = 0b10100010 +PUSH = 0b01000101 +POP = 0b01000110 + +SP = 7 class CPU: """Main CPU class.""" @@ -134,6 +138,16 @@ def execute_instruction(self, instruction, operation_1, operation_2): elif instruction == MUL: self.alu(instruction, operation_1, operation_2) self.pc += 3 + elif instruction == PUSH: + # decrement the stack pointer + self.reg[SP] -= 1 + # store the operaind in the stack + self.ram_write(self.reg[operation_1], self.reg[SP]) + self.pc += 2 + elif instruction == POP: + self.reg[operation_1] = self.ram_read(self.reg[SP]) + self.reg[SP] += 1 + self.pc += 2 else: print("I don't know what to do.") sys.exit(1) From ad21839dd1154e317de704ffee255c89a0a7475b Mon Sep 17 00:00:00 2001 From: Claudia Maciel Date: Wed, 9 Dec 2020 18:51:35 -0800 Subject: [PATCH 11/11] Implement the System Stack --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 56c73b248..b381380be 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ ### Day 3: Stack -- [ ] Implement the System Stack and be able to run the `stack.ls8` program +- [x] Implement the System Stack and be able to run the `stack.ls8` program ### Day 4: Get `call.ls8` running -- [ ] Implement the CALL and RET instructions +- [x] Implement the CALL and RET instructions - [ ] Implement Subroutine Calls and be able to run the `call.ls8` program ### Stretch