def render(instr): if 'ops' in instr: optexts = [] for op in instr['ops']: if isinstance(op, dict) and 'type' in op: optext = op['text'] if 'text' in op else hex(op['value']) optexts.append(optext) else: optexts.append(str(op)) return "{} {}".format(instr['mnemonic'], ', '.join(optexts)) else: return instr['mnemonic'] def sext(number, bit): mask = 1 << bit if number & mask > 0: return - ((~number & (mask - 1)) + 1) else: return number NAMES = { 0xF60: '_ZERO_', 0xF61: '_ZERO_', 0xF62: 'SPPDATA', 0xF63: 'SPPCFG', 0xF64: 'SPPEPS', 0xF65: 'SPPCON', 0xF66: 'UFRML', 0xF67: 'UFRMH', 0xF68: 'UIR', 0xF69: 'UIE', 0xF6A: 'UEIR', 0xF6B: 'UEIE', 0xF6C: 'USTAT', 0xF6D: 'UCON', 0xF6E: 'UADDR', 0xF6F: 'UCFG', 0xF70: 'UEP0', 0xF71: 'UEP1', 0xF72: 'UEP2', 0xF73: 'UEP3', 0xF74: 'UEP4', 0xF75: 'UEP5', 0xF76: 'UEP6', 0xF77: 'UEP7', 0xF78: 'UEP8', 0xF79: 'UEP9', 0xF7A: 'UEP10', 0xF7B: 'UEP11', 0xF7C: 'UEP12', 0xF7D: 'UEP13', 0xF7E: 'UEP14', 0xF7F: 'UEP15', 0xF80: 'PORTA', 0xF81: 'PORTB', 0xF82: 'PORTC', 0xF83: 'PORTD', 0xF84: 'PORTE', 0xF85: '_ZERO_', 0xF86: '_ZERO_', 0xF87: '_ZERO_', 0xF88: '_ZERO_', 0xF89: 'LATA', 0xF8A: 'LATB', 0xF8B: 'LATC', 0xF8C: 'LATD', 0xF8D: 'LATE', 0xF8E: '_ZERO_', 0xF8F: '_ZERO_', 0xF90: '_ZERO_', 0xF91: '_ZERO_', 0xF92: 'TRISA', 0xF93: 'TRISB', 0xF94: 'TRISC', 0xF95: 'TRISD', 0xF96: 'TRISE', 0xF97: '_ZERO_', 0xF98: '_ZERO_', 0xF99: '_ZERO_', 0xF9A: '_ZERO_', 0xF9B: 'OSCTUNE', 0xF9C: '_ZERO_', 0xF9D: 'PIE1', 0xF9E: 'PIR1', 0xF9F: 'IPR1', 0xFA0: 'PIE2', 0xFA1: 'PIR2', 0xFA2: 'IPR2', 0xFA3: '_ZERO_', 0xFA4: '_ZERO_', 0xFA5: '_ZERO_', 0xFA6: 'EECON1', 0xFA7: 'EECON2', 0xFA8: 'EEDATA', 0xFA9: 'EEADR', 0xFAA: '_ZERO_', 0xFAB: 'RCSTA', 0xFAC: 'TXSTA', 0xFAD: 'TXREG', 0xFAE: 'RCREG', 0xFAF: 'SPBRG', 0xFB0: 'SPBRGH', 0xFB1: 'T3CON', 0xFB2: 'TMR3L', 0xFB3: 'TMR3H', 0xFB4: 'CMCON', 0xFB5: 'CVRCON', 0xFB6: 'ECCP1AS', 0xFB7: 'ECCP1DEL', 0xFB8: 'BAUDCON', 0xFB9: '_ZERO_', 0xFBA: 'CCP2CON', 0xFBB: 'CCPR2L', 0xFBC: 'CCPR2H', 0xFBD: 'CCP1CON', 0xFBE: 'CCPR1L', 0xFBF: 'CCPR1H', 0xFC0: 'ADCON2', 0xFC1: 'ADCON1', 0xFC2: 'ADCON0', 0xFC3: 'ADRESL', 0xFC4: 'ADRESH', 0xFC5: 'SSPCON2', 0xFC6: 'SSPCON1', 0xFC7: 'SSPSTAT', 0xFC8: 'SSPADD', 0xFC9: 'SSPBUF', 0xFCA: 'T2CON', 0xFCB: 'PR2', 0xFCC: 'TMR2', 0xFCD: 'T1CON', 0xFCE: 'TMR1L', 0xFCF: 'TMR1H', 0xFD0: 'RCON', 0xFD1: 'WDTCON', 0xFD2: 'HLVDCON', 0xFD3: 'OSCCON', 0xFD4: '_ZERO_', 0xFD5: 'T0CON', 0xFD6: 'TMR0L', 0xFD7: 'TMR0H', 0xFD8: 'STATUS', 0xFD9: 'FSR2L', 0xFDA: 'FSR2H', 0xFDB: 'PLUSW2', 0xFDC: 'PREINC2', 0xFDD: 'POSTDEC2', 0xFDE: 'POSTINC2', 0xFDF: 'INDF2', 0xFE0: 'BSR', 0xFE1: 'FSR1L', 0xFE2: 'FSR1H', 0xFE3: 'PLUSW1', 0xFE4: 'PREINC1', 0xFE5: 'POSTDEC1', 0xFE6: 'POSTINC1', 0xFE7: 'INDF1', 0xFE8: 'WREG', 0xFE9: 'FSR0L', 0xFEA: 'FSR0H', 0xFEB: 'PLUSW0', 0xFEC: 'PREINC0', 0xFED: 'POSTDEC0', 0xFEE: 'POSTINC0', 0xFEF: 'INDF0', 0xFF0: 'INTCON3', 0xFF1: 'INTCON2', 0xFF2: 'INTCON', 0xFF3: 'PRODL', 0xFF4: 'PRODH', 0xFF5: 'TABLAT', 0xFF6: 'TBLPTRL', 0xFF7: 'TBLPTRH', 0xFF8: 'TBLPTRU', 0xFF9: 'PCL', 0xFFA: 'PCLATH', 0xFFB: 'PCLATU', 0xFFC: 'STKPTR', 0xFFD: 'TOSL', 0xFFE: 'TOSH', 0xFFF: 'TOSU' } def reg_name(number): if number in NAMES: return NAMES[number] else: return None def disassemble(blob, offset): instr = {} instr['length'] = 1 instrbytes = blob[offset:offset + 2] instrbytes.reverse() # instrbytes.reverse() # print("Decoding {:02x}{:02x}...".format(instrbytes[0], instrbytes[1])) if instrbytes[0] == 0x00: # there's a few instructions here... if instrbytes[1] == 0xff: instr['mnemonic'] = 'reset' else: mnemonicmap = [ 'nop', 'BAD', 'BAD', 'sleep', 'clrwdt', 'push', 'pop', 'daw', 'tblrd*', 'tblrd*+', 'tblrd*-', 'tblrd+*', 'tblwr*', 'tblwr*+', 'tblwr*-', 'tblwr+*', 'retfie', 'retfie fast', 'return', 'return fast', 'callw*'] if instrbytes[1] > len(mnemonicmap): instr['mnemonic'] = 'BAD' else: instr['mnemonic'] = mnemonicmap[instrbytes[1]] elif instrbytes[0] == 0x01: if instrbytes[1] > 0xf: instr['mnemonic'] = 'BAD' else: instr['mnemonic'] = 'movlb' instr['ops'] = ["#" + str(instrbytes[1])] elif instrbytes[0] == 0x02 or instrbytes[0] == 0x03: instr['mnemonic'] = 'mulwf' instr['ops'] = ['TODO'] elif instrbytes[0] >= 0x04 and instrbytes[0] < 0x08: instr['mnemonic'] = 'decf' d = (instrbytes[0] >> 1) & 1 a = instrbytes[0] & 1 f = instrbytes[1] if a == 0: # "Access Bank" f_physical = f if f < 0x60 else 0xf00 + f source = { 'type': 'register', 'value': f_physical } else: source = { 'type': 'banked-register', 'value': f } if d == 0: dest = { 'type': 'register', 'value': 'W' } else: dest = source if a == 0: instr['ops'] = [ source, dest ] else: instr['ops'] = [ source, dest, 'banked' ] elif instrbytes[0] >= 0x08 and instrbytes[0] < 0x10: code = instrbytes[0] & 0x7 instr['mnemonic'] = [ 'sublw', 'iorlw', 'xorlw', 'andlw', 'retlw', 'mullw', 'movlw', 'addlw' ][code] instr['ops'] = ['#' + hex(instrbytes[1])] elif instrbytes[0] >= 0x10 and instrbytes[0] < 0x20: code = (instrbytes[0] >> 2) & 0x3 instr['mnemonic'] = [ 'iorwf', 'andwf', 'xorwf', 'comf' ][code] d = (instrbytes[0] >> 1) & 1 a = instrbytes[0] & 1 f = instrbytes[1] if a == 0: # "Access Bank" f_physical = f if f < 0x60 else 0xf00 + f source = { 'type': 'register', 'value': f_physical } else: source = { 'type': 'banked-register', 'value': f } if d == 0: dest = { 'type': 'register', 'value': 'W' } else: dest = source if a == 0: instr['ops'] = [ source, dest ] else: instr['ops'] = [ source, dest, 'banked' ] elif instrbytes[0] >= 0x20 and instrbytes[0] < 0x60: mnemonicSel = instrbytes[0] >> 2 instr['mnemonic'] = [ 'mulwf (TODO)', #000000 'decf', #000001 'BAD', 'BAD', #00001X 'iorwf', #000100 'andwf', #000101 'xorwf', #000110 'comf', #000111 'addwfc', #001000 'addwf', #001001 'incf', #001010 'decfsz', #001011 'rrcf', #001100 'rlcf', #001101 'swapf', #001110 'incfsz', #001111 'rrncf', #010000 'rlncf', #010001 'infsnz', #010010 'dcfsnz', #010011 'movf', #010100 'subwfb', #010101 'subwfb', #000000 'subwf' #000000 ][mnemonicSel] d = (instrbytes[0] >> 1) & 1 a = instrbytes[0] & 1 f = instrbytes[1] if a == 0: # "Access Bank" f_physical = f if f < 0x60 else 0xf00 + f source = { 'type': 'register', 'value': f_physical } else: source = { 'type': 'banked-register', 'value': f } if d == 0: dest = { 'type': 'register', 'value': 'W' } else: dest = source if a == 0: instr['ops'] = [ source, dest ] else: instr['ops'] = [ source, dest, 'banked' ] elif instrbytes[0] >= 0x60 and instrbytes[0] < 0x70: mnemonicSel = (instrbytes[0] >> 1) & 0x7 instr['mnemonic'] = [ 'cpfslt', 'cpfseq', 'cpfsgt', 'tstfsz', 'setf', 'clrf', 'negf', 'movwf' ][mnemonicSel] a = instrbytes[0] & 1 f = instrbytes[1] if a == 0: # "Access Bank" f_physical = f if f < 0x60 else 0xf00 + f instr['ops'] = [ { 'type': 'register', 'value': f_physical } ] else: instr['ops'] = [ { 'type': 'banked-register', 'value': f }, "banked" ] elif instrbytes[0] >= 0x70 and instrbytes[0] < 0xc0: mnemonicSel = instrbytes[0] >> 4 instr['mnemonic'] = [ 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'btg', 'bsf', 'bcf', 'btfss', 'btfsc' ][mnemonicSel] bit = (instrbytes[0] >> 1) & 0x7 a = instrbytes[0] & 1 f = instrbytes[1] if a == 0: # "Access Bank" f_physical = f if f < 0x60 else 0xf00 + f instr['ops'] = [ { 'type': 'register', 'value': f_physical }, bit ] else: instr['ops'] = [ { 'type': 'banked-register', 'value': f }, bit, "banked" ] elif instrbytes[0] >= 0xc0 and instrbytes[0] < 0xd0: instr['mnemonic'] = 'movff' instr['length'] = 2 fs = ((instrbytes[0] & 0xf) << 8) | instrbytes[1] followingbytes = blob[offset + 2:offset + 4] followingbytes.reverse() if followingbytes[0] < 0xf0: instr['mnemonic'] = 'movff (BAD)' else: fd = ((followingbytes[0] & 0xf) << 8) | followingbytes[1] instr['ops'] = [ { 'type': 'register', 'value': fs }, { 'type': 'register', 'value': fd } ] elif instrbytes[0] >= 0xd0 and instrbytes[0] < 0xd8: instr['mnemonic'] = 'bra' n = ((instrbytes[0] & 0x7) << 8) | instrbytes[1] n = sext(n, 10) instr['ops'] = [{ 'type': 'relpostdest', 'value': n << 1 }] elif instrbytes[0] >= 0xd8 and instrbytes[0] < 0xe0: instr['mnemonic'] = 'rcall' n = ((instrbytes[0] & 0x7) << 8) | instrbytes[1] instr['ops'] = [{ 'type': 'relpostdest', 'value': n << 1 }] elif instrbytes[0] >= 0xe0 and instrbytes[0] <= 0xe8: code = instrbytes[0] & 0x7 instr['mnemonic'] = [ 'bz', 'bnz', 'bc', 'bnc', 'bov', 'bnov', 'bn', 'bnn' ][code] n = instrbytes[1] n = sext(n, 7) instr['ops'] = [{ 'type': 'relpostdest', 'value': n << 1 }] elif instrbytes[0] >= 0xf0 and instrbytes[0] <= 0xff: instr['mnemonic'] = 'BAD (misdecode)' elif instrbytes[0] == 0xea: instr['mnemonic'] = 'push' instr['ops'] = [instrbytes[1]] elif instrbytes[0] == 0xec or instrbytes[0] == 0xed: instr['mnemonic'] = 'call' s = instrbytes[0] & 1 instr['length'] = 2 lowbits = instrbytes[1] followingbytes = blob[offset + 2:offset + 4] followingbytes.reverse() if followingbytes[0] < 0xf0: instr['mnemonic'] = 'CALL (BAD)' else: k = (((followingbytes[0] & 0x0f) << 16) | (followingbytes[1] << 8) | lowbits) instr['ops'] = [{ 'type': 'absolutedest', 'value': k << 1 }, str(s)] elif instrbytes[0] == 0xee: instr['mnemonic'] = 'lfsr' instr['length'] = 2 f = (instrbytes[1] >> 4) & 3 followingbytes = blob[offset + 2:offset + 4] followingbytes.reverse() if followingbytes[0] < 0xf0: instr['mnemonic'] = 'lsfr (BAD)' else: k = ((instrbytes[1] & 0xf) << 8) | followingbytes[1] instr['ops'] = [str(f), hex(k)] elif instrbytes[0] == 0xef: instr['mnemonic'] = 'goto' instr['length'] = 2 lowbits = instrbytes[1] followingbytes = blob[offset + 2:offset + 4] followingbytes.reverse() if followingbytes[0] < 0xf0: instr['mnemonic'] = 'GOTO (BAD)' else: k = ((followingbytes[0] & 0x0f) << 16) | (followingbytes[1] << 8) | lowbits instr['ops'] = [{ 'type': 'absolutedest', 'value': k << 1 }] else: instr['mnemonic'] = 'TODO' return (offset + instr['length'] * 2, instr)