Skip to content
Open
Show file tree
Hide file tree
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
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,31 @@

### Day 1: Get `print8.ls8` running

- [ ] Inventory what is here
- [ ] Implement the `CPU` constructor
- [ ] Add RAM functions `ram_read()` and `ram_write()`
- [ ] Implement the core of `run()`
- [ ] Implement the `HLT` instruction handler
- [ ] Add the `LDI` instruction
- [ ] Add the `PRN` instruction
- [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
- [x] Implement the `CPU` constructor
- [x] Add RAM functions `ram_read()` and `ram_write()`
- [x] Implement the core of `run()`
- [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

- [ ] 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

- [ ] 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
Expand Down
136 changes: 113 additions & 23 deletions ls8/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,95 @@

import sys

HLT = 0b00000001
LDI = 0b10000010
PRN = 0b01000111
MUL = 0b10100010
PUSH = 0b01000101
POP = 0b01000110

SP = 7

class CPU:
"""Main CPU class."""

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

def load(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
#R3
#R4
#R5 reserved as the interrupt mask (IM)
#R6 reserved as the interrupt status (IS)
#R7 reserved as the stack pointer (SP)

#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
# Running
self.running = True

#`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, 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


# 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("#")
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

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")
Expand All @@ -62,4 +117,39 @@ def trace(self):

def run(self):
"""Run the CPU."""
pass
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)

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
elif instruction == PRN:
print(self.reg[operation_1])
self.pc += 2
elif instruction == HLT:
self.running = False
self.pc += 1
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)
pass

10 changes: 6 additions & 4 deletions ls8/ls8.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import sys
from cpu import *

cpu = CPU()

cpu.load()
cpu.run()
if len(sys.argv) != 2:
print("Wrong number of arguments passed in")
else:
cpu = CPU()
cpu.load(sys.argv[1])
cpu.run()