Move meowbit CPU to its own dir + get screen going

This commit is contained in:
n loewen 2025-03-29 08:34:42 +00:00
parent 6bea93308c
commit 4c605e92c5
1 changed files with 134 additions and 124 deletions

View File

@ -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()