from argparse import ArgumentParser from os.path import exists as f_exists from os import remove as f_remove # Adressmodi IMP = 0 # Implied: z.B. BRK, INX ACC = 1 # Accumulator: z.B. ASL A IMM = 2 # Immediate: z.B. LDA #$A7 ZP = 3 # Zeropage: z.B. STA $60 ZPX = 4 # Zeropage X: z.B. LDA $60,x ABS = 5 # Absolute: z.B. LDA $C000 ABSX = 6 # Absolute X: z.B. LDA $6000,x ABSY = 7 # Absolute Y: z.B. STA $8000,y INDY = 8 # Indirect Y: z.B. LDA ($61),Y IND = 9 # Indirect: z.B. JMP ($8000) REL = 10 # Relative: z.B. BNE def hexfmt4(val): """ 4bit-Zahl mit hex(val) umwandeln und das Ergebnis wie folgt anpassen: '0x5' -> '5' """ if val > 15: raise SystemExit("hexfmt4 overflow: %d" % val) s = hex(val) s = s[2:] return s.upper() def hexfmt8(val): """ 8bit-Zahl hexadezimal ausgeben """ return "%s%s" % (hexfmt4(val >> 4), hexfmt4(val & 0xf)) def hexfmt16(high, low): """ 16bit-Zahl hexadezimal ausgeben """ return "%s%s" % (hexfmt8(high), hexfmt8(low)) def binfmt4(val): """ 4bit-Zahl mit bin(val) umwandeln und das Ergebnis wie folgt anpassen: '0b1' -> '0001' """ if val > 15: raise SystemExit("binfmt4 overflow: %d" % val) s = bin(val) s = s[2:] x = len(s) # linksbuendig mit null auffuellen while x < 4: s = '0' + s x += 1 return s def binfmt8(val): """ 8bit-Zahl binaer ausgeben """ return "%s %s" % (binfmt4(val >> 4), binfmt4(val & 0xf)) def binfmt16(high, low): """ 16bit-Zahl binaer ausgeben """ return "%s %s" % (binfmt8(high), binfmt8(low)) class Opcode: def __init__(self, opc, txt, amode, cyc, chg_pc, func): self.opc = opc self.txt = txt self.amode = amode self.cyc = cyc self.changepc = chg_pc self.func = func # Befehlslaenge if (amode == IMP) or (amode == ACC): self.bytes_ = 1 elif amode in [IMM, ZP, ZPX, INDY, REL]: self.bytes_ = 2 elif amode in [ABS, ABSX, ABSY, IND]: self.bytes_ = 3 def to_str(self, arg_txt=''): amode_txt = "" if self.amode == ACC: amode_txt = "A" elif self.amode == IMM: amode_txt = "#%s" % arg_txt elif self.amode in [ZP, ABS, REL]: amode_txt = arg_txt elif self.amode in [ZPX, ABSX]: amode_txt = "%s,X" % arg_txt elif self.amode == ABSY: amode_txt = "%s,Y" % arg_txt elif self.amode == INDY: amode_txt = "(%s),Y" % arg_txt elif self.amode == IND: amode_txt = "(%s)" % arg_txt return "%s %s" % (self.txt, amode_txt) class CPU6502: def __init__(self): # Flags self.flag_c = False self.flag_n = False self.flag_z = False self.flag_i = True # disable Interrupt self.flag_v = False # Stackpointer self.sp = 0xff # Programmzaehler self.pc = 0 # Register self.reg_a = 0 self.reg_x = 0 self.reg_y = 0 # 64KB Speicher self.mem = bytearray(65536) # Stackadresse self.stack = 0x100 # Taktzyklen self.cycles = 0 # Start und Ende des Programms self.start = 0 self.end = 0 # Symboltabelle # - Adresse als Schluessel, Label als Inhalt self.addresses = {} # - Label als Schluessel, Adresse als Inhalt self.labels = {} # Datei, die einen IRQ signalisiert self.irq_file = "/tmp/irq" # Datei, die einen Abbruch signalisiert self.brk_file = "/tmp/brk" # Alternative Routinen fuer JSR-Aufrufe # in der Form { adr: func } self.jsr_alt = {} # BEFEHLE ANLEGEN self.opcodes = { # opc: opc txt mod cyc pc func 0x00: Opcode(0x00, 'BRK', IMP, 7, True, self.brk), 0x05: Opcode(0x05, 'ORA', ZP, 3, False, self.ora_zp), 0x06: Opcode(0x06, 'ASL', ZP, 5, False, self.asl_zp), 0x08: Opcode(0x08, 'PHP', IMP, 3, False, self.php), 0x09: Opcode(0x09, 'ORA', IMM, 2, False, self.ora_imm), 0x0a: Opcode(0x0a, 'ASL', ACC, 2, False, self.asl), 0x0d: Opcode(0x0d, 'ORA', ABS, 4, False, self.ora_abs), 0x10: Opcode(0x10, 'BPL', REL, 3, True, self.bpl), 0x16: Opcode(0x16, 'ASL', ZPX, 6, False, self.asl_zp_x), 0x18: Opcode(0x18, 'CLC', IMP, 2, False, self.clc), 0x20: Opcode(0x20, 'JSR', ABS, 6, True, self.jsr_abs), 0x24: Opcode(0x24, 'BIT', ZP, 3, False, self.bit_zp), 0x25: Opcode(0x25, 'AND', ZP, 3, False, self.and_zp), 0x26: Opcode(0x26, 'ROL', ZP, 5, False, self.rol_zp), 0x28: Opcode(0x28, 'PLP', IMP, 4, False, self.plp), 0x29: Opcode(0x29, 'AND', IMM, 2, False, self.and_imm), 0x2a: Opcode(0x2a, 'ROL', ACC, 2, False, self.rol), 0x2c: Opcode(0x2c, 'BIT', ABS, 4, False, self.bit_abs), 0x2d: Opcode(0x2d, 'AND', ABS, 4, False, self.and_abs), 0x30: Opcode(0x30, 'BMI', REL, 3, True, self.bmi), 0x38: Opcode(0x38, 'SEC', IMP, 2, False, self.sec), 0x40: Opcode(0x40, 'RTI', IMP, 6, True, self.rti), 0x45: Opcode(0x45, 'EOR', ZP, 3, False, self.eor_zp), 0x46: Opcode(0x46, 'LSR', ZP, 5, False, self.lsr_zp), 0x48: Opcode(0x48, 'PHA', IMP, 3, False, self.pha), 0x49: Opcode(0x49, 'EOR', IMM, 2, False, self.eor_imm), 0x4a: Opcode(0x4a, 'LSR', ACC, 2, False, self.lsr), 0x4c: Opcode(0x4c, 'JMP', ABS, 3, True, self.jmp_abs), 0x4d: Opcode(0x4d, 'EOR', ABS, 4, False, self.eor_abs), 0x50: Opcode(0x50, 'BVC', REL, 3, True, self.bvc), 0x56: Opcode(0x56, 'LSR', ZPX, 6, False, self.lsr_zp_x), 0x58: Opcode(0x58, 'CLI', IMP, 2, False, self.cli), 0x60: Opcode(0x60, 'RTS', IMP, 6, True, self.rts), 0x65: Opcode(0x65, 'ADC', ZP, 3, False, self.adc_zp), 0x66: Opcode(0x66, 'ROR', ZP, 5, False, self.ror_zp), 0x68: Opcode(0x68, 'PLA', IMP, 4, False, self.pla), 0x69: Opcode(0x69, 'ADC', IMM, 2, False, self.adc_imm), 0x6a: Opcode(0x6a, 'ROR', ACC, 2, False, self.ror), 0x6c: Opcode(0x6c, 'JMP', IND, 3, True, self.jmp_ind), 0x6d: Opcode(0x6d, 'ADC', ABS, 4, False, self.adc_abs), 0x70: Opcode(0x70, 'BVS', REL, 3, True, self.bvs), 0x75: Opcode(0x75, 'ADC', ZPX, 4, False, self.adc_zp_x), 0x78: Opcode(0x78, 'SEI', IMP, 2, False, self.sei), 0x79: Opcode(0x79, 'ADC', ABSY,4, False, self.adc_abs_y), 0x7d: Opcode(0x7d, 'ADC', ABSX,4, False, self.adc_abs_x), 0x84: Opcode(0x84, 'STY', ZP, 3, False, self.sty_zp), 0x85: Opcode(0x85, 'STA', ZP, 3, False, self.sta_zp), 0x86: Opcode(0x86, 'STX', ZP, 3, False, self.stx_zp), 0x88: Opcode(0x88, 'DEY', IMP, 2, False, self.dey), 0x8a: Opcode(0x8a, 'TXA', IMP, 2, False, self.txa), 0x8c: Opcode(0x8c, 'STY', ABS, 4, False, self.sty_abs), 0x8d: Opcode(0x8d, 'STA', ABS, 4, False, self.sta_abs), 0x8e: Opcode(0x8e, 'STX', ABS, 4, False, self.stx_abs), 0x90: Opcode(0x90, 'BCC', REL, 3, True, self.bcc), 0x91: Opcode(0x91, 'STA', INDY,6, False, self.sta_ind_y), 0x94: Opcode(0x94, 'STY', ZPX, 4, False, self.sty_zp_x), 0x95: Opcode(0x95, 'STA', ZPX, 4, False, self.sta_zp_x), 0x98: Opcode(0x98, 'TYA', IMP, 2, False, self.tya), 0x99: Opcode(0x99, 'STA', ABSY,5, False, self.sta_abs_y), 0x9d: Opcode(0x9d, 'STA', ABSX,5, False, self.sta_abs_x), 0xa0: Opcode(0xa0, 'LDY', IMM, 2, False, self.ldy_imm), 0xa2: Opcode(0xa2, 'LDX', IMM, 2, False, self.ldx_imm), 0xa4: Opcode(0xa4, 'LDY', ZP, 3, False, self.ldy_zp), 0xa5: Opcode(0xa5, 'LDA', ZP, 3, False, self.lda_zp), 0xa6: Opcode(0xa6, 'LDX', ZP, 3, False, self.ldx_zp), 0xa8: Opcode(0xa8, 'TAY', IMP, 2, False, self.tay), 0xa9: Opcode(0xa9, 'LDA', IMM, 2, False, self.lda_imm), 0xaa: Opcode(0xaa, 'TAX', IMP, 2, False, self.tax), 0xac: Opcode(0xac, 'LDY', ABS, 4, False, self.ldy_abs), 0xad: Opcode(0xad, 'LDA', ABS, 4, False, self.lda_abs), 0xae: Opcode(0xae, 'LDX', ABS, 4, False, self.ldx_abs), 0xb0: Opcode(0xb0, 'BCS', REL, 3, True, self.bcs), 0xb1: Opcode(0xb1, 'LDA', INDY,5, False, self.lda_ind_y), 0xb4: Opcode(0xb4, 'LDY', ZPX, 4, False, self.ldy_zp_x), 0xb5: Opcode(0xb5, 'LDA', ZPX, 4, False, self.lda_zp_x), 0xb8: Opcode(0xb8, 'CLV', IMP, 2, False, self.clv), 0xb9: Opcode(0xb9, 'LDA', ABSY,4, False, self.lda_abs_y), 0xbd: Opcode(0xbd, 'LDA', ABSX,4, False, self.lda_abs_x), 0xc0: Opcode(0xc0, 'CPY', IMM, 2, False, self.cpy_imm), 0xc4: Opcode(0xc4, 'CPY', ZP, 3, False, self.cpy_zp), 0xc5: Opcode(0xc5, 'CMP', ZP, 3, False, self.cmp_zp), 0xc6: Opcode(0xc6, 'DEC', ZP, 5, False, self.dec_zp), 0xc8: Opcode(0xc8, 'INY', IMP, 2, False, self.iny), 0xc9: Opcode(0xc9, 'CMP', IMM, 2, False, self.cmp_imm), 0xca: Opcode(0xca, 'DEX', IMP, 2, False, self.dex), 0xcc: Opcode(0xcc, 'CPY', ABS, 4, False, self.cpy_abs), 0xcd: Opcode(0xcd, 'CMP', ABS, 4, False, self.cmp_abs), 0xce: Opcode(0xce, 'DEC', ABS, 6, False, self.dec_abs), 0xd0: Opcode(0xd0, 'BNE', REL, 3, True, self.bne), 0xd6: Opcode(0xd6, 'DEC', ZPX, 6, False, self.dec_zp_x), 0xd9: Opcode(0xd9, 'CMP', ABSY,4, False, self.cmp_abs_y), 0xdd: Opcode(0xdd, 'CMP', ABSX,4, False, self.cmp_abs_x), 0xde: Opcode(0xde, 'DEC', ABSX,7, False, self.dec_abs_x), 0xe0: Opcode(0xe0, 'CPX', IMM, 2, False, self.cpx_imm), 0xe4: Opcode(0xe4, 'CPX', ZP, 3, False, self.cpx_zp), 0xe5: Opcode(0xe5, 'SBC', ZP, 3, False, self.sbc_zp), 0xe6: Opcode(0xe6, 'INC', ZP, 5, False, self.inc_zp), 0xe8: Opcode(0xe8, 'INX', IMP, 2, False, self.inx), 0xe9: Opcode(0xe9, 'SBC', IMM, 2, False, self.sbc_imm), 0xea: Opcode(0xea, 'NOP', IMP, 2, False, self.nop), 0xec: Opcode(0xec, 'CPX', ABS, 4, False, self.cpx_abs), 0xed: Opcode(0xed, 'SBC', ABS, 4, False, self.sbc_abs), 0xee: Opcode(0xee, 'INC', ABS, 6, False, self.inc_abs), 0xf0: Opcode(0xf0, 'BEQ', REL, 3, True, self.beq), 0xf6: Opcode(0xf6, 'INC', ZPX, 6, False, self.inc_zp_x), 0xf9: Opcode(0xf9, 'SBC', ABSY,4, False, self.sbc_abs_y), 0xfd: Opcode(0xfd, 'SBC', ABSX,4, False, self.sbc_abs_x), 0xfe: Opcode(0xfe, 'INC', ABSX,7, False, self.inc_abs_x), } # Zugriff auf die Befehle ueber Assembler anstatt Maschinencode self.commands = { 'adc #': self.opcodes[0x69], 'adc aa': self.opcodes[0x65], 'adc aa,x': self.opcodes[0x75], 'adc aaaa': self.opcodes[0x6d], 'adc aaaa,x': self.opcodes[0x7d], 'adc aaaa,y': self.opcodes[0x79], 'and #': self.opcodes[0x29], 'and aa': self.opcodes[0x25], 'and aaaa': self.opcodes[0x2d], 'asl A': self.opcodes[0x0a], 'asl aa': self.opcodes[0x06], 'asl aa,x': self.opcodes[0x16], 'bcc aa': self.opcodes[0x90], 'bcs aa': self.opcodes[0xb0], 'beq aa': self.opcodes[0xf0], 'bit aa': self.opcodes[0x24], 'bit aaaa': self.opcodes[0x2c], 'bmi aa': self.opcodes[0x30], 'bne aa': self.opcodes[0xd0], 'bpl aa': self.opcodes[0x10], 'brk': self.opcodes[0x00], 'bvc aa': self.opcodes[0x50], 'bvs aa': self.opcodes[0x70], 'clc': self.opcodes[0x18], 'cli': self.opcodes[0x58], 'clv': self.opcodes[0xb8], 'cmp #': self.opcodes[0xc9], 'cmp aa': self.opcodes[0xc5], 'cmp aaaa': self.opcodes[0xcd], 'cmp aaaa,x': self.opcodes[0xdd], 'cmp aaaa,y': self.opcodes[0xd9], 'cpx #': self.opcodes[0xe0], 'cpx aa': self.opcodes[0xe4], 'cpx aaaa': self.opcodes[0xec], 'cpy #': self.opcodes[0xc0], 'cpy aa': self.opcodes[0xc4], 'cpy aaaa': self.opcodes[0xcc], 'dec aa': self.opcodes[0xc6], 'dec aa.x': self.opcodes[0xd6], 'dec aaaa': self.opcodes[0xce], 'dec aaaa,x': self.opcodes[0xde], 'dex': self.opcodes[0xca], 'dey': self.opcodes[0x88], 'eor #': self.opcodes[0x49], 'eor aa': self.opcodes[0x45], 'eor aaaa': self.opcodes[0x4d], 'inc aa': self.opcodes[0xe6], 'inc aa,x': self.opcodes[0xf6], 'inc aaaa': self.opcodes[0xee], 'inc aaaa,x': self.opcodes[0xfe], 'inx': self.opcodes[0xe8], 'iny': self.opcodes[0xc8], 'jmp aaaa': self.opcodes[0x4c], 'jmp (aaaa)': self.opcodes[0x6c], 'jsr aaaa': self.opcodes[0x20], 'lda #': self.opcodes[0xa9], 'lda aa': self.opcodes[0xa5], 'lda aa,x': self.opcodes[0xb5], 'lda aaaa': self.opcodes[0xad], 'lda aaaa,x': self.opcodes[0xbd], 'lda aaaa,y': self.opcodes[0xb9], 'lda (aa),y': self.opcodes[0xb1], 'ldx #': self.opcodes[0xa2], 'ldx aa': self.opcodes[0xa6], 'ldx aaaa': self.opcodes[0xae], 'ldy #': self.opcodes[0xa0], 'ldy aa': self.opcodes[0xa4], 'ldy aa,x': self.opcodes[0xb4], 'ldy aaaa': self.opcodes[0xac], 'lsr A': self.opcodes[0x4a], 'lsr aa': self.opcodes[0x46], 'lsr aa,x': self.opcodes[0x56], 'nop': self.opcodes[0xea], 'ora #': self.opcodes[0x09], 'ora aa': self.opcodes[0x05], 'ora aaaa': self.opcodes[0x0d], 'pha': self.opcodes[0x48], 'pla': self.opcodes[0x68], 'php': self.opcodes[0x08], 'plp': self.opcodes[0x28], 'rol A': self.opcodes[0x2a], 'rol aa': self.opcodes[0x26], 'ror A': self.opcodes[0x6a], 'ror aa': self.opcodes[0x66], 'rti': self.opcodes[0x40], 'rts': self.opcodes[0x60], 'sbc #': self.opcodes[0xe9], 'sbc aa': self.opcodes[0xe5], 'sbc aaaa': self.opcodes[0xed], 'sbc aaaa,x': self.opcodes[0xfd], 'sbc aaaa,y': self.opcodes[0xf9], 'sei': self.opcodes[0x78], 'sta aa': self.opcodes[0x85], 'sta aa,x': self.opcodes[0x95], 'sta aaaa': self.opcodes[0x8d], 'sta aaaa,x': self.opcodes[0x9d], 'sta aaaa,y': self.opcodes[0x99], 'sta (aa),y': self.opcodes[0x91], 'stx aa': self.opcodes[0x86], 'stx aaaa': self.opcodes[0x8e], 'sty aa': self.opcodes[0x84], 'sty aa,x': self.opcodes[0x94], 'sty aaaa': self.opcodes[0x8c], 'sec': self.opcodes[0x38], 'tax': self.opcodes[0xaa], 'tay': self.opcodes[0xa8], 'txa': self.opcodes[0x8a], 'tya': self.opcodes[0x98], } # Trennlinie im Disassembler-Listing self.sep_lines = [0x00, 0x4c, 0x60] # BRK, JMP, RTS # Name und Beschreibung fuer Programmoptionen self.progname = 'cpu6502.py' self.progdesc = '6502 CPU Emulator' def resetcyc(self): self.cycles = 0 def addcmd(self, txt, argl=0, argh=0): cmd = self.commands[txt] self.mem[self.pc] = cmd.opc if cmd.amode in [IMM, ZP, ZPX, INDY, ABS, ABSX, ABSY, IND, REL]: self.mem[self.pc+1] = argl if cmd.amode in [ABS, ABSX, ABSY, IND]: self.mem[self.pc+2] = argh self.pc += cmd.bytes_ def addcmd2(self, txt, arg=0): cmd = self.commands[txt] self.mem[self.pc] = cmd.opc if cmd.amode in [IMM, ZP, ZPX, INDY, ABS, ABSX, ABSY, IND, REL]: self.mem[self.pc+1] = arg & 0xff if cmd.amode in [ABS, ABSX, ABSY, IND]: self.mem[self.pc+2] = arg >> 8 self.pc += cmd.bytes_ def inc_cyc(self, cmds): """ Taktzyklen manuell mit der uebergebenen Liste von Befehlen erhoehen """ for cmd in cmds: self.cycles += self.commands[cmd].cyc # HILFSROUTINEN ZUM SETZEN DER FLAGS def _a_set_nz_flags(self): """ Setzt Neg- und Zero-Flags fuer A """ self.flag_z = (self.reg_a == 0) self.flag_n = (self.reg_a > 127) def _x_set_nz_flags(self): """ Setzt Neg- und Zero-Flags fuer X """ self.flag_z = (self.reg_x == 0) self.flag_n = (self.reg_x > 127) def _y_set_nz_flags(self): """ Setzt Neg- und Zero-Flags fuer Y """ self.flag_z = (self.reg_y == 0) self.flag_n = (self.reg_y > 127) def _mem_set_nz_flags(self, adr): """ Setzt Neg- und Zero-Flags anhand einer Speicherstelle """ self.flag_z = (self.mem[adr] == 0) self.flag_n = (self.mem[adr] > 127) def _comp_set_flags(self, reg, comp): """ Setzt die Flags fuer die Vergleichsroutinen Der Parameter reg enthhaelt den Wert des Registers, comp den Vergleichswert (direkt bzw. aus dem Speicher). """ self.flag_z = (reg == comp) self.flag_c = (reg >= comp) self.flag_n = (reg < comp) # HILFSROUTINE FUeR VERZWEIGUNGEN def _branch_rel(self): """ Fuehrt einen relativen Sprung aus """ branch = self.mem[self.pc] # Zweier-Komplement bei Rueckwaerts-Spruengen # in negative Zahl umwandeln if branch > 127: branch = branch ^ 255 # xor branch += 1 branch = - branch # Sprung gilt ab der Adresse des Folgebefehls # (daher noch +1) self.pc = self.pc + 1 + branch # HILFSROUTINEN FUeR ADDITION UND SUBSTRAKTION def _add(self, val): s = self.reg_a + val if self.flag_c: s += 1 # Test auf Ueberlauf self.flag_c = (s != s & 255) self.reg_a = s & 255 self._a_set_nz_flags() def _sub(self, val): self.reg_a = self.reg_a - val # Wenn das Carray-Flag vor der Substraktion nicht # gesetzt wurde, wird noch der Wert 1 abgezogen if not self.flag_c: self.reg_a -= 1 # Carry-Flag setzen (bei positivem Resultat) self.flag_c = (self.reg_a >= 0) # Bei negativem Resultat Zweier-Komplement bilden if self.reg_a < 0: self.reg_a = abs(self.reg_a) self.reg_a = self.reg_a ^ 255 # xor self.reg_a += 1 self._a_set_nz_flags() # HILFSROUTINEN FUeR ERHOEHUNG UND VERRINGERUNG def _inc(self, adr): if self.mem[adr] == 255: self.mem[adr] = 0 else: self.mem[adr] += 1 self._mem_set_nz_flags(adr) def _dec(self, adr): if self.mem[adr] == 0: self.mem[adr] = 255 else: self.mem[adr] -= 1 self._mem_set_nz_flags(adr) # HILFSROUTINE FUeR BIT-TEST def _bit(self, val): self.flag_n = (val & 128 > 0) self.flag_v = (val & 64 > 0) self.flag_z = (val & self.reg_a == 0) # HILFSROUTINEN ZUM SETZEN STACKPOINTER def _dec_sp(self): self.sp -= 1 # Test auf Ueberlauf if self.sp < 0: self.sp = 0xff def _inc_sp(self): self.sp += 1 # Test auf Ueberlauf if self.sp > 0xff: self.sp = 0 def _exec_irq(self): # Programmzaehler auf dem Stack sichern self.mem[self.stack + self.sp] = self.pc >> 8 self._dec_sp() self.mem[self.stack + self.sp] = self.pc & 0xff self._dec_sp() # Prozessorstatus auf dem Stack sichern self.php() # Programmzaehler setzen self.pc = self.mem[0xffff] << 8 | self.mem[0xfffe] # Disable interrupt self.sei() def _check_irq(self): if f_exists(self.irq_file): self._exec_irq() def _clear_irq(self): if f_exists(self.irq_file): f_remove(self.irq_file) # BEFEHLE def adc_imm(self): """ ADC # """ self._add(self.mem[self.pc]) def adc_zp(self): """ ADC aa """ adr = self.mem[self.pc] self._add(self.mem[adr]) def adc_zp_x(self): """ ADC aa,x """ adr = self.mem[self.pc] + self.reg_x self._add(self.mem[adr]) def adc_abs(self): """ ADC aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._add(self.mem[adr]) def adc_abs_x(self): """ ADC aaaa,x """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._add(self.mem[adr + self.reg_x]) def adc_abs_y(self): """ ADC aaaa,y """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._add(self.mem[adr + self.reg_y]) def and_imm(self): """ AND # """ self.reg_a = self.reg_a & self.mem[self.pc] self._a_set_nz_flags() def and_zp(self): """ AND aa """ adr = self.mem[self.pc] self.reg_a = self.reg_a & self.mem[adr] self._a_set_nz_flags() def and_abs(self): """ AND aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.reg_a & self.mem[adr] self._a_set_nz_flags() def asl(self): """ ASL A """ self.reg_a = self.reg_a << 1 # Test auf Ueberlauf self.flag_c = (self.reg_a != self.reg_a & 255) self.reg_a = self.reg_a & 255 self._a_set_nz_flags() def asl_zp(self): """ ASL aa """ adr = self.mem[self.pc] res = self.mem[adr] << 1 # Test auf Ueberlauf self.flag_c = (res != res & 255) self.mem[adr] = res & 255 self._mem_set_nz_flags(adr) def asl_zp_x(self): """ ASL aa,x """ adr = self.mem[self.pc] + self.reg_x res = self.mem[adr] << 1 # Test auf Ueberlauf self.flag_c = (res != res & 255) self.mem[adr] = res & 255 self._mem_set_nz_flags(adr) def bcc(self): """ BCC aa """ if self.flag_c == 0: self._branch_rel() else: self.pc += 1 def bcs(self): """ BCS aa """ if self.flag_c == 1: self._branch_rel() else: self.pc += 1 def beq(self): """ BEQ aa """ if self.flag_z == 1: self._branch_rel() else: self.pc += 1 def bit_zp(self): """ BIT aa """ adr = self.mem[self.pc] self._bit(self.mem[adr]) def bit_abs(self): """ BIT aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._bit(self.mem[adr]) def bmi(self): """ BMI aa """ if self.flag_n == 1: self._branch_rel() else: self.pc += 1 def bne(self): """ BNE aa """ if self.flag_z == 0: self._branch_rel() else: self.pc += 1 def bpl(self): """ BPL aa """ if self.flag_n == 0: self._branch_rel() else: self.pc += 1 def brk(self): """ BRK """ #self.pc = 0 def bvc(self): """ BVC aa """ if self.flag_v == 0: self._branch_rel() else: self.pc += 1 def bvs(self): """ BVS aa """ if self.flag_v == 1: self._branch_rel() else: self.pc += 1 def clc(self): """ CLC """ self.flag_c = False def cli(self): """ CLI """ self.flag_i = False def clv(self): """ CLV """ self.flag_v = False def cmp_imm(self): """ CMP # """ self._comp_set_flags(self.reg_a, self.mem[self.pc]) def cmp_zp(self): """ CMP aa """ adr = self.mem[self.pc] self._comp_set_flags(self.reg_a, self.mem[adr]) def cmp_abs(self): """ CMP aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._comp_set_flags(self.reg_a, self.mem[adr]) def cmp_abs_x(self): """ CMP aaaa,x """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._comp_set_flags(self.reg_a, self.mem[adr + self.reg_x]) def cmp_abs_y(self): """ CMP aaaa,y """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._comp_set_flags(self.reg_a, self.mem[adr + self.reg_y]) def cpx_imm(self): """ CPX # """ self._comp_set_flags(self.reg_x, self.mem[self.pc]) def cpx_zp(self): """ CPX aa """ adr = self.mem[self.pc] self._comp_set_flags(self.reg_x, self.mem[adr]) def cpx_abs(self): """ CPX aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._comp_set_flags(self.reg_x, self.mem[adr]) def cpy_imm(self): """ CPY # """ self._comp_set_flags(self.reg_y, self.mem[self.pc]) def cpy_zp(self): """ CPY aa """ adr = self.mem[self.pc] self._comp_set_flags(self.reg_y, self.mem[adr]) def cpy_abs(self): """ CPY aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._comp_set_flags(self.reg_y, self.mem[adr]) def dec_zp(self): """ DEC aa """ adr = self.mem[self.pc] self._dec(adr) def dec_zp_x(self): """ DEC aa,x """ adr = self.mem[self.pc] + self.reg_x self._dec(adr) def dec_abs(self): """ DEC aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._dec(adr) def dec_abs_x(self): """ DEC aaaa,x """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._dec(adr + self.reg_x) def dex(self): """ DEX """ self.reg_x -= 1 if self.reg_x < 0: self.reg_x = 255 self._x_set_nz_flags() def dey(self): """ DEY """ self.reg_y -= 1 if self.reg_y < 0: self.reg_y = 255 self._y_set_nz_flags() def eor_imm(self): """ EOR # """ self.reg_a = self.reg_a ^ self.mem[self.pc] self._a_set_nz_flags() def eor_zp(self): """ EOR aa """ adr = self.mem[self.pc] self.reg_a = self.reg_a ^ self.mem[adr] self._a_set_nz_flags() def eor_abs(self): """ EOR aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.reg_a ^ self.mem[adr] self._a_set_nz_flags() def inc_zp(self): """ INC aa """ adr = self.mem[self.pc] self._inc(adr) def inc_zp_x(self): """ INC aa,x """ adr = self.mem[self.pc] + self.reg_x self._inc(adr) def inc_abs(self): """ INC aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._inc(adr) def inc_abs_x(self): """ INC aaaa,x """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._inc(adr + self.reg_x) def inx(self): """ INX """ self.reg_x += 1 if self.reg_x > 255: self.reg_x = 0 self._x_set_nz_flags() def iny(self): """ INY """ self.reg_y += 1 if self.reg_y > 255: self.reg_y = 0 self._y_set_nz_flags() def jmp_abs(self): """ JMP aaaa """ self.pc = self.mem[self.pc+1] << 8 | self.mem[self.pc] def jmp_ind(self): """ JMP (aaaa) """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.pc = self.mem[adr+1] << 8 | self.mem[adr] def jsr_abs(self): """ JSR aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] if not adr in self.jsr_alt: # Programmzaehler+2 als Ruecksprungadresse auf den # Stack legen (PC wurde schon um eins erhoeht, # daher nur noch +1) self.mem[self.stack + self.sp] = (self.pc+1) >> 8 self._dec_sp() self.mem[self.stack + self.sp] = (self.pc+1) & 0xff self._dec_sp() self.pc = adr else: # Alternativen Handler aufrufen (Programmzaehler wurde # schon um eins erhoeht, daher nur noch +2) self.jsr_alt[adr]() self.pc += 2 def lda_imm(self): """ LDA # """ self.reg_a = self.mem[self.pc] self._a_set_nz_flags() def lda_zp(self): """ LDA aa """ adr = self.mem[self.pc] self.reg_a = self.mem[adr] self._a_set_nz_flags() def lda_zp_x(self): """ LDA aa,X """ adr = self.mem[self.pc] self.reg_a = self.mem[adr + self.reg_x] self._a_set_nz_flags() def lda_abs(self): """ LDA aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.mem[adr] self._a_set_nz_flags() def lda_abs_x(self): """ LDA aaaa,X """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.mem[adr + self.reg_x] self._a_set_nz_flags() def lda_abs_y(self): """ LDA aaaa,Y """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.mem[adr + self.reg_y] self._a_set_nz_flags() def lda_ind_y(self): """ LDA (aa),Y """ ptr = self.mem[self.pc] adr = (self.mem[ptr+1] << 8 | self.mem[ptr]) + self.reg_y self.reg_a = self.mem[adr] self._a_set_nz_flags() def ldx_imm(self): """ LDX # """ self.reg_x = self.mem[self.pc] self._x_set_nz_flags() def ldx_zp(self): """ LDX aa """ adr = self.mem[self.pc] self.reg_x = self.mem[adr] self._x_set_nz_flags() def ldx_abs(self): """ LDX aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_x = self.mem[adr] self._x_set_nz_flags() def ldy_imm(self): """ LDY # """ self.reg_y = self.mem[self.pc] self._y_set_nz_flags() def ldy_zp(self): """ LDY aa """ adr = self.mem[self.pc] self.reg_y = self.mem[adr] self._y_set_nz_flags() def ldy_zp_x(self): """ LDY aa,X """ adr = self.mem[self.pc] self.reg_y = self.mem[adr + self.reg_x] self._y_set_nz_flags() def ldy_abs(self): """ LDY aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_y = self.mem[adr] self._y_set_nz_flags() def lsr(self): """ LSR A """ self.reg_a = self.reg_a & 255 # Test auf vorhersehbaren Ueberlauf (Bit 0 gesetzt?) self.flag_c = (self.reg_a != self.reg_a & 254) self.reg_a = self.reg_a >> 1 self._a_set_nz_flags() def lsr_zp(self): """ LSR aa """ adr = self.mem[self.pc] val = self.mem[adr] # Test auf vorhersehbaren Ueberlauf (Bit 0 gesetzt?) self.flag_c = (val != val & 254) self.mem[adr] = val >> 1 self._mem_set_nz_flags(adr) def lsr_zp_x(self): """ LSR aa,x """ adr = self.mem[self.pc] + self.reg_x val = self.mem[adr] # Test auf vorhersehbaren Ueberlauf (Bit 0 gesetzt?) self.flag_c = (val != val & 254) self.mem[adr] = val >> 1 self._mem_set_nz_flags(adr) def nop(self): """ NOP """ pass def ora_imm(self): """ ORA # """ self.reg_a = self.reg_a | self.mem[self.pc] self._a_set_nz_flags() def ora_zp(self): """ ORA aa """ adr = self.mem[self.pc] self.reg_a = self.reg_a | self.mem[adr] self._a_set_nz_flags() def ora_abs(self): """ ORA aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.reg_a = self.reg_a | self.mem[adr] self._a_set_nz_flags() def pha(self): """ PHA """ self.mem[self.stack + self.sp] = self.reg_a self._dec_sp() def pla(self): """ PLA """ self._inc_sp() self.reg_a = self.mem[self.stack + self.sp] self._a_set_nz_flags() def php(self): """ PHP """ preg = 0 if self.flag_n: preg = preg | 0x80 if self.flag_i: preg = preg | 0x04 if self.flag_z: preg = preg | 0x02 if self.flag_c: preg = preg | 0x01 self.mem[self.stack + self.sp] = preg self._dec_sp() def plp(self): """ PLP """ self._inc_sp() preg = self.mem[self.stack + self.sp] self.flag_n = (preg & 0x80 > 0) self.flag_i = (preg & 0x04 > 0) self.flag_z = (preg & 0x02 > 0) self.flag_c = (preg & 0x01 > 0) def rol(self): """ ROL A """ self.reg_a = self.reg_a << 1 # Carry-Flag ins Bit 0 uebertragen self.reg_a = self.reg_a | self.flag_c # Test auf Ueberlauf self.flag_c = (self.reg_a != self.reg_a & 255) self.reg_a = self.reg_a & 255 self._a_set_nz_flags() def rol_zp(self): """ ROL aa """ adr = self.mem[self.pc] res = self.mem[adr] << 1 # Carry-Flag ins Bit 0 uebertragen res = res | self.flag_c # Test auf Ueberlauf self.flag_c = (res != res & 255) self.mem[adr] = res & 255 self._mem_set_nz_flags(adr) def ror(self): """ ROR A """ self.reg_a = self.reg_a & 255 # Carry-Flag merken (fuer unten) cs = self.flag_c # Test auf vorhersehbaren Ueberlauf (Bit 0 gesetzt?) self.flag_c = (self.reg_a != self.reg_a & 254) self.reg_a = self.reg_a >> 1 # Carry, falls es gesetzt war, ins Bit 7 uebertragen if cs: self.reg_a = self.reg_a | 128 self._a_set_nz_flags() def ror_zp(self): """ ROR aa """ adr = self.mem[self.pc] val = self.mem[adr] # Carry-Flag merken (fuer unten) cs = self.flag_c # Test auf vorhersehbaren Ueberlauf (Bit 0 gesetzt?) self.flag_c = (val != val & 254) self.mem[adr] = val >> 1 # Carry, falls es gesetzt war, ins Bit 7 uebertragen if cs: self.mem[adr] = self.mem[adr] | 128 self._mem_set_nz_flags(adr) def rti(self): """ RTI """ self.plp() self._inc_sp() pcl = self.mem[self.stack + self.sp] self._inc_sp() pch = self.mem[self.stack + self.sp] self.pc = pch << 8 | pcl #IRQ-Quelle bereinigen self._clear_irq() def rts(self): """ RTS """ self._inc_sp() pcl = self.mem[self.stack + self.sp] self._inc_sp() pch = self.mem[self.stack + self.sp] self.pc = pch << 8 | pcl self.pc += 1 def sbc_imm(self): """ SBC # """ self._sub(self.mem[self.pc]) def sbc_zp(self): """ SBC aa """ adr = self.mem[self.pc] self._sub(self.mem[adr]) def sbc_abs(self): """ SBC aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._sub(self.mem[adr]) def sbc_abs_x(self): """ SBC aaaa,x """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._sub(self.mem[adr + self.reg_x]) def sbc_abs_y(self): """ SBC aaaa,y """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self._sub(self.mem[adr + self.reg_y]) def sec(self): """ SEC """ self.flag_c = True def sei(self): """ SEI """ self.flag_i = True def sta_zp(self): """ STA zp """ adr = self.mem[self.pc] self.mem[adr] = self.reg_a def sta_zp_x(self): """ STA aa,X """ adr = self.mem[self.pc] self.mem[adr + self.reg_x] = self.reg_a def sta_abs(self): """ STA aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.mem[adr] = self.reg_a def sta_abs_x(self): """ STA aaaa,X """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.mem[adr + self.reg_x] = self.reg_a def sta_abs_y(self): """ STA aaaa,Y """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.mem[adr + self.reg_y] = self.reg_a def sta_ind_y(self): """ STA (aa),y """ ptr = self.mem[self.pc] adr = (self.mem[ptr+1] << 8 | self.mem[ptr]) + self.reg_y self.mem[adr] = self.reg_a def stx_zp(self): """ STX aa """ adr = self.mem[self.pc] self.mem[adr] = self.reg_x def stx_abs(self): """ STX aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.mem[adr] = self.reg_x def sty_zp(self): """ STY aa """ adr = self.mem[self.pc] self.mem[adr] = self.reg_y def sty_zp_x(self): """ STY aa,X """ adr = self.mem[self.pc] self.mem[adr + self.reg_x] = self.reg_y def sty_abs(self): """ STY aaaa """ adr = self.mem[self.pc+1] << 8 | self.mem[self.pc] self.mem[adr] = self.reg_y def tax(self): """ TAX """ self.reg_x = self.reg_a self._x_set_nz_flags() def tay(self): """ TAY """ self.reg_y = self.reg_a self._y_set_nz_flags() def txa(self): """ TXA """ self.reg_a = self.reg_x self._a_set_nz_flags() def tya(self): """ TYA """ self.reg_a = self.reg_y self._a_set_nz_flags() # HAUPTROUTINEN def load(self, filename): """ Laedt das Programm an die angegebene Adresse, die in den ersten beiden Bytes steht (cbm format), und setzt den Start und das Ende fuer das Programm """ f = open(filename, 'rb') data = f.read() f.close() # Startadresse (die ersten zwei Bytes) laden slow = data[0] shigh = data[1] self.start = shigh << 8 | slow # restliches Programm laden idx = self.start for b in data[2:]: self.mem[idx] = b idx += 1 self.end = idx - 1 def loadsym(self, filename): f = open(filename, 'r') data = f.readlines() f.close() for line in data: parts = line.split(chr(9)) # tab sep # [TAB]vscroll[TAB]= $c1b0[TAB]; ? # -> ['', 'vscroll', '= $c1b0', '; ?'] adr = int(parts[2][3:],16) label = parts[1] self.addresses[adr] = label self.labels[label] = adr def disass(self): """ Gibt das geladene Programm in Assembler aus """ adr = self.start while adr <= self.end: if (len(self.addresses) > 0) and (adr in self.addresses): print("%s:" % self.addresses[adr]) try: cmd = self.opcodes[self.mem[adr]] except KeyError: cmd = Opcode(None, '???', IMP, 0, False, None) argl = self.mem[adr+1] argh = self.mem[adr+2] print(hexfmt16(adr >> 8, adr & 0xff), end='') print(" ", end='') arg_txt = "" if cmd.amode in [IMM, ZP, ZPX, INDY]: arg_txt = hexfmt8(argl) elif cmd.amode in [ABS, ABSX, ABSY, IND]: arg_txt = "%s%s" % (hexfmt8(argh), hexfmt8(argl)) elif cmd.amode == REL: # Zweier-Komplement bei Rueckwaerts-Spruengen # in negative Zahl umwandeln if argl > 127: branch = argl ^ 255 # xor branch += 1 dest = adr + 2 - branch else: dest = adr + 2 + argl arg_txt = hexfmt16(dest >> 8, dest & 0xff) print(cmd.to_str(arg_txt), end='') if (len(self.addresses) > 0) and (cmd.amode in [ZP, ZPX, ABS, ABSX, ABSY, IND]): # (cmd.opc in [0x20, 0x4c]) try: if cmd.amode in [ZP, ZPX]: label = self.addresses[argl] else: label = self.addresses[argh << 8 | argl] print(" ; %s" % label, end='') except KeyError: pass print("") if cmd.opc in self.sep_lines: print("------------------") adr += cmd.bytes_ def run(self): """ Startet das geladene Programm """ self.pc = self.start while True: opc = self.mem[self.pc] try: cmd = self.opcodes[opc] except KeyError: print("Illegal opcode: %s" % hexfmt8(opc)) self.registers() raise SystemExit() # Programmzaehler auf das erste Argument setzen self.pc += 1 cmd.func() # Programmzaehler weiter erhoehen, wenn es kein # Sprungbefehl ist if not cmd.changepc: self.pc += cmd.bytes_ - 1 # -1 wegen der Erhoehung oben self.cycles += self.opcodes[opc].cyc # Bei BRK-Befehl abbrechen if opc == 0: break # Bei Existenz einer Stop-Datei abbrechen if f_exists(self.brk_file): f_remove(self.brk_file) break # Interrupt if not self.flag_i: self._check_irq() # Debug def registers(self): """ Druckt die Register und die Flags aus """ print("") print(" PC AC XR YR SP NV-BDIZC") print("------------------------------") print("%s %s %s %s %s %d%d---%d%d%d" % ( hexfmt16(self.pc >> 8, self.pc & 0xff), hexfmt8(self.reg_a), hexfmt8(self.reg_x), hexfmt8(self.reg_y), hexfmt8(self.sp), self.flag_n, self.flag_v, self.flag_i, self.flag_z, self.flag_c )) def mempage(self, page): """ Druckt die angegebene Speicherseite aus """ print("") print("Page %s:" % hexfmt8(page)) print("--------") for i in range(16): print("%s: " % hexfmt8(i << 4), end='') for j in range(16): p = (i << 4) + j print("%s " % hexfmt8(self.mem[(page << 8) + p]), end='') print("") print("") def cmdtable(self): """ Druckt eine Tabelle aller implementierten Befehle sortiert nach den Opcodes aus (wie im Datenblatt von WDC). Aus Platzgruenden wird die Tabelle in der Mitte geteilt und die beiden Haelften nacheinander ausgedruckt. """ # linke und rechte Haelfte for page in range(2): # Spaltentitel (unteren 4 Bits) mit 0-7 bzw. 8-F print(" ", end = '') offset = page * 8 for i in range(8): print("|%s" % hexfmt4(i+offset).center(7), end='') print("") # 16 Zeilen fuer die oberen 4 Bits for row in range(16): # Trennlinie print("--", end = '') print("+-------" * 8) # Zeilentitel 00-F0 print("%sx" % hexfmt4(row), end='') # Die Befehle werden in zwei Zeilen gedruckt # (1. Zeile mit Befehlsnamen und 2. Zeile mit # Addressierungsart). Daher werden die Texte # zuerst in zwei Listen gesammelt und am Ende # ausgedruckt row1 = [] row2 = [] for col in range(8): opc = row << 4 | (col+offset) try: cmd = self.opcodes[opc] arg_txt = "" if cmd.amode in [ZP, ZPX, INDY, REL]: arg_txt = "aa" elif cmd.amode in [ABS, ABSX, ABSY, IND]: arg_txt = "aaaa" txt = cmd.to_str(arg_txt) # Befehlsnamen und Adressierungsart aufteilen itms = txt.split(" ") row1.append(itms[0]) if len(itms) > 1: row2.append(itms[1]) else: row2.append("") except KeyError: # kein Befehl fuer diese Opcode implementiert row1.append("") row2.append("") # 1. Zeile der Befehle ausgeben for itm in row1: print("|%s" % itm.center(7), end='') # 2. Zeile der Befehle ausgeben print("") print(" ", end='') for itm in row2: print("|%s" % itm.center(7), end='') print("") # Zwischenraum print("") print("") def setirq(self, adr): """ Aktiviert den Hardware-IRQ und setzt den Zeiger bei $fffe """ self.flag_i = False self.mem[0xfffe] = adr & 0xff self.mem[0xffff] = adr >> 8 def addhandler(self, label, adr, handler): """ Setzt einen Handler fuer eine bestimmte Adresse, der dann von JSR aufgerufen wird. """ self.jsr_alt[adr] = handler self.addresses[adr] = label self.labels[label] = adr def getargs(self): """ Verarbeitet die Parameter aus dem Programmaufruf """ self.parser = ArgumentParser( prog=self.progname, description=self.progdesc ) self.parser.add_argument("-r", "--reg", action='store_true', help="print registers") self.parser.add_argument("-c", "--cyc", action='store_true', help="print cycles") self.parser.add_argument("-m", "--mem", metavar="INT", help="print memory page") self.parser.add_argument("-f", "--file", metavar="FILE", help="program file in cbm format") self.parser.add_argument("-s", "--symtab", metavar="FILE", help="symtable for program file") self.parser.add_argument("-a", "--rega", metavar="INT", help="start value for A-Register") self.parser.add_argument("-x", "--regx", metavar="INT", help="start value for X-Register") self.parser.add_argument("-y", "--regy", metavar="INT", help="start value for Y-Register") self.parser.add_argument("--irq", metavar="INT", help="set IRQ handler") # self.parser.add_argument("--reset", metavar="INT", # help="set hardware reset handler") # self.parser.add_argument("--start", metavar="ADR", default=32768, # help="start of program (default $8000)") self.parser.add_argument("-d", "--disass", action='store_true', help="disassemble the program") self.parser.add_argument("--run", action='store_true', help="run the program") self.parser.add_argument("--jsr", action='store_true', help="create jsr call for program") self.parser.add_argument("--commands", action='store_true', help="print command table") def parseargs(self): """ Ruft den Argument-Parser auf (in einer extra Methode, damit abgeleitete Klassen noch Argumente hinzufuegen koennen, da ein mehrmaliger Aufruf von parse_args nicht funktioniert hat) """ self.args = self.parser.parse_args() def executeargs(self): """ Fuehrt die beim Programm uebergebenen Argumente aus """ if self.args.file: self.load(self.args.file) if self.args.symtab: self.loadsym(self.args.symtab) if self.args.commands: self.cmdtable() if self.args.disass: self.disass() if self.args.rega: self.reg_a = int(self.args.rega) if self.args.regx: self.reg_x = int(self.args.regx) if self.args.regy: self.reg_y = int(self.args.regy) if self.args.irq: try: adr = int(self.args.irq) # Dezimalwert except ValueError: adr = int(self.args.irq, 16) # Hex-Wert self.setirq(adr) if self.args.jsr: start_prg = self.start self.start = 0x0000 self.addcmd2('jsr aaaa', start_prg) self.addcmd('brk') if self.args.run: self.run() if self.args.reg: self.registers() if self.args.cyc: print("Cycles: %d" % self.cycles) if self.args.mem: self.mempage(int(self.args.mem)) if __name__ == "__main__": cpu = CPU6502() cpu.getargs() cpu.parseargs() cpu.executeargs()