diff --git a/python/cpu.py b/python/cpu.py new file mode 100644 index 0000000..35b4063 --- /dev/null +++ b/python/cpu.py @@ -0,0 +1,164 @@ +import time + +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(self.memory) + + def start(self): + self.running = True + + def step(self): + if self.IP >= 255: # TODO CHECK + self.IP = 0 + print("IP:", toHex(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:", toHex(self.instruction['opcode']), toHex(self.instruction['operand'])) + print("mnem:", self.nums2mnems[self.instruction['opcode']]) + print("acc:", self.acc, "N:", self.flags['N']) + 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 + 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 lda_mem(self, operand): + self.acc = self.memory[operand] + 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 sta_lit(self, operand): + self.memory[operand] = self.acc + + def sta_mem(self, operand): + self.memory[self.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 = self.memory[operand] + + def ske(self, operand): # FIXME +# if self.flags['Eq']: +# self.IP += 2 + if self.acc == operand: + 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, # x0 + 1: nop, # x1 + 2: lda_lit, # 02 + 3: sta_lit, # 03 + 4: add_lit, # 04 + 5: sub_lit, # 05 + 6: jmp_lit, # 06 + 7: ske, # x7 + 8: skz, # x8 + 9: skn, # x9 + 10: skc, # A + 11: cst, # B + 12: ccl, # C + 16: hlt, # + 17: nop, # + 18: lda_mem, # 12 + 19: sta_mem, # 13 + 20: add_mem, # 14 + 21: sub_mem, # 15 + 22: jmp_mem, # 16 + 23: ske, + 24: skz, + 25: skn, + 26: skc, + 27: cst, + 28: ccl, + } diff --git a/python/simulator-scrap.py b/python/simulator-scrap.py new file mode 100644 index 0000000..0a4473b --- /dev/null +++ b/python/simulator-scrap.py @@ -0,0 +1,124 @@ +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() + + # In data entry mode, when a full byte is keyed in, + # the next keypress advances to the next address and continues entering data there. + # This variable tracks whether it's time to do that or not. + self.advanceDataEntryNextPress = False + + 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 == "addr": + self.monitorMode = 'addressEntry' + print("\nENTERING", self.monitorMode, "MODE") + self.monitorAddressInput.currentDigit = 0 + time.sleep(0.5) # lazy debounce + if key == "data": + self.monitorMode = 'dataEntry' + print("\nENTERING", self.monitorMode, "MODE") + self.monitorDataInput.clear() + self.advanceDataEntryNextPress = False + 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) + + if self.monitorMode == 'dataEntry': + if self.advanceDataEntryNextPress: + print("ADVANCING") + self.cpu.IP = (self.cpu.IP + 1) % 256 + # self.monitorDataInput.clear() # reset .currentDigit + self.monitorDataInput.set(self.cpu.memory[self.cpu.IP]) + self.advanceDataEntryNextPress = False + 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 next keypress is for the next address + self.advanceDataEntryNextPress = True + + print("Acc", self.cpu.acc, "IP", self.cpu.IP, "Data", self.cpu.memory[self.cpu.IP], "\n") + + + def displayScreen(self): + for x in range(8): + for y in range(8): + matrix[x, y] = self.cpu.memory[x + (8*y)] + + + + def run(self): + #self.cpu.start() + t = time.time() + while (time.time() - t) < 120: # TODO: add a time delta or sth maybe so this doesn't just burn cycles + self.handleKeys() + display_1.print(toHex(self.cpu.IP) + toHex(self.cpu.memory[self.cpu.IP])) + # display_1.print(toHex(self.monitorAddressInput.value) + toHex(self.cpu.memory[self.cpu.IP])) + # display_2.print(toHex(self.cpu.IP) + toHex(self.cpu.acc)) + display_2.print(toHex(self.cpu.acc)) + self.displayScreen() + if self.cpu.running: + self.cpu.step() + # time.sleep(0.5) # TODO ? + print("timeout") + print(self.cpu.memory) + + +cpu = CPU() +monitor = Monitor(cpu) + +# preamble = '00 ' * 64 +# prog = preamble + '02 01 13 f0 12 f0 04 02 03 f0 12 f0 05 41 08 00 06 40 00 00' # STRIPES +# offset = 64 +# prog = preamble + '02 01 13 f0 12 f0 04 02 03 f0 05 08 09 00 04 09 03 f0 07 41 06' + toHex(offset) + '00 00' +#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') # jump to addr 00 +# program_with_jump = program_bytes + bytearray(254 - len(program_bytes)) + bytearray.fromhex('0640') # jump to addr 0x40 (dec 64) + +with open('test-multiply2.bin', 'rb') as file: + program_bytes = bytearray(file.read()) + +cpu.load_memory(program_bytes) + +monitor.run() diff --git a/python/simulator.py b/python/simulator.py new file mode 100644 index 0000000..1f3fbd9 --- /dev/null +++ b/python/simulator.py @@ -0,0 +1,5 @@ +import cpu + +c = cpu.CPU() + +print(c)