#!/usr/bin/env python3 """Minimal-but-practical Motorola 68HC11 disassembler for the PD01D221 ROM. CPU address == ROM offset for $8000-$FFFF (EPROM upper 32KB maps 1:1).""" import sys # addressing modes and their extra operand length (beyond opcode) INH='inh'; IMM8='imm8'; IMM16='imm16'; DIR='dir'; EXT='ext'; IDX='idx'; IDY='idy'; REL='rel' BITDIR='bitdir'; BITIDX='bitidx'; BITIDY='bitidy' # BSET/BCLR (mask) BRDIR='brdir'; BRIDX='bridx'; BRIDY='bridy' # BRSET/BRCLR (mask+rel) # page 0 P0 = { 0x00:('TEST',INH),0x01:('NOP',INH),0x02:('IDIV',INH),0x03:('FDIV',INH), 0x04:('LSRD',INH),0x05:('ASLD',INH),0x06:('TAP',INH),0x07:('TPA',INH), 0x08:('INX',INH),0x09:('DEX',INH),0x0A:('CLV',INH),0x0B:('SEV',INH), 0x0C:('CLC',INH),0x0D:('SEC',INH),0x0E:('CLI',INH),0x0F:('SEI',INH), 0x10:('SBA',INH),0x11:('CBA',INH),0x12:('BRSET',BRDIR),0x13:('BRCLR',BRDIR), 0x14:('BSET',BITDIR),0x15:('BCLR',BITDIR),0x16:('TAB',INH),0x17:('TBA',INH), 0x19:('DAA',INH),0x1B:('ABA',INH), 0x1C:('BSET',BITIDX),0x1D:('BCLR',BITIDX),0x1E:('BRSET',BRIDX),0x1F:('BRCLR',BRIDX), 0x20:('BRA',REL),0x21:('BRN',REL),0x22:('BHI',REL),0x23:('BLS',REL), 0x24:('BCC',REL),0x25:('BCS',REL),0x26:('BNE',REL),0x27:('BEQ',REL), 0x28:('BVC',REL),0x29:('BVS',REL),0x2A:('BPL',REL),0x2B:('BMI',REL), 0x2C:('BGE',REL),0x2D:('BLT',REL),0x2E:('BGT',REL),0x2F:('BLE',REL), 0x30:('TSX',INH),0x31:('INS',INH),0x32:('PULA',INH),0x33:('PULB',INH), 0x34:('DES',INH),0x35:('TXS',INH),0x36:('PSHA',INH),0x37:('PSHB',INH), 0x38:('PULX',INH),0x39:('RTS',INH),0x3A:('ABX',INH),0x3B:('RTI',INH), 0x3C:('PSHX',INH),0x3D:('MUL',INH),0x3E:('WAI',INH),0x3F:('SWI',INH), 0x40:('NEGA',INH),0x43:('COMA',INH),0x44:('LSRA',INH),0x46:('RORA',INH), 0x47:('ASRA',INH),0x48:('ASLA',INH),0x49:('ROLA',INH),0x4A:('DECA',INH), 0x4C:('INCA',INH),0x4D:('TSTA',INH),0x4F:('CLRA',INH), 0x50:('NEGB',INH),0x53:('COMB',INH),0x54:('LSRB',INH),0x56:('RORB',INH), 0x57:('ASRB',INH),0x58:('ASLB',INH),0x59:('ROLB',INH),0x5A:('DECB',INH), 0x5C:('INCB',INH),0x5D:('TSTB',INH),0x5F:('CLRB',INH), 0x60:('NEG',IDX),0x63:('COM',IDX),0x64:('LSR',IDX),0x66:('ROR',IDX), 0x67:('ASR',IDX),0x68:('ASL',IDX),0x69:('ROL',IDX),0x6A:('DEC',IDX), 0x6C:('INC',IDX),0x6D:('TST',IDX),0x6E:('JMP',IDX),0x6F:('CLR',IDX), 0x70:('NEG',EXT),0x73:('COM',EXT),0x74:('LSR',EXT),0x76:('ROR',EXT), 0x77:('ASR',EXT),0x78:('ASL',EXT),0x79:('ROL',EXT),0x7A:('DEC',EXT), 0x7C:('INC',EXT),0x7D:('TST',EXT),0x7E:('JMP',EXT),0x7F:('CLR',EXT), 0x80:('SUBA',IMM8),0x81:('CMPA',IMM8),0x82:('SBCA',IMM8),0x83:('SUBD',IMM16), 0x84:('ANDA',IMM8),0x85:('BITA',IMM8),0x86:('LDAA',IMM8),0x88:('EORA',IMM8), 0x89:('ADCA',IMM8),0x8A:('ORAA',IMM8),0x8B:('ADDA',IMM8),0x8C:('CPX',IMM16), 0x8D:('BSR',REL),0x8E:('LDS',IMM16),0x8F:('XGDX',INH), 0x90:('SUBA',DIR),0x91:('CMPA',DIR),0x92:('SBCA',DIR),0x93:('SUBD',DIR), 0x94:('ANDA',DIR),0x95:('BITA',DIR),0x96:('LDAA',DIR),0x97:('STAA',DIR), 0x98:('EORA',DIR),0x99:('ADCA',DIR),0x9A:('ORAA',DIR),0x9B:('ADDA',DIR), 0x9C:('CPX',DIR),0x9D:('JSR',DIR),0x9E:('LDS',DIR),0x9F:('STS',DIR), 0xA0:('SUBA',IDX),0xA1:('CMPA',IDX),0xA2:('SBCA',IDX),0xA3:('SUBD',IDX), 0xA4:('ANDA',IDX),0xA5:('BITA',IDX),0xA6:('LDAA',IDX),0xA7:('STAA',IDX), 0xA8:('EORA',IDX),0xA9:('ADCA',IDX),0xAA:('ORAA',IDX),0xAB:('ADDA',IDX), 0xAC:('CPX',IDX),0xAD:('JSR',IDX),0xAE:('LDS',IDX),0xAF:('STS',IDX), 0xB0:('SUBA',EXT),0xB1:('CMPA',EXT),0xB2:('SBCA',EXT),0xB3:('SUBD',EXT), 0xB4:('ANDA',EXT),0xB5:('BITA',EXT),0xB6:('LDAA',EXT),0xB7:('STAA',EXT), 0xB8:('EORA',EXT),0xB9:('ADCA',EXT),0xBA:('ORAA',EXT),0xBB:('ADDA',EXT), 0xBC:('CPX',EXT),0xBD:('JSR',EXT),0xBE:('LDS',EXT),0xBF:('STS',EXT), 0xC0:('SUBB',IMM8),0xC1:('CMPB',IMM8),0xC2:('SBCB',IMM8),0xC3:('ADDD',IMM16), 0xC4:('ANDB',IMM8),0xC5:('BITB',IMM8),0xC6:('LDAB',IMM8),0xC8:('EORB',IMM8), 0xC9:('ADCB',IMM8),0xCA:('ORAB',IMM8),0xCB:('ADDB',IMM8),0xCC:('LDD',IMM16), 0xCE:('LDX',IMM16),0xCF:('STOP',INH), 0xD0:('SUBB',DIR),0xD1:('CMPB',DIR),0xD2:('SBCB',DIR),0xD3:('ADDD',DIR), 0xD4:('ANDB',DIR),0xD5:('BITB',DIR),0xD6:('LDAB',DIR),0xD7:('STAB',DIR), 0xD8:('EORB',DIR),0xD9:('ADCB',DIR),0xDA:('ORAB',DIR),0xDB:('ADDB',DIR), 0xDC:('LDD',DIR),0xDD:('STD',DIR),0xDE:('LDX',DIR),0xDF:('STX',DIR), 0xE0:('SUBB',IDX),0xE1:('CMPB',IDX),0xE2:('SBCB',IDX),0xE3:('ADDD',IDX), 0xE4:('ANDB',IDX),0xE5:('BITB',IDX),0xE6:('LDAB',IDX),0xE7:('STAB',IDX), 0xE8:('EORB',IDX),0xE9:('ADCB',IDX),0xEA:('ORAB',IDX),0xEB:('ADDB',IDX), 0xEC:('LDD',IDX),0xED:('STD',IDX),0xEE:('LDX',IDX),0xEF:('STX',IDX), 0xF0:('SUBB',EXT),0xF1:('CMPB',EXT),0xF2:('SBCB',EXT),0xF3:('ADDD',EXT), 0xF4:('ANDB',EXT),0xF5:('BITB',EXT),0xF6:('LDAB',EXT),0xF7:('STAB',EXT), 0xF8:('EORB',EXT),0xF9:('ADCB',EXT),0xFA:('ORAB',EXT),0xFB:('ADDB',EXT), 0xFC:('LDD',EXT),0xFD:('STD',EXT),0xFE:('LDX',EXT),0xFF:('STX',EXT), } # page 1 ($18): Y versions P1 = { 0x08:('INY',INH),0x09:('DEY',INH),0x1C:('BSET',BITIDY),0x1D:('BCLR',BITIDY), 0x1E:('BRSET',BRIDY),0x1F:('BRCLR',BRIDY),0x30:('TSY',INH),0x35:('TYS',INH), 0x38:('PULY',INH),0x3A:('ABY',INH),0x3C:('PSHY',INH), 0x60:('NEG',IDY),0x63:('COM',IDY),0x64:('LSR',IDY),0x66:('ROR',IDY), 0x67:('ASR',IDY),0x68:('ASL',IDY),0x69:('ROL',IDY),0x6A:('DEC',IDY), 0x6C:('INC',IDY),0x6D:('TST',IDY),0x6E:('JMP',IDY),0x6F:('CLR',IDY), 0x8C:('CPY',IMM16),0x8F:('XGDY',INH),0x9C:('CPY',DIR), 0xA0:('SUBA',IDY),0xA1:('CMPA',IDY),0xA2:('SBCA',IDY),0xA3:('SUBD',IDY), 0xA4:('ANDA',IDY),0xA5:('BITA',IDY),0xA6:('LDAA',IDY),0xA7:('STAA',IDY), 0xA8:('EORA',IDY),0xA9:('ADCA',IDY),0xAA:('ORAA',IDY),0xAB:('ADDA',IDY), 0xAC:('CPY',IDY),0xAD:('JSR',IDY),0xAE:('LDS',IDY),0xAF:('STS',IDY), 0xBC:('CPY',EXT),0xCE:('LDY',IMM16),0xDE:('LDY',DIR),0xDF:('STY',DIR), 0xE0:('SUBB',IDY),0xE1:('CMPB',IDY),0xE2:('SBCB',IDY),0xE3:('ADDD',IDY), 0xE4:('ANDB',IDY),0xE5:('BITB',IDY),0xE6:('LDAB',IDY),0xE7:('STAB',IDY), 0xE8:('EORB',IDY),0xE9:('ADCB',IDY),0xEA:('ORAB',IDY),0xEB:('ADDB',IDY), 0xEC:('LDD',IDY),0xED:('STD',IDY),0xEE:('LDY',IDY),0xEF:('STY',IDY), 0xFE:('LDY',EXT),0xFF:('STY',EXT), } # page 2 ($1A): CPD, and X/Y cross indexed P2 = {0x83:('CPD',IMM16),0x93:('CPD',DIR),0xA3:('CPD',IDX),0xB3:('CPD',EXT), 0xAC:('CPY',IDX),0xEE:('LDY',IDX),0xEF:('STY',IDX)} # page 4 ($CD): X/Y cross indexed P4 = {0xA3:('CPD',IDY),0xAC:('CPX',IDY),0xEE:('LDX',IDY),0xEF:('STX',IDY)} def disasm(rom, addr, count): out=[] for _ in range(count): start=addr op=rom[addr]; addr+=1 tab=P0; pfx='' if op==0x18: pfx='18 '; op=rom[addr]; addr+=1; tab=P1 elif op==0x1A: pfx='1A '; op=rom[addr]; addr+=1; tab=P2 elif op==0xCD: pfx='CD '; op=rom[addr]; addr+=1; tab=P4 ent=tab.get(op) if ent is None: out.append((start,f".byte ${op:02X}",'?')); continue mn,mode=ent; operand=''; tgt=None if mode==INH: pass elif mode==IMM8: operand=f"#${rom[addr]:02X}"; addr+=1 elif mode==IMM16: operand=f"#${(rom[addr]<<8)|rom[addr+1]:04X}"; addr+=2 elif mode==DIR: operand=f"${rom[addr]:02X}"; addr+=1 elif mode==EXT: v=(rom[addr]<<8)|rom[addr+1]; addr+=2; operand=f"${v:04X}"; tgt=v elif mode==IDX: operand=f"${rom[addr]:02X},X"; addr+=1 elif mode==IDY: operand=f"${rom[addr]:02X},Y"; addr+=1 elif mode==REL: rel=rom[addr]; addr+=1; d=rel-256 if rel>127 else rel tgt=(addr+d)&0xFFFF; operand=f"${tgt:04X}" elif mode==BITDIR: operand=f"${rom[addr]:02X} #${rom[addr+1]:02X}"; addr+=2 elif mode==BITIDX: operand=f"${rom[addr]:02X},X #${rom[addr+1]:02X}"; addr+=2 elif mode==BITIDY: operand=f"${rom[addr]:02X},Y #${rom[addr+1]:02X}"; addr+=2 elif mode==BRDIR: dd=rom[addr]; mk=rom[addr+1]; rel=rom[addr+2]; addr+=3 s=rel-256 if rel>127 else rel; tgt=(addr+s)&0xFFFF operand=f"${dd:02X} #${mk:02X} ${tgt:04X}" elif mode==BRIDX: dd=rom[addr]; mk=rom[addr+1]; rel=rom[addr+2]; addr+=3 s=rel-256 if rel>127 else rel; tgt=(addr+s)&0xFFFF operand=f"${dd:02X},X #${mk:02X} ${tgt:04X}" elif mode==BRIDY: dd=rom[addr]; mk=rom[addr+1]; rel=rom[addr+2]; addr+=3 s=rel-256 if rel>127 else rel; tgt=(addr+s)&0xFFFF operand=f"${dd:02X},Y #${mk:02X} ${tgt:04X}" raw=' '.join(f'{rom[b]:02X}' for b in range(start,addr)) out.append((start,f"{pfx}{mn} {operand}".strip(), raw, mn, tgt)) return out if __name__=='__main__': rom=open(__import__('os').path.join(__import__('os').path.dirname(__file__),'tms27pc512.BIN'),'rb').read() start=int(sys.argv[1],16); count=int(sys.argv[2]) if len(sys.argv)>2 else 40 for row in disasm(rom,start,count): a=row[0]; txt=row[1]; raw=row[2] print(f"{a:04X}: {raw:<12} {txt}")