cardiograph-computer/src/cpu.py

276 lines
8.2 KiB
Python

# 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 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
km = keypad.KeyMatrix(
row_pins = (board.P0, board.P1, board.P2, board.P3),
column_pins = (board.P4, board.P6, board.P8, board.P9) )
class CPU:
def __init__(self):
self.running = False
self.IP = 254
self.acc = 0
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 = "00"
self.monitorDataInput = "00"
self.monitorAddressDisplay = "00"
self.monitorDataDisplay = "00"
def load_memory(self, bytes):
self.memory = bytes + bytearray(256 - len(bytes))
print(type(self.memory))
print('mem 254', self.memory[254])
# print(self.memory)
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):
displayGroup = displayio.Group()
board.DISPLAY.root_group = displayGroup
text = self.monitorAddressDisplay + " " + self.monitorDataDisplay
text_area = label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 100
displayGroup.append(text_area)
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("STARTING")
time.sleep(0.5) # lazy debounce
if btnb.value == False:
self.monitorMode = 'addressEntry' if self.monitorMode != 'addressEntry' else 'dataEntry'
print(self.monitorMode)
time.sleep(0.5) # lazy debounce
if keypad_event and keypad_event.released:
new_digit_0x = hex(keypad_event.key_number)
new_digit = new_digit_0x[2:3]
if self.monitorMode == 'addressEntry':
cat = self.monitorAddressInput + new_digit
self.monitorAddressInput = cat[1:3]
print("MA", self.monitorAddressInput)
else:
cat = self.monitorDataInput + new_digit
self.monitorDataInput = cat[1:3]
print("MD", self.monitorDataInput)
print("Acc", self.acc, "Addr", self.monitorAddressInput, "Data", self.memory[int(self.monitorAddressInput)])
# TODO: update data with keypad
# then, automatically go to next address (?)
def step(self):
if self.IP >= 256:
self.IP = 0
print("IP:", self.IP)
self.instruction['opcode'] = self.memory[self.IP]
self.IP = self.IP+1
self.instruction['operand'] = self.memory[self.IP]
self.IP = self.IP+1
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()
#self.print_monitor()
#if self.running:
# self.step()
# time.time.sleep(0.5)
print("timeout")
def hlt(self, operand):
self.running = False
def nop(self, operand):
pass
def lda_lit(self, operand):
self.acc = operand
def lda_mem(self, operand):
self.acc = memory[operand]
def sta_lit(self, operand):
memory[operand] = self.acc
def sta_mem(self, operand):
memory[memory[operand]] = self.acc
def add_lit(self, operand):
self.acc = self.acc + operand
if self.acc > 255:
self.acc = self.acc % 256
self.flags['C'] = True
else:
self.flags['C'] = False
self.flags['Z'] = True if self.acc == 0 else False
self.flags['Eq'] = True if self.acc == operand else False
self.flags['N'] = True if self.acc > 127 else False
def add_mem(self, operand):
self.acc = self.acc + self.memory[operand]
if self.acc > 255:
self.acc = self.acc % 256
self.flags['C'] = True
else:
self.flags['C'] = False
self.flags['Z'] = True if self.acc == 0 else False
self.flags['Eq'] = True if self.acc == operand else False
self.flags['N'] = True if self.acc > 127 else False
def sub_lit(self, operand):
self.acc = self.acc - operand
if self.acc < 0:
self.acc = self.acc % 256
self.flags['C'] = True
else:
self.flags['C'] = False
self.flags['Z'] = True if self.acc == 0 else False
self.flags['Eq'] = True if self.acc == operand else False
self.flags['N'] = True if self.acc > 127 else False
def sub_mem(self, operand):
self.acc = self.acc - self.memory[operand]
if self.acc > 255:
self.acc = self.acc % 256
self.flags['C'] = True
else:
self.flags['C'] = False
self.flags['Z'] = True if self.acc == 0 else False
self.flags['Eq'] = True if self.acc == operand else False
self.flags['N'] = True if self.acc > 127 else False
def jmp_lit(self, operand):
self.IP = operand
def jmp_mem(self, operand):
self.IP = memory[operand]
def ske(self, operand):
if self.flags['Eq']:
self.IP += 2
def skz(self, operand):
if self.flags['Z']:
self.IP += 2
def skn(self, operand):
if self.flags['N']:
self.IP += 2
def skc(self, operand):
if self.flags['C']:
self.IP += 2
def cst(self, operand):
self.flags['C'] = True
def ccl(self, operand):
self.flags['C'] = False
nums2mnems = {
0: hlt,
1: nop,
2: lda_lit,
3: sta_lit,
4: add_lit,
5: sub_lit,
6: jmp_lit,
7: ske,
8: skz,
9: skn,
10: skc,
11: cst,
12: ccl,
16: hlt,
17: nop,
18: lda_mem,
19: sta_mem,
20: add_mem,
21: sub_mem,
22: jmp_mem,
23: ske,
24: skz,
25: skn,
26: skc,
27: cst,
28: ccl,
}
cpu = CPU()
prog = '04 FF 04 01 14 01 00 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()