Start work on pi pico version of CPU simulator
This commit is contained in:
parent
6f164294e5
commit
e82a429d5e
|
|
@ -0,0 +1,298 @@
|
|||
# TO USE KEYPAD TO MANIPULATE DATA:
|
||||
#
|
||||
# A button: run/halt
|
||||
# B button: when halted, toggles address/data entry
|
||||
# Right button: when halted, single-steps
|
||||
#
|
||||
# Address entry: press the two digits for the address. It is entered immediately (there's no "enter" key)
|
||||
# Data entry: likewise. After you press the second digit, it will automatically go to the next address.
|
||||
|
||||
|
||||
import time
|
||||
import board
|
||||
import keypad
|
||||
import digitalio
|
||||
from tm1637_display import TM1637Display
|
||||
|
||||
|
||||
class TwoDigitHexInput:
|
||||
def __init__(self):
|
||||
self.digits = [0x0, 0x0]
|
||||
self.currentDigit = 0
|
||||
self.value = 0
|
||||
|
||||
def input(self, d):
|
||||
self.digits[self.currentDigit] = d
|
||||
self.value = (self.digits[0] * 16) + self.digits[1]
|
||||
print("INPUT", self.digits)
|
||||
self.currentDigit = 0 if self.currentDigit else 1
|
||||
|
||||
def clear(self):
|
||||
self.__init__()
|
||||
print(self.digits)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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 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
|
||||
self.nums2mnems[self.instruction['opcode']](self, self.instruction['operand'])
|
||||
|
||||
print("instr:", self.instruction['opcode'], self.instruction['operand'])
|
||||
print("mnem:", self.nums2mnems[self.instruction['opcode']])
|
||||
print("acc:", self.acc)
|
||||
print("running:", self.running)
|
||||
print()
|
||||
# self.print_screen()
|
||||
print("byte 26 (keyboard):", self.memory[26])
|
||||
print()
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
|
||||
### PI PICO SPECIFIC STUFF ###
|
||||
|
||||
# to list board features: print(dir(board))
|
||||
|
||||
display_1 = TM1637Display(board.GP0, board.GP1, length=4)
|
||||
display_2 = TM1637Display(board.GP2, board.GP3, length=4)
|
||||
|
||||
keymatrix = keypad.KeyMatrix(
|
||||
row_pins = (board.GP5, board.GP6, board.GP7, board.GP8),
|
||||
column_pins = (board.GP9, board.GP10, board.GP11, board.GP12, board.GP13) )
|
||||
|
||||
keymap = {
|
||||
15:"0", 16:"1", 17:"2", 18:"3", 19:"runhalt",
|
||||
10:"4", 11:"5", 12:"6", 13:"7", 14:"step",
|
||||
5:"8", 6:"9", 7:"A", 8:"B", 9:"addrdata",
|
||||
0:"C", 1:"D", 2:"E", 3:"F", 4:"NA" }
|
||||
|
||||
numericKeys = [ "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F" ]
|
||||
|
||||
def toHex(n):
|
||||
return "%0.2X" % n
|
||||
|
||||
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 = keymatrix.events.get()
|
||||
keyPressed = True if (keypad_event and keypad_event.released ) else False
|
||||
key = keymap[keypad_event.key_number] if keyPressed else False
|
||||
numericKeyPressed = True if (keyPressed and (key in numericKeys)) else False
|
||||
|
||||
if self.cpu.running:
|
||||
if key == "runhalt":
|
||||
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 numericKeyPressed:
|
||||
self.cpu.memory[26] = int(key, 16)
|
||||
|
||||
elif not self.cpu.running:
|
||||
if key == "runhalt":
|
||||
self.cpu.running = True
|
||||
print("\nSTARTING")
|
||||
time.sleep(0.5) # lazy debounce
|
||||
|
||||
if key == "addrdata":
|
||||
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 key == "step":
|
||||
print("\nSINGLE STEP FROM MONITOR ADDR")
|
||||
# self.IP = self.monitorAddressInput.value
|
||||
self.cpu.step()
|
||||
time.sleep(0.5) # lazy debounce
|
||||
|
||||
if numericKeyPressed:
|
||||
if self.monitorMode == 'addressEntry':
|
||||
self.monitorAddressInput.input(int(key, 16))
|
||||
self.cpu.IP = self.monitorAddressInput.value
|
||||
print("MA", self.cpu.IP)
|
||||
|
||||
else:
|
||||
self.monitorDataInput.input(int(key, 16))
|
||||
self.cpu.memory[self.cpu.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 run(self):
|
||||
self.cpu.start()
|
||||
t = time.time()
|
||||
while (time.time() - t) < 120:
|
||||
self.handleKeys()
|
||||
display_1.print(toHex(self.monitorAddressInput.value) + toHex(self.monitorDataInput.value))
|
||||
display_2.print(toHex(self.cpu.IP) + toHex(self.cpu.acc))
|
||||
if self.cpu.running:
|
||||
self.cpu.step()
|
||||
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'
|
||||
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)
|
||||
|
||||
monitor.run()
|
||||
Loading…
Reference in New Issue