diff --git a/src/cpu.py b/src/meowbit/cpu.py similarity index 80% rename from src/cpu.py rename to src/meowbit/cpu.py index 25a3278..926bd0e 100644 --- a/src/cpu.py +++ b/src/meowbit/cpu.py @@ -1,13 +1,3 @@ -# from sys import exit -import time -import board -import displayio -# import vectorio -import terminalio # for font -from adafruit_display_text import label -import keypad -from digitalio import DigitalInOut, Direction, Pull - # TO USE KEYPAD TO MANIPULATE DATA: # # A button: run/halt @@ -18,24 +8,16 @@ from digitalio import DigitalInOut, Direction, Pull # Data entry: likewise. After you press the second digit, it will automatically go to the next address. +import time +import board +import displayio +import vectorio +import terminalio # for font +from adafruit_display_text import label +import keypad +from digitalio import DigitalInOut, Direction, Pull -# to list board features: print(board.__dir__) -btna = DigitalInOut(board.BTNA) -btna.direction = Direction.INPUT -btna.pull = Pull.UP # down doesn't work - -btnb = DigitalInOut(board.BTNB) -btnb.direction = Direction.INPUT -btnb.pull = Pull.UP # down doesn't work - -btnr = DigitalInOut(board.RIGHT) -btnr.direction = Direction.INPUT -btnr.pull = Pull.UP # down doesn't work - -km = keypad.KeyMatrix( - row_pins = (board.P0, board.P1, board.P2, board.P3), - column_pins = (board.P4, board.P6, board.P8, board.P9) ) class TwoDigitHexInput: @@ -55,13 +37,6 @@ class TwoDigitHexInput: print(self.digits) -group = displayio.Group() -board.DISPLAY.root_group = group -text_area = label.Label(terminalio.FONT, text="") -text_area.x = 10 -text_area.y = 10 -group.append(text_area) - class CPU: def __init__(self): self.running = False @@ -70,9 +45,6 @@ class CPU: self.flags = { 'C': False, 'Z': False, 'N': False, 'Eq': False } self.instruction = { 'opcode': False, 'operand': False } self.memory = False - self.monitorMode = 'addressEntry' # dataEntry - self.monitorAddressInput = TwoDigitHexInput() - self.monitorDataInput = TwoDigitHexInput() def load_memory(self, bytes): @@ -84,73 +56,6 @@ class CPU: def start(self): self.running = True - def print_screen(self): - for i in range(5): - for j in range(5): - # print(f"{i}-{j}", end=" ") - # print(self.memory[(i*5)+j], end=" ") - memory_index = (i * 5) + j - if self.memory[memory_index] > 0: - print("#", end=" ") - else: - print("_", end=" ") - print() - - def print_monitor(self): - text1 = "IP " + str(self.IP) + " DATA " + str(self.memory[self.IP]) # + "ACC " + str(self.acc) - print(text1) - text_area.text = text1 - - - - - def read_keys(self): - keypad_event = km.events.get() - if keypad_event and keypad_event.released: - print(keypad_event.key_number) - - if self.running: - if btna.value == False: - self.running = False - print("HALT PRESSED") - time.sleep(0.5) # lazy debounce - # km.events.clear() # don't track keypresses from during the run - if keypad_event and keypad_event.released: - self.memory[26] = keypad_event.key_number - print("mem26", self.memory[26]) - - - else: # halted - if btna.value == False: - self.running = True - print("\nSTARTING") - time.sleep(0.5) # lazy debounce - if btnb.value == False: - self.monitorMode = 'addressEntry' if self.monitorMode != 'addressEntry' else 'dataEntry' - print("\nENTERING", self.monitorMode, "MODE") - self.monitorDataInput.currentDigit = 0 - self.monitorAddressInput.currentDigit = 0 - time.sleep(0.5) # lazy debounce - if btnr.value == False: - print("\nSINGLE STEP FROM MONITOR ADDR") - # self.IP = self.monitorAddressInput.value - self.step() - time.sleep(0.5) # lazy debounce - if keypad_event and keypad_event.released: - if self.monitorMode == 'addressEntry': - self.monitorAddressInput.input(keypad_event.key_number) - self.IP = self.monitorAddressInput.value - print("MA", self.IP) - else: - self.monitorDataInput.input(keypad_event.key_number) - self.memory[self.IP] = self.monitorDataInput.value - print("MD", self.monitorDataInput.value) - if self.monitorDataInput.currentDigit == 0: # that was the second keypress, so go to the next addresss - self.IP = (self.IP + 1) % 256 - print("ADVANCING") - print("Acc", self.acc, "IP", self.IP, "Data", self.memory[self.IP], "\n") - - def step(self): if self.IP >= 256: self.IP = 0 @@ -159,29 +64,16 @@ class CPU: self.IP = self.IP+1 self.instruction['operand'] = self.memory[self.IP] self.IP = self.IP+1 + self.nums2mnems[self.instruction['opcode']](self, self.instruction['operand']) + print("instr:", self.instruction['opcode'], self.instruction['operand']) print("mnem:", self.nums2mnems[self.instruction['opcode']]) - self.nums2mnems[self.instruction['opcode']](self, self.instruction['operand']) print("acc:", self.acc) print("running:", self.running) print() # self.print_screen() print("byte 26 (keyboard):", self.memory[26]) print() - # if not self.running: - # exit() - - def run(self): - self.start() - t = time.time() - while (time.time() - t) < 30: - self.read_keys() - if self.running: - self.step() - self.print_monitor() - time.sleep(0.5) - print("timeout") - print(self.memory) def hlt(self, operand): self.running = False @@ -302,16 +194,134 @@ class CPU: 28: ccl, } -cpu = CPU() -prog = '04 FF 04 01 14 01 00 00' +### MEOWBIT-SPECIFIC STUFF ### + +# to list board features: print(board.__dir__) + +btna = DigitalInOut(board.BTNA) +btna.direction = Direction.INPUT +btna.pull = Pull.UP # down doesn't work + +btnb = DigitalInOut(board.BTNB) +btnb.direction = Direction.INPUT +btnb.pull = Pull.UP # down doesn't work + +btnr = DigitalInOut(board.RIGHT) +btnr.direction = Direction.INPUT +btnr.pull = Pull.UP # down doesn't work + +km = keypad.KeyMatrix( + row_pins = (board.P0, board.P1, board.P2, board.P3), + column_pins = (board.P4, board.P6, board.P8, board.P9) ) + +# This is global because that way you can update the text by just altering text_area.text +displayGroup = displayio.Group() +board.DISPLAY.root_group = displayGroup +text_area = label.Label(terminalio.FONT, text="") +text_area.x = 10 +text_area.y = 10 +displayGroup.append(text_area) + +palette = displayio.Palette(1) +palette[0] = 0xff00ff + + +class Monitor: + def __init__(self, cpu): + self.cpu = cpu + self.monitorMode = 'addressEntry' # or dataEntry + self.monitorAddressInput = TwoDigitHexInput() + self.monitorDataInput = TwoDigitHexInput() + + def handleKeys(self): + keypad_event = km.events.get() + keyPressed = True if (keypad_event and keypad_event.released) else False + key = keypad_event.key_number if keyPressed else False + + if self.cpu.running: + if btna.value == False: + print("HALT PRESSED") + self.cpu.running = False + time.sleep(0.5) # lazy debounce + # km.events.clear() # don't track keypresses from during the run + + if keyPressed: + self.cpu.memory[26] = key + + elif not self.cpu.running: + if btna.value == False: + self.cpu.running = True + print("\nSTARTING") + time.sleep(0.5) # lazy debounce + + if btnb.value == False: + self.monitorMode = 'addressEntry' if self.monitorMode != 'addressEntry' else 'dataEntry' + print("\nENTERING", self.monitorMode, "MODE") + self.monitorDataInput.currentDigit = 0 + self.monitorAddressInput.currentDigit = 0 + time.sleep(0.5) # lazy debounce + + if btnr.value == False: + print("\nSINGLE STEP FROM MONITOR ADDR") + # self.IP = self.monitorAddressInput.value + self.cpu.step() + time.sleep(0.5) # lazy debounce + + if keypad_event and keypad_event.released: + if self.monitorMode == 'addressEntry': + self.monitorAddressInput.input(keypad_event.key_number) + self.cpu.IP = self.monitorAddressInput.value + print("MA", self.IP) + + else: + self.monitorDataInput.input(keypad_event.key_number) + self.cpu.memory[self.IP] = self.monitorDataInput.value + print("MD", self.monitorDataInput.value) + if self.monitorDataInput.currentDigit == 0: # that was the second keypress, so go to the next addresss + self.cpu.IP = (self.cpu.IP + 1) % 256 + print("ADVANCING") + print("Acc", self.cpu.acc, "IP", self.cpu.IP, "Data", self.cpu.memory[self.cpu.IP], "\n") + + def printMonitor(self): + text = "IP " + str(self.cpu.IP) + "\tDATA " + str(self.cpu.memory[self.cpu.IP]) + "\tACC " + str(self.cpu.acc) + "\nRunning: " + str(self.cpu.running) + text_area.text = text + + + def printScreen(self): + for i in range(5): + for j in range(5): + memory_index = (i * 5) + j + if self.cpu.memory[memory_index] > 0: + print("#", end=" ") + circle = vectorio.Circle(pixel_shader=palette, radius=8, x=(10 + (j * 20)), y=(40 + (i * 20))) + displayGroup.append(circle) + else: + print("_", end=" ") + print() + + def run(self): + self.cpu.start() + t = time.time() + while (time.time() - t) < 30: + self.handleKeys() + if self.cpu.running: + self.cpu.step() + self.printMonitor() + # self.printScreen() + time.sleep(0.5) + print("timeout") + print(self.cpu.memory) + + +cpu = CPU() +monitor = Monitor(cpu) + +prog = '04 FF 04 01 14 01 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01' #prog = '00' program_bytes = bytearray.fromhex(prog.replace(" ", "")) # Add jmp at addr 254: program_with_jump = program_bytes + bytearray(254 - len(program_bytes)) + bytearray.fromhex('0600') cpu.load_memory(program_with_jump) -# cpu.start() -# cpu.step() - -cpu.run() +monitor.run()