/* * Copyright (c) 2013, Peter Rutenbar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "../core/shoebill.h" #include "../core/mc68851.h" struct dis_t dis; uint16_t dis_op; // // Helper routines // uint16_t dis_next_word (void) { uint16_t next = dis.binary[dis.pos]; next <<= 8; next |= dis.binary[dis.pos+1]; dis.pos+=2; return next; } // // EA decoder routines // void disass_ea_extended (char *buf, uint8_t mr) { const uint32_t start_pc = dis.orig_pc + dis.pos; const uint32_t ext_a = dis_next_word(); ~decompose(ext_a, d rrr w ss F b i zz 0 III); // d == index register type // r == index register // w == word/long-word index size // s == scale factor // F == extension word format (0==brief, 1==full) // b == base register suppress // i == index suppress // z == base displacement size // I == index/indirect selection // printf("index_reg_type=%u, index_reg=%u, index_sz=%u, scale=%u, brief/ful=%u, supress_base=%u, suppress_index=%u, base_disp_sz=%u, I=%x\n", // d, r, w, s, F, b, i, z, I); if (F == 0) { // If this is the brief extension word char base_disp[32] = "0x0"; char base_addr[32] = "0x0"; char index[32] = ""; // use the sign extended least significant byte in the extension word int8_t base_disp_addr = (int8_t)(ext_a & 0xff); sprintf(base_disp, "%s0x%x", (base_disp_addr<0)?"-":"", abs(base_disp_addr)); // find the base address if (~bmatch(mr, 00xx1xxx)) // consult the MR, use the PC? sprintf(base_addr, "pc"); else // otherwise, it's aX sprintf(base_addr, "a%u", mr&7); // find the index value sprintf(index, "%c%u.%c", "da"[d], r, "wl"[w]); if (s > 0) // if there's an actual scale value sprintf(index+strlen(index), "*%u", 1< 0) // if there's an actual scale value sprintf(index+strlen(index), "*%u", 1< 1) { // but only if the size is > null uint32_t base_disp_addr; if (z == 2) // the base displacement is a sign-extended word base_disp_addr = (int16_t)dis_next_word(); else { // else, it's a long word base_disp_addr = dis_next_word(); base_disp_addr = (base_disp_addr<<16) | dis_next_word(); } sprintf(base_disp, "0x%x", base_disp_addr); } // find the outer displacement switch ((i<<3)|I) { // based on I/IS case ~b(0010): case ~b(0110): case ~b(1010): { // sign-extended word-length outer displacemnt uint32_t addr = (int16_t)(dis_next_word()); sprintf(outer_disp, "0x%x", addr); break; } case ~b(0011): case ~b(0111): case ~b(1011): { // long word outer displacement uint32_t addr = dis_next_word(); addr = (addr << 16) | dis_next_word(); sprintf(outer_disp, "0x%x", addr); break; } } // now generate a disassembled EA string // switch on the index/indirect selection switch ((i<<3)|I) { case ~b(1100) ... ~b(1111): case ~b(0100): { // invalid sprintf(buf, "???"); return ; } case ~b(0001): case ~b(0010): case ~b(0011): { // indirect preindexed with * outer displacement // ([bd,An,Xn.SIZE*SCALE],od) if (strlen(outer_disp)) sprintf(buf, "[%s,%s,%s],%s", base_disp, base_addr, index, outer_disp); else sprintf(buf, "[%s,%s,%s]", base_disp, base_addr, index); return ; } case ~b(0101): case ~b(0110): case ~b(0111): { // indirect postindexed with * outer displacement // ([bd,An],Xn.SIZE*SCALE,od) if (strlen(outer_disp)) sprintf(buf, "[%s,%s],%s,%s", base_disp, base_addr, index, outer_disp); else sprintf(buf, "[%s,%s],%s", base_disp, base_addr, index); return ; } case ~b(1001): case ~b(1010): case ~b(1011): { // Memory indirect with * outer displacement // ([bd,An],od) if (strlen(outer_disp)) sprintf(buf, "[%s,%s],%s", base_disp, base_addr, outer_disp); else sprintf(buf, "[%s,%s]", base_disp, base_addr); return ; } case ~b(0000): { // No memory indirect action (with index) sprintf(buf, "%s,%s,%s", base_disp, base_addr, index); return; } case ~b(1000): { // No memory indirect action (without index) sprintf(buf, "%s,%s", base_disp, base_addr); return ; } } } // never get here sprintf(buf, "NEVER GET HERE!"); return ; } char* decode_ea_rw (uint8_t mr, uint8_t sz) { const uint8_t mode = (mr >> 3) & 7, reg = (mr & 7); char *str = dis.ea_str_internal + dis.ea_last_pos_internal; dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024; switch (mode) { case 0: { // Data register direct mode sprintf(str, "d%u", reg); return str; } case 1: { // address register direct mode sprintf(str, "a%u", reg); return str; } case 2: { // address register indirect mode sprintf(str, "(a%u)", reg); return str; } case 3: { // address register indirect with postincrement mode sprintf(str, "(a%u)+", reg); return str; } case 4: { // address register indirect with predecrement mode sprintf(str, "-(a%u)", reg); return str; } case 5: { // address register indirect with displacement mode int16_t displacement = ((int16_t)dis_next_word()); sprintf(str, "%s0x%x(a%u)", (displacement>=0)?"":"-", abs(displacement), reg); return str; } case 6: { str[0] = '('; disass_ea_extended(str+1, mr); sprintf(str + strlen(str), ")"); return str; } case 7: { switch (reg) { case 0: { // absolute short addressing mode const int32_t addr = (int16_t)(dis_next_word()); sprintf(str, "(0x%08x)", addr); return str; } case 1: { // absolute long addressing mode uint32_t addr = dis_next_word(); addr = (addr<<16) | dis_next_word(); sprintf(str, "(0x%08x)", addr); return str; } case 2: { // program counter indirect with displacement mode const uint16_t ext = dis_next_word(); sprintf(str, "(0x%08x)", dis.orig_pc + 2 + ((int16_t)ext)); return str; } case 3: { // (program counter - evil 68020 addr modes) str[0] = '('; disass_ea_extended(str+1, mr); sprintf(str + strlen(str), ")"); return str; } case 4: { // immediate data const uint16_t ext = dis_next_word(); if (sz == 1) { sprintf(str, "0x%02x", ext&0xff); } else if (sz == 2) { sprintf(str, "0x%04x", ext); } else { const uint16_t ext2 = dis_next_word(); sprintf(str, "0x%04x%04x", ext, ext2); } return str; } case 5 ... 7: { sprintf(str, "???"); return str; } } } } return "error: dis: Never get here!"; } char* decode_ea_addr (uint8_t mr) { const uint8_t mode = (mr >> 3) & 7, reg = (mr & 7); char *str = dis.ea_str_internal + dis.ea_last_pos_internal; dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024; switch (mode) { case 0 ... 1: { // Data/address register direct mode sprintf(str, "???"); return str; } case 2: { // address register indirect mode sprintf(str, "(a%u)", reg); return str; } case 3: { // address register indirect with postincrement mode sprintf(str, "???"); return str; } case 4: { // address register indirect with predecrement mode sprintf(str, "???"); return str; } case 5: { // address register indirect with displacement mode int16_t displacement = ((int16_t)dis_next_word()); sprintf(str, "%s0x%x(a%u)", (displacement>=0)?"":"-", abs(displacement), reg); return str; } case 6: { str[0] = '('; disass_ea_extended(str+1, mr); sprintf(str + strlen(str), ")"); return str; } case 7: { switch (reg) { case 0: { // absolute short addressing mode const int32_t addr = (int16_t)(dis_next_word()); sprintf(str, "(0x%08x)", addr); return str; } case 1: { // absolute long addressing mode uint32_t addr = dis_next_word() << 16; addr |= dis_next_word(); sprintf(str, "(0x%08x)", addr); return str; } case 2: { // program counter indirect with displacement mode const uint16_t ext = dis_next_word(); sprintf(str, "(0x%08x)", dis.orig_pc + 2 + ((int16_t)ext)); return str; } case 3: { // (program counter - evil 68020 addr modes) str[0] = '('; disass_ea_extended(str+1, mr); sprintf(str + strlen(str), ")"); return str; } case 4: { // immediate data sprintf(str, "???"); return str; } case 5 ... 7: { sprintf(str, "???"); return str; } } } } return "Error: decode_ea_addr: never get here!"; } // // Disassembler instruction implementations // void dis_reset() { sprintf(dis.str, "reset"); } void dis_asx_reg () { ~decompose(dis_op, 1110 ccc d ss i 00 rrr); if (i) { sprintf(dis.str, "as%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); } else { const uint8_t count = (c==0)?8:c; sprintf(dis.str, "as%c.%c %u,d%u", "rl"[d], "bwl"[s], count, r); } } void dis_asx_mem () { sprintf(dis.str, "asx_mem?"); } void dis_lsx_reg () { ~decompose(dis_op, 1110 ccc d ss i 01 rrr); if (i) { sprintf(dis.str, "ls%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); } else { const uint8_t count = (c==0)?8:c; sprintf(dis.str, "ls%c.%c %u,d%u", "rl"[d], "bwl"[s], count, r); } } void dis_lsx_mem () { ~decompose(dis_op, 1110 001d 11 MMMMMM); sprintf(dis.str, "ls%c %s", "rl"[d], decode_ea_rw(M, 2)); } void dis_roxx_reg () { ~decompose(dis_op, 1110 ccc d ss i 10 rrr); if (i) sprintf(dis.str, "rox%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); else sprintf(dis.str, "rox%c.%c %u,d%u", "rl"[d], "bwl"[s], c?c:8, r); } void dis_roxx_mem () { sprintf(dis.str, "roxx_mem?"); } void dis_rox_reg () { ~decompose(dis_op, 1110 ccc d ss i 11 rrr); if (i) sprintf(dis.str, "ro%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); else sprintf(dis.str, "ro%c.%c %u,d%u", "rl"[d], "bwl"[s], c?c:8, r); } void dis_rox_mem () { sprintf(dis.str, "rox_mem?"); } void dis_moveq () { ~decompose(dis_op, 0111 rrr 0 dddddddd); const int32_t dat = ((int8_t)d); sprintf(dis.str, "moveq.l 0x%x,d%u", dat, r); } void dis_add () { ~decompose(dis_op, 1101 rrr d ss MMMMMM); if (d) { sprintf(dis.str, "add.%c d%u,%s", "bwl"[s], r, decode_ea_rw(M, 1<>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfextu %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); sprintf(dis.str + strlen(dis.str), "},d%u", r); } void dis_bfchg() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 000 Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfchg %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); } void dis_bfexts() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 rrr Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfexts %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); sprintf(dis.str + strlen(dis.str), "},d%u", r); } void dis_bfclr() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 000 Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfclr %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); } void dis_bfset() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 000 Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfset %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); } void dis_bfffo() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 rrr Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfffo %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); sprintf(dis.str + strlen(dis.str), "},d%u", r); } void dis_bftst() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 000 Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bftst %s{", ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); } void dis_bfins() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 1110 1111 11 MMMMMM); ~decompose(ext, 0 rrr Ffffff Wwwwww); char *ea = decode_ea_addr(M); if ((M>>3)==0) // addr modes or data reg sprintf(ea, "d%u", M&7); sprintf(dis.str, "bfins d%u,%s{", r, ea); if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); else sprintf(dis.str + strlen(dis.str), "%u:", f); if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); } void dis_btst_reg() { ~decompose(dis_op, 0000 rrr 100 MMMMMM); // sz==4 if M==000xxx if ((M >> 3) == 0) sprintf(dis.str, "btst.l d%u,%s", r, decode_ea_rw(M, 4)); else sprintf(dis.str, "btst.b d%u,%s", r, decode_ea_rw(M, 1)); } void dis_bchg_reg() { ~decompose(dis_op, 0000 rrr 101 MMMMMM); const uint32_t sz = (M >> 3) ? 4 : 1; sprintf(dis.str, "bchg %du,%s", r%32, decode_ea_rw(M, sz)); } void dis_bclr_reg() { ~decompose(dis_op, 0000 rrr 110 MMMMMM); const uint32_t sz = (M >> 3) ? 4 : 1; sprintf(dis.str, "bclr d%u,%s", r%32, decode_ea_rw(M, sz)); } void dis_bset_reg() { ~decompose(dis_op, 0000 rrr 111 MMMMMM); const uint32_t sz = (M >> 3) ? 4 : 1; sprintf(dis.str, "bset %u,%s", r%32, decode_ea_rw(M, sz)); } void dis_subi () { ~decompose(dis_op, 0000 0100 ss MMMMMM); const uint8_t sz = 1<> 1)) sprintf(dis.str, "movea.b ???"); else sprintf(dis.str, "movea.%c %s,a%u", "lw"[s&1], decode_ea_rw(M, 1< relative address (?) const char *condition_names[16] = { "t", "ra", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" }; ~decompose(dis_op, 0101 cccc 11001 rrr); uint32_t new_pc = dis.orig_pc+2; new_pc += (int16_t)dis_next_word(); sprintf(dis.str, "db%s d%u,*0x%08x", condition_names[c], r, new_pc); } void dis_bcc () { uint32_t new_pc = dis.orig_pc+2; char size = 'b'; ~decompose(dis_op, 0110 cccc dddddddd); // ra => relative address (?) // sr => subroutine (?) const char *condition_names[16] = { "ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" }; // figure out the new PC if ((d==0) || (d==0xff)) { const uint16_t ext = dis_next_word(); if (d==0xff) { size = 'l'; uint32_t mylong = ((uint32_t)ext)<<16; mylong |= dis_next_word(); new_pc += mylong; } else { size = 'w'; new_pc += ((int16_t)ext); } } else { uint8_t tmp = d; new_pc += ((int8_t)d); } sprintf(dis.str, "b%s.%c *0x%08x", condition_names[c], size, new_pc); } void dis_bsr () { dis_bcc(); // bsr is bcc where cc==F } void dis_subx() { ~decompose(dis_op, 1001 yyy 1 ss 00 m xxx); if (m) sprintf(dis.str, "subx.%c -(a%u),-(a%u)", "bwl"[s], x, y); else sprintf(dis.str, "subx.%c d%u,d%u", "bwl"[s], x, y); } void dis_btst_immediate() { ~decompose(dis_op, 0000 1000 11 MMMMMM); ~decompose(dis_op, 0000 1000 11 mmmrrr); const uint16_t ext = dis_next_word(); ~decompose(ext, 00000000 bbbbbbbb); if ((M >> 3) == 0) sprintf(dis.str, "btst.l %u,%s", b % 32, decode_ea_rw(M, 4)); else sprintf(dis.str, "btst.b %u,%s", b % 8, decode_ea_rw(M, 1)); } void dis_move_from_ccr() { ~decompose(dis_op, 0100 0010 11 MMMMMM); sprintf(dis.str, "move.w ccr,%s", decode_ea_rw(M, 2)); } void dis_move_to_ccr() { ~decompose(dis_op, 0100 0100 11 MMMMMM); sprintf(dis.str, "move.w %s,ccr", decode_ea_rw(M, 2)); } void dis_neg() { ~decompose(dis_op, 0100 0100 ss MMMMMM); sprintf(dis.str, "neg.%c %s", "bwl"[s], decode_ea_rw(M, 1<>3)==0; const uint8_t sz = is_data_reg ? 4 : 1; const uint8_t shift = b % (is_data_reg ? 32 : 8); sprintf(dis.str, "bclr.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); } void dis_bchg_immediate() { ~decompose(dis_op, 0000 1000 10 MMMMMM); const uint16_t ext = dis_next_word(); ~decompose(ext, 00000000 bbbbbbbb); const uint8_t is_data_reg = (M>>3)==0; const uint8_t sz = is_data_reg ? 4 : 1; const uint8_t shift = b % (is_data_reg ? 32 : 8); sprintf(dis.str, "bchg.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); } void dis_bset_immediate() { ~decompose(dis_op, 0000 1000 11 MMMMMM); const uint16_t ext = dis_next_word(); ~decompose(ext, 00000000 bbbbbbbb); const uint8_t is_data_reg = (M>>3)==0; const uint8_t sz = is_data_reg ? 4 : 1; const uint8_t shift = b % (is_data_reg ? 32 : 8); sprintf(dis.str, "bset.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); } void dis_sub() { ~decompose(dis_op, 1001 rrr dss MMMMMM); const uint8_t sz = 1< - Dn -> sprintf(dis.str, "sub.%c d%u,%s", "bwl"[s], r, decode_ea_rw(M, sz)); } else { sprintf(dis.str, "sub.%c %s,d%u", "bwl"[s], decode_ea_rw(M, sz), r); } } void dis_suba () { ~decompose(dis_op, 1001 rrr s 11 MMMMMM); sprintf(dis.str, "suba.%c %s,a%u", "wl"[s], decode_ea_rw(M, 2+2*s), r); } void dis_move_to_sr() { ~decompose(dis_op, 0100 0110 11 MMMMMM); sprintf(dis.str, "move.w %s,sr", decode_ea_rw(M, 2)); } void dis_move_from_sr() { ~decompose(dis_op, 0100 0000 11 MMMMMM); sprintf(dis.str, "move.w sr,%s", decode_ea_rw(M, 2)); } void dis_negx() { ~decompose(dis_op, 0100 0000 ss MMMMMM); sprintf(dis.str, "negx.%c %s", "bwl"[s], decode_ea_rw(M, 1<word, 2->long word sprintf(dis.str, "chk.%c %s,d%u", "lw"[s], decode_ea_rw(M, sz), r); } void dis_jmp () { ~decompose(dis_op, 0100 1110 11 MMMMMM); sprintf(dis.str, "jmp %s", decode_ea_addr(M)); } void dis_unknown () { sprintf(dis.str, "???"); } void dis_link_word () { ~decompose(dis_op, 0100 1110 0101 0 rrr); const int16_t ext = dis_next_word(); sprintf(dis.str, "link.w a%u,%d", r, ext); } void dis_unlk () { ~decompose(dis_op, 0100 1110 0101 1 rrr); sprintf(dis.str, "unlk a%u", r); } void dis_rts () { sprintf(dis.str, "rts"); } void dis_cinv() { ~decompose(dis_op, 1111 0100 cc 0 ss rrr); switch (s) { case 1: sprintf(dis.str, "cinvl %cc,(a%u)", "ndib"[c], r); break ; case 2: sprintf(dis.str, "cinvp %cc,(a%u)", "ndib"[c], r); break ; case 3: sprintf(dis.str, "cinva %cc", "ndib"[c]); } } void dis_cpush() { ~decompose(dis_op, 1111 0100 cc 1 ss rrr); switch (s) { case 1: sprintf(dis.str, "cpushl %cc,(a%u)", "ndib"[c], r); break ; case 2: sprintf(dis.str, "cpushp %cc,(a%u)", "ndib"[c], r); break ; case 3: sprintf(dis.str, "cpusha %cc", "ndib"[c]); } } void dis_link_long() { ~decompose(dis_op, 0100 1000 0000 1 rrr); uint32_t disp = dis_next_word() << 16; disp |= dis_next_word(); sprintf(dis.str, "link.l a%u,%d", r, (int32_t)disp); } void dis_pea() { ~decompose(dis_op, 0100 1000 01 MMMMMM); sprintf(dis.str, "pea %s", decode_ea_addr(M)); } void dis_nbcd() { sprintf(dis.str, "nbcd???"); } void dis_sbcd() { sprintf(dis.str, "sbcd???"); } void dis_pack() { sprintf(dis.str, "pack???"); } void dis_unpk() { sprintf(dis.str, "unpk???"); } void dis_divu() { ~decompose(dis_op, 1000 rrr 011 MMMMMM); sprintf(dis.str, "divu.w %s,d%u", decode_ea_rw(M, 2), r); } void dis_divs() { ~decompose(dis_op, 1000 rrr 111 MMMMMM); sprintf(dis.str, "divs.w %s,d%u", decode_ea_rw(M, 2), r); } void dis_bkpt() { sprintf(dis.str, "bkpt???"); } void dis_swap() { ~decompose(dis_op, 0100 1000 0100 0 rrr); sprintf(dis.str, "swap d%u", r); } void dis_abcd() { ~decompose(dis_op, 1100 xxx 10000 m yyy); if (m) sprintf(dis.str, "abcd.b -(a%u),-(a%u)", y, x); else sprintf(dis.str, "abcd.b d%u,d%u", y, x); } void dis_muls() { ~decompose(dis_op, 1100 rrr 011 MMMMMM); sprintf(dis.str, "muls.w %s,d%u", decode_ea_rw(M, 2), r); } void dis_mulu() { ~decompose(dis_op, 1100 rrr 011 MMMMMM); sprintf(dis.str, "mulu.w %s,d%u", decode_ea_rw(M, 2), r); } void dis_exg() { ~decompose(dis_op, 1100 xxx 1 ppppp yyy); if (p == ~b(01000)) // data reg mode sprintf(dis.str, "exg d%u,d%u", x, y); else if (p == ~b(01001)) // address reg mode sprintf(dis.str, "exg a%u,a%u", x, y); else if (p == ~b(10001)) // data/addr reg mode sprintf(dis.str, "exg d%u,a%u", x, y); else sprintf(dis.str, "exg ???\n"); } void dis_stop() { uint16_t ext = dis_next_word(); sprintf(dis.str, "stop 0x%04x", ext); } void dis_rte() { sprintf(dis.str, "rte"); } void dis_rtr() { sprintf(dis.str, "rtr"); } void dis_rtd() { const int16_t ext = dis_next_word(); sprintf(dis.str, "rtd %d", ext); } void dis_move_usp() { ~decompose(dis_op, 0100 1110 0110 d rrr); if (d) sprintf(dis.str, "move.l usp,a%u", r); else sprintf(dis.str, "move.l a%u,usp", r); } void dis_and() { ~decompose(dis_op, 1100 rrr dss MMMMMM); const uint8_t sz = 1<>3) == ~b(100)) sprintf(ea_str, "-(a%u)", M&7); else if ((M>>3) == ~b(011)) sprintf(ea_str, "(a%u)+", M&7); else ea_str = decode_ea_addr(M); // For predecrement-mode, the mask is backwards, for nobody's convenience const uint8_t is_mask_backwards = (((M>>3)==4) && (D==0)); char regstr[50] = ""; int8_t a[8], d[8], ai=0, di=0; uint32_t i, j; // movem traditionally has a format like "movem (a7),d2-d5/a1" // Also, this implementation is very, very ugly, and I am very embarrassed about it. uint8_t newmask[16]; for (i=0; i<16; i++) newmask[i] = is_mask_backwards ? (1&(mask>>(15-i))) : ((mask>>i)&1); if (mask) { for (i=0; i<16; i++) { if ((i/8) && newmask[i]) // addr reg sprintf(regstr + strlen(regstr), "a%u/", i%8); else if (newmask[i]) // data reg sprintf(regstr + strlen(regstr), "d%u/", i%8); } regstr[strlen(regstr)-1] = 0; } else { sprintf(regstr, "0"); } if (D) { // memory - to - register sprintf(dis.str, "movem.%c %s,%s", "wl"[s], ea_str, regstr); } else { // register - to - memory sprintf(dis.str, "movem.%c %s,%s", "wl"[s], regstr, ea_str); } } void dis_movec() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 0100 1110 0111 101x); ~decompose(ext, t rrr cccccccccccc); char *c_reg; switch (c) { case 0x002: // CACR c_reg = "cacr"; break; case 0x000: // SFC c_reg = "sfc"; break; case 0x001: // DFC c_reg = "dfc"; break; case 0x800: // USP c_reg = "usp"; break; case 0x801: // VBR c_reg = "vbr"; break; case 0x802: // CAAR (not supported on 68040) c_reg = "caar"; break; case 0x803: // MSP c_reg = "msp"; break; case 0x804: // ISP c_reg = "isp"; break; case 0x003: // TC c_reg = "tc"; break; case 0x004: // ITT0 c_reg = "itt0"; break; case 0x005: // ITT1 c_reg = "itt1"; break; case 0x006: // DTT0 c_reg = "dtt0"; break; case 0x007: // DTT1 c_reg = "dtt1"; break; case 0x805: // MMUSR c_reg = "mmusr"; break; case 0x806: // URP c_reg = "urp"; break; case 0x807: // SRP c_reg = "srp"; break; default: c_reg = "???"; break; } if (x) sprintf(dis.str, "movec.l %s%u,%s", t?"a":"d", r, c_reg); else sprintf(dis.str, "movec.l %s,%s%u", c_reg, t?"a":"d", r); } void dis_moves() { const uint16_t ext = dis_next_word(); ~decompose(dis_op, 0000 1110 ss MMMMMM); ~decompose(ext, a rrr d 00000000000); const uint8_t sz = 1< 2)) dis_mc68851_ptrapcc(c); else dis_mc68851_pscc(c); return ; } // dis_op must have the form (1111 000 000 xxxxxx) now ~decompose(ext, XXX YYY 00 0000 0000); switch (X) { case 1: // pflush, pload, pvalid if (Y == ~b(000)) dis_mc68851_pload(ext); else if ((Y == ~b(010)) || (Y == ~b(011))) dis_mc68851_pvalid(ext); else dis_mc68851_pflush(ext); return ; case 2: // pmove format 1 dis_mc68851_pmove(ext); return ; case 3: // pmove formats 2 and 3, dis_mc68851_pmove(ext); return ; case 4: // ptest dis_mc68851_ptest(ext); return ; case 5: // pflushr dis_mc68851_pflushr(ext); return ; default: sprintf(dis.str, "p_unknown"); return ; } assert(!"never get here"); } #include "dis_decoder_guts.c" /* * Disassembler entry point */ void disassemble_inst(uint8_t binary[32], uint32_t orig_pc, char *str, uint32_t *instlen) { dis.pos = 0; memcpy(dis.binary, binary, 32); dis.ea_last_pos_internal = 0; // start the ea decoder's ring buffer at 0 dis.orig_pc = orig_pc; dis.str = str; dis_op = dis_next_word(); // dis_decode() can only see dis_op dis_instruction_to_pointer[dis_opcode_map[dis_op]](); if (instlen) *instlen = dis.pos; }