/* This file is in the public domain. */ /* * Super-H support. For the moment, this is for the SH-4, such as used * in the Dreamcast; in particular, Hitachi document ADE-602-156A rev * 2.0, documenting the SH7750, is my main reference. */ #include #include extern const char *__progname; #include "machine.h" #include "fnprintf.h" typedef struct instr INSTR; struct instr { const char *init; const char *fmt; unsigned short int mask; unsigned short int value; } ; /* * In fmt: * %n = 0x0f00 bits * %N3 = like %n, but masked with 0xe * %N2 = like %n, but masked with 0xc * %m = 0x00f0 bits * %M3 = like %m, but masked with 0xe * %M2 = 0x0300 bits, *4 * %i = 0x00ff bits, signed * %b8 = 0x00ff bits, branch offset * %bc = 0x0fff bits, branch offset * %r = 0x0070 bits * %p2 = 0x00ff bits, pc-relative offset ×2 * %p4 = 0x00ff bits, (pc&~3)-relative offset ×4 * %d1 = 0x00ff bits * %d2 = 0x00ff bits ×2 * %d4 = 0x00ff bits ×4 * %D1 = 0x000f bits * %D2 = 0x000f bits ×2 * %D4 = 0x000f bits ×4 * * %w also exists in the code (dis_fmt), but it is not for use by this * table; it's for the "unrecognized" format. */ static INSTR instrs[] = { { "0011nnnnmmmm1100", "add r%m,r%n" }, { "0111nnnniiiiiiii", "add #%i,r%n" }, { "0011nnnnmmmm1110", "addc r%m,r%n" }, { "0011nnnnmmmm1111", "addv r%m,r%n" }, { "0010nnnnmmmm1001", "and r%m,r%n" }, { "11001001iiiiiiii", "and #%i,r0" }, { "11001101iiiiiiii", "and.b #%i,@(r0,gbr)" }, { "10001011dddddddd", "bf %b8" }, { "10001111dddddddd", "bf/s %b8" }, { "1010dddddddddddd", "bra %bc" }, { "0000nnnn00100011", "braf r%n" }, { "1011dddddddddddd", "bsr %bc" }, { "0000nnnn00000011", "bsrf r%n" }, { "10001001dddddddd", "bt %b8" }, { "10001101dddddddd", "bt/s %b8" }, { "0000000000101000", "clrmac" }, { "0000000001001000", "clrs" }, { "0000000000001000", "clrt" }, { "0011nnnnmmmm0000", "cmp/eq r%m,r%n" }, { "0011nnnnmmmm0011", "cmp/ge r%m,r%n" }, { "0011nnnnmmmm0111", "cmp/gt r%m,r%n" }, { "0011nnnnmmmm0110", "cmp/hi r%m,r%n" }, { "0011nnnnmmmm0010", "cmp/hs r%m,r%n" }, { "0100nnnn00010101", "cmp/pl r%n" }, { "0100nnnn00010001", "cmp/pz r%n" }, { "0010nnnnmmmm1100", "cmp/str r%m,r%n" }, { "10001000iiiiiiii", "cmp/eq #%i,r0" }, { "0010nnnnmmmm0111", "div0s r%m,r%n" }, { "0000000000011001", "div0u" }, { "0011nnnnmmmm0100", "div1 r%m,r%n" }, { "0011nnnnmmmm1101", "dmuls.l r%m,r%n" }, { "0011nnnnmmmm0101", "dmulu.l r%m,r%n" }, { "0100nnnn00010000", "dt r%n" }, { "0110nnnnmmmm1110", "exts.b r%m,r%n" }, { "0110nnnnmmmm1111", "exts.w r%m,r%n" }, { "0110nnnnmmmm1100", "extu.b r%m,r%n" }, { "0110nnnnmmmm1101", "extu.w r%m,r%n" }, { "1111nnnn01011101", "fabs fr%n" }, { "1111nnn001011101", "fabs dr%n" }, { "1111nnnnmmmm0000", "fadd fr%m,fr%n" }, { "1111nnn0mmm00000", "fadd dr%M3,dr%N3" }, { "1111nnnnmmmm0100", "fcmp/eq fr%m,fr%n" }, { "1111nnn0mmm00100", "fcmp/eq dr%M3,dr%N3" }, { "1111nnnnmmmm0101", "fcmp/gt fr%m,fr%n" }, { "1111nnn0mmm00101", "fcmp/gt dr%M3,dr%N3" }, { "1111nnn010111101", "fcnvds dr%N3,fpul" }, { "1111nnn010101101", "fcnvsd fpul,dr%N3" }, { "1111nnnnmmmm0011", "fdiv fr%m,fr%n" }, { "1111nnn0mmm00011", "fdiv dr%M3,dr%N3" }, { "1111nnmm11101101", "fipr fv%M2,fv%M2" }, { "1111nnnn10001101", "fldi0 fr%n" }, { "1111nnnn10011101", "fldi1 fr%n" }, { "1111nnnn00011101", "flds fr%n,fpul" }, { "1111nnnn00101101", "float fpul,fr%n" }, { "1111nnn000101101", "float fpul,dr%n" }, { "1111nnnnmmmm1110", "fmac fr0,fr%m,fr%n" }, { "1111nnnnmmmm1100", "fmov fr%m,fr%n" }, { "1111nnn0mmm01100", "fmov dr%M3,dr%N3" }, { "1111nnnnmmmm1010", "fmov.s fr%m,@r%n" }, { "1111nnnnmmm01010", "fmov dr%M3,@r%n" }, { "1111nnnnmmmm1000", "fmov.s @r%m,fr%n" }, { "1111nnn0mmmm1000", "fmov @r%m,dr%N3" }, { "1111nnnnmmmm1001", "fmov.s @r%m+,fr%n" }, { "1111nnn0mmmm1001", "fmov @r%m+,dr%N3" }, { "1111nnnnmmmm1011", "fmov.s fr%m,@-r%n" }, { "1111nnnnmmm01011", "fmov dr%m,@-r%n" }, { "1111nnnnmmmm0110", "fmov.s @(r0,r%m),fr%n" }, { "1111nnn0mmmm0110", "fmov @(r0,r%m),dr%N3" }, { "1111nnnnmmmm0111", "fmov.s fr%m,@(r0,r%n)" }, { "1111nnnnmmm00111", "fmov dr%M3,@(r0,r%n)" }, { "1111nnnnmmm11010", "fmov xd%M3,@r%n" }, { "1111nnn1mmmm1000", "fmov @r%m,xd%N3" }, { "1111nnn1mmmm1001", "fmov @r%m+,xd%N3" }, { "1111nnnnmmm11011", "fmov xd%M3,@-r%n" }, { "1111nnn1mmmm0110", "fmov @(r0,r%m),xd%N3" }, { "1111nnnnmmm10111", "fmov xd%M3,@(r0,r%n)" }, { "1111nnn1mmm11100", "fmov xd%M3,xd%N3" }, { "1111nnn0mmm11100", "fmov xd%M3,dr%N3" }, { "1111nnn1mmm01100", "fmov dr%M3,xd%N3" }, { "1111nnnnmmmm0010", "fmul fr%m,fr%n" }, { "1111nnn0mmm00010", "fmul dr%M3,dr%N3" }, { "1111nnnn01001101", "fneg fr%n" }, { "1111nnn001001101", "fneg dr%N3" }, { "1111101111111101", "frchg" }, { "1111001111111101", "fschg" }, { "1111nnnn01101101", "fsqrt fr%n" }, { "1111nnn001101101", "fsqrt dr%N3" }, { "1111nnnn00001101", "fsts fpul,fr%n" }, { "1111nnnnmmmm0001", "fsub fr%m,fr%n" }, { "1111nnn0mmm00001", "fsub dr%M3,dr%N3" }, { "1111nnnn00111101", "ftrc fr%n,fpul" }, { "1111nnn000111101", "ftrc dr%N3,fpul" }, { "1111nn0111111101", "ftrv xmtrx,fv%N2" }, { "0100nnnn00101011", "jmp @r%n" }, { "0100nnnn00001011", "jsr @r%n" }, { "0100nnnn00001110", "ldc r%n,sr" }, { "0100nnnn00011110", "ldc r%n,gbr" }, { "0100nnnn00101110", "ldc r%n,vbr" }, { "0100nnnn00111110", "ldc r%n,ssr" }, { "0100nnnn01001110", "ldc r%n,spc" }, { "0100nnnn11111010", "ldc r%n,dbr" }, { "0100nnnn1rrr1110", "ldc r%n,r%r_bank" }, { "0100nnnn00000111", "ldc.l @r%n+,sr" }, { "0100nnnn00010111", "ldc.l @r%n+,gbr" }, { "0100nnnn00100111", "ldc.l @r%n+,vbr" }, { "0100nnnn00110111", "ldc.l @r%n+,ssr" }, { "0100nnnn01000111", "ldc.l @r%n+,spc" }, { "0100nnnn11110110", "ldc.l @r%n+,dbr" }, { "0100nnnn1rrr0111", "ldc.l @r%n+,r%r_bank" }, { "0100nnnn01011010", "lds r%n,fpul" }, { "0100nnnn01010110", "lds.l @r%n+,fpul" }, { "0100nnnn01101010", "lds r%n,fpscr" }, { "0100nnnn01100110", "lds.l @r%n+,fpscr" }, { "0100nnnn00001010", "lds r%n,mach" }, { "0100nnnn00011010", "lds r%n,macl" }, { "0100nnnn00101010", "lds r%n,pr" }, { "0100nnnn00000110", "lds.l @r%n+,mach" }, { "0100nnnn00010110", "lds.l @r%n+,macl" }, { "0100nnnn00100110", "lds.l @r%n+,pr" }, { "0000000000111000", "ldtlb" }, { "0000nnnnmmmm1111", "mac.l @r%m+,@r%n+" }, { "0100nnnnmmmm1111", "mac.w @r%m+,@r%n+" }, { "0110nnnnmmmm0011", "mov r%m,r%n" }, { "0010nnnnmmmm0000", "mov.b r%m,@r%n" }, { "0010nnnnmmmm0001", "mov.w r%m,@r%n" }, { "0010nnnnmmmm0010", "mov.l r%m,@r%n" }, { "0110nnnnmmmm0000", "mov.b @r%m,r%n" }, { "0110nnnnmmmm0001", "mov.w @r%m,r%n" }, { "0110nnnnmmmm0010", "mov.l @r%m,r%n" }, { "0010nnnnmmmm0100", "mov.b r%m,@-r%n" }, { "0010nnnnmmmm0101", "mov.w r%m,@-r%n" }, { "0010nnnnmmmm0110", "mov.l r%m,@-r%n" }, { "0110nnnnmmmm0100", "mov.b @r%m+,r%n" }, { "0110nnnnmmmm0101", "mov.w @r%m+,r%n" }, { "0110nnnnmmmm0110", "mov.l @r%m+,r%n" }, { "0000nnnnmmmm0100", "mov.b r%m,@(r0,r%n)" }, { "0000nnnnmmmm0101", "mov.w r%m,@(r0,r%n)" }, { "0000nnnnmmmm0110", "mov.l r%m,@(r0,r%n)" }, { "0000nnnnmmmm1100", "mov.b @(r0,r%m),r%n" }, { "0000nnnnmmmm1101", "mov.w @(r0,r%m),r%n" }, { "0000nnnnmmmm1110", "mov.l @(r0,r%m),r%n" }, { "1110nnnniiiiiiii", "mov #%i,r%n" }, { "1001nnnnoooooooo", "mov.w %p2,r%n" }, { "1101nnnnoooooooo", "mov.l %p4,r%n" }, { "11000100oooooooo", "mov.b @(%d1,gbr),r0" }, { "11000101oooooooo", "mov.w @(%d2,gbr),r0" }, { "11000110oooooooo", "mov.l @(%d4,gbr),r0" }, { "11000000oooooooo", "mov.b r0,@(%d1,gbr)" }, { "11000001oooooooo", "mov.w r0,@(%d2,gbr)" }, { "11000010oooooooo", "mov.l r0,@(%d4,gbr)" }, { "10000000mmmmoooo", "mov.b r0,@(%D1,r%m)" }, { "10000001mmmmoooo", "mov.w r0,@(%D2,r%m)" }, { "0001nnnnmmmmoooo", "mov.l r%m,@(%D4,r%n)" }, { "10000100mmmmoooo", "mov.b @(%D1,r%m),r0" }, { "10000101mmmmoooo", "mov.w @(%D2,r%m),r0" }, { "0101nnnnmmmmoooo", "mov.l @(%D4,r%m),r%n" }, { "11000111oooooooo", "mova %p4,r0" }, { "0000nnnn11000011", "movca.l r0,@r%n" }, { "0000nnnn00101001", "movt r%n" }, { "0000nnnnmmmm0111", "mul.l r%m,r%n" }, { "0010nnnnmmmm1111", "muls.w r%m,r%n" }, { "0010nnnnmmmm1110", "mulu.w r%m,r%n" }, { "0110nnnnmmmm1011", "neg r%m,r%n" }, { "0110nnnnmmmm1010", "negc r%m,r%n" }, { "0000000000001001", "nop" }, { "0110nnnnmmmm0111", "not r%m,r%n" }, { "0000nnnn10010011", "ocbi @r%n" }, { "0000nnnn10100011", "ocbp @r%n" }, { "0000nnnn10110011", "ocbwb @r%n" }, { "0010nnnnmmmm1011", "or r%m,r%n" }, { "11001011iiiiiiii", "or #%i,r0" }, { "11001111iiiiiiii", "or.b #%i,@(r0,gbr)" }, { "0000nnnn10000011", "pref @r%n" }, { "0100nnnn00100100", "rotcl r%n" }, { "0100nnnn00100101", "rotcr r%n" }, { "0100nnnn00000100", "rotl r%n" }, { "0100nnnn00000101", "rotr r%n" }, { "0000000000101011", "rte" }, { "0000000000001011", "rts" }, { "0000000001011000", "sets" }, { "0000000000011000", "sett" }, { "0100nnnnmmmm1100", "shad r%m,r%n" }, { "0100nnnn00100000", "shal r%n" }, { "0100nnnn00100001", "shar r%n" }, { "0100nnnnmmmm1101", "shld r%m,r%n" }, { "0100nnnn00000000", "shll r%n" }, { "0100nnnn00001000", "shll2 r%n" }, { "0100nnnn00011000", "shll8 r%n" }, { "0100nnnn00101000", "shll16 r%n" }, { "0100nnnn00000001", "shlr r%n" }, { "0100nnnn00001001", "shlr2 r%n" }, { "0100nnnn00011001", "shlr8 r%n" }, { "0100nnnn00101001", "shlr16 r%n" }, { "0000000000011011", "sleep" }, { "0000nnnn00000010", "stc sr,r%n" }, { "0000nnnn00010010", "stc gbr,r%n" }, { "0000nnnn00100010", "stc vbr,r%n" }, { "0000nnnn00110010", "stc ssr,r%n" }, { "0000nnnn01000010", "stc spc,r%n" }, { "0000nnnn00111010", "stc sgr,r%n" }, { "0000nnnn11111010", "stc dbr,r%n" }, { "0000nnnn1rrr0010", "stc r%r_bank,r%n" }, { "0100nnnn00000011", "stc.l sr,@-r%n" }, { "0100nnnn00010011", "stc.l gbr,@-r%n" }, { "0100nnnn00100011", "stc.l vbr,@-r%n" }, { "0100nnnn00110011", "stc.l ssr,@-r%n" }, { "0100nnnn01000011", "stc.l spc,@-r%n" }, { "0100nnnn00110010", "stc.l sgr,@-r%n" }, { "0100nnnn11110010", "stc.l dbr,@-r%n" }, { "0100nnnn1rrr0011", "stc.l r%r_bank,@-r%n" }, { "0000nnnn00001010", "sts mach,r%n" }, { "0000nnnn00011010", "sts macl,r%n" }, { "0000nnnn00101010", "sts pr,r%n" }, { "0100nnnn00000010", "sts.l mach,@-r%n" }, { "0100nnnn00010010", "sts.l macl,@-r%n" }, { "0100nnnn00100010", "sts.l pr,@-r%n" }, { "0000nnnn01011010", "sts fpul,r%n" }, { "0000nnnn01101010", "sts fpscr,r%n" }, { "0100nnnn01010010", "sts.l fpul,@-r%n" }, { "0100nnnn01100010", "sts.l fpscr,@-r%n" }, { "0011nnnnmmmm1000", "sub r%m,r%n" }, { "0011nnnnmmmm1010", "subc r%m,r%n" }, { "0011nnnnmmmm1011", "subv r%m,r%n" }, { "0110nnnnmmmm1000", "swap.b r%m,r%n" }, { "0110nnnnmmmm1001", "swap.w r%m,r%n" }, { "0100nnnn00011011", "tas.b @r%n" }, { "11000011iiiiiiii", "trapa #%i" }, { "0010nnnnmmmm1000", "tst r%m,r%n" }, { "11001000iiiiiiii", "tst #%i,r0" }, { "11001100iiiiiiii", "tst.b #%i,@(r0,gbr)" }, { "0010nnnnmmmm1010", "xor r%m,r%n" }, { "11001010iiiiiiii", "xor #%i,r0" }, { "11001110iiiiiiii", "xor.b #%i,@(r0,gbr)" }, { "0010nnnnmmmm1101", "xtrct r%m,r%n" }, { 0, 0 } }; static void dis_fmt(const char *fmt, unsigned short int inst, ADDR at, void (*fn)(char)) { int v; while (*fmt) { if (*fmt++ != '%') { if (fn) (*fn)(fmt[-1]); continue; } switch (*fmt++) { case 'n': v = (inst >> 8) & 0xf; break; case 'N': switch (*fmt++) { case '3': v = (inst >> 8) & 0xe; break; case '2': v = (inst >> 8) & 0xc; break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } break; case 'm': v = (inst >> 4) & 0xf; break; case 'M': switch (*fmt++) { case '3': v = (inst >> 4) & 0xe; break; case '2': v = (inst >> 6) & 0xc; break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } break; case 'i': v = (inst & 0x0080) ? (int)(inst&0xff) - (int)0x100 : (inst & 0xff); break; case 'b': switch (*fmt++) { case '8': v = (inst & 0x0080) ? (int)(inst&0xff) - (int)0x100 : (inst & 0xff); break; case 'c': v = (inst & 0x0800) ? (int)(inst&0xfff) - (int)0x1000 : (inst & 0xfff); break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } print_symbol_or_hex(fn,at+4+(v*2)); continue; break; case 'r': v = (inst >> 4) & 0x7; break; case 'p': v = inst & 0x00ff; switch (*fmt++) { case '2': print_symbol_or_hex(fn,at+4+(v*2)); break; case '4': print_symbol_or_hex(fn,(at&~(ADDR)3)+4+(v*4)); break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } continue; break; case 'd': switch (*fmt++) { case '1': v = inst & 0xff; break; case '2': v = (inst & 0xff) << 1; break; case '4': v = (inst & 0xff) << 2; break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } break; case 'D': switch (*fmt++) { case '1': v = inst & 0xf; break; case '2': v = (inst & 0xf) << 1; break; case '4': v = (inst & 0xf) << 2; break; default: fnprintf(fn,"",(unsigned char)fmt[-1]); return; break; } break; case 'w': fnprintf(fn,"%04x",inst); continue; break; } fnprintf(fn,"%d",v); } } static int do_dis_inst(ADDR addr, void (*fn)(char), CFLAG flg) { unsigned short int inst; const char *fmt; int i; const INSTR *ip; int found; addr -= corebase; if (addr+2 > coresize) return(-1); inst = corefetchu(addr,2); found = -1; for (i=0;instrs[i].init;i++) { ip = &instrs[i]; if ((inst & ip->mask) == ip->value) { if (found == -1) { found = i; } else { found = -2; } } } switch (found) { case -1: fmt = ""; break; case -2: fmt = ""; break; default: if (found < 0) abort(); fmt = instrs[found].fmt; break; } dis_fmt(fmt,inst,addr,fn); if (flg & CFF_INST_PARALLEL) { return(1); } else { flags[addr+1] = CF_PREV; return(2); } } static int init_instr(INSTR *i) { int j; unsigned short int m; unsigned short int v; if (! i->init) return(0); m = 0; v = 0; for (j=0;j<16;j++) { switch (i->init[j]) { case '0': m = (m << 1) | 1; v = (v << 1) | 0; break; case '1': m = (m << 1) | 1; v = (v << 1) | 1; break; case 'd': case 'i': case 'm': case 'n': case 'o': case 'r': m = (m << 1) | 0; v = (v << 1) | 0; break; default: fprintf(stderr,"%s: invalid init (%02x at %d): %s %s\n",__progname,(unsigned char)i->init[j],j,i->init,i->fmt); exit(1); } i->mask = m; i->value = v; } return(1); } static void dreamcast_init(void) { int i; for (i=0;init_instr(&instrs[i]);i++) ; } static int dreamcast_dis(ADDR addr, void (*fn)(char)) { int rv; if (ISINST(flags[addr-corebase])) { rv = do_dis_inst(addr,fn,flags[addr-corebase]); } else { fnprintf(fn,"",(unsigned long int)flags[addr-corebase]); rv = 1; } return(rv); } static unsigned long int dreamcast_fetch(const void *base, int size) #define bp(n) ((unsigned long int)(((const unsigned char *)base)[(n)])) { switch (size) { case 1: return(bp(0)); break; case 2: return((bp(1)<<8)|bp(0)); break; case 4: return((bp(3)<<24)|(bp(2)<<16)|(bp(1)<<8)|bp(0)); break; } abort(); } #undef bp static const char *dreamcast_names[] = { "DREAMCAST", "DreamCast", "Dreamcast", "DC", "dc", 0 }; MACHINE machine_dreamcast = { &dreamcast_names[0], 4, &dreamcast_init, 0, &dreamcast_dis, &dreamcast_fetch, 0 };