/* This file is in the public domain. */ #include #include #include "fnprintf.h" #include "machine.h" #define CFF_ENTRY CFF_INST_MS1 #define CFO_ENTRY (CF_MSPEC+0) #define CFO_PENTRY (CF_MSPEC+1) #define OPC(x) ((int)(((x)>>26)&0x3f)) #define RS(x) ((int)(((x)>>21)&0x1f)) #define RT(x) ((int)(((x)>>16)&0x1f)) #define RD(x) ((int)(((x)>>11)&0x1f)) #define SA(x) ((int)(((x)>> 6)&0x1f)) #define FN(x) ((int)((x)&0x3f)) #define RB(x) RS(x) #define IMM_S(x) signextend((x)&0xffff,16) #define IMM_Z(x) ((x)&0xffff) #define JA(x) ((x)&0x03ffffff) #define BREAKCODE(x) (((x)>>6)&0xfffffUL) #define CTRAPCODE(x) ((int)(((x)>>6)&0x3ff)) #define FF5(x) RS(x) #define FRT(x) RT(x) #define FRS(x) RD(x) #define FRD(x) SA(x) #define FRB(x) RS(x) #define FRX(x) RT(x) #define FRR(x) RS(x) #define FF3(x) ((int)((x)&7)) #define CMOVECC(x) ((int)(((x)>>18)&7)) #define CMOVEL(x) ((int)(((x)>>17)&1)) #define CMOVETF(x) ((int)(((x)>>16)&1)) #define FCC(x) ((int)(((x)>>8)&7)) #define JUMPTARGET(delayaddr,opc) (((delayaddr)&0xf0000000UL)|(JA(opc)<<2)) #define BRANCHTARGET(delayaddr,opc) ((delayaddr)+signextend(IMM_Z(opc)<<2,18)) #define FF5_S 16 #define FF5_D 17 #define FF5_W 20 #define FF5_L 21 #define FF3_S 0 #define FF3_D 1 #define FF3_W 4 #define FF3_L 5 static const char *gpr[] = { "$zero","$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra" }; static const char *fpr[] = { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" }; static const char *fcr[] = { "$firr", "$fcr1", "$fcr2", "$fcr3", "$fcr4", "$fcr5", "$fcr6", "$fcr7", "$fcr8", "$fcr9", "$fcr10", "$fcr11", "$fcr12", "$fcr13", "$fcr14", "$fcr15", "$fcr16", "$fcr17", "$fcr18", "$fcr19", "$fcr20", "$fcr21", "$fcr22", "$fcr23", "$fcr24", "$fcr25", "$fcr26", "$fcr27", "$fcr28", "$fcr29", "$fcr30", "$fcsr" }; static const char ff5chr[32] = "????????????????sd??wl??????????"; static const char ff3chr[8] = "sd??wl??"; static const char *hints[] = { "0(load)", "1(store)", "2(?)", "2(?)", "4(load-stream)", "5(store-stream)", "6(load-retain)", "7(store-retain)", "8(?)", "9(?)", "10(?)", "11(?)", "12(?)", "13(?)", "14(?)", "15(?)", "16(?)", "17(?)", "18(?)", "19(?)", "20(?)", "21(?)", "22(?)", "23(?)", "24(?)", "25(?)", "26(?)", "27(?)", "28(?)", "29(?)", "30(?)", "31(?)" }; static signed long int signextend(unsigned long int ul, int nbits) { return( (ul&(1UL<<(nbits-1))) ? -(signed long int)((((1UL< coresize) return(-1); opc = corefetchu(addr,4); switch (OPC(opc)) { case 000: /* special */ switch (FN(opc)) { static const char *shifthow[] = { "ll", 0, "rl", "ra" }; case 000: case 002: case 003: case 070: case 072: case 073: if (RS(opc) == 0) { fnprintf(fn,"%ss%-*s%s, %s, %d",(FN(opc)>=070)?"d":"",(FN(opc)>=070)?10:11,shifthow[FN(opc)&3],gpr[RD(opc)],gpr[RT(opc)],SA(opc)); } else { unimp(fn,opc); } break; case 001: if ((SA(opc) == 0) && (CMOVEL(opc) == 0)) { fnprintf(fn,"mov%c %s, %s, %d",CMOVETF(opc)?'t':'f',gpr[RD(opc)],gpr[RS(opc)],CMOVECC(opc)); } else { unimp(fn,opc); } break; case 004: case 006: case 007: case 024: case 026: case 027: if (SA(opc) == 0) { fnprintf(fn,"%ss%sv%*s%s, %s, %s",(FN(opc)&020)?"d":"",shifthow[FN(opc)&3],(FN(opc)&020)?7:8,"",gpr[RD(opc)],gpr[RT(opc)],gpr[RS(opc)]); } else { unimp(fn,opc); } break; case 010: case 021: case 023: if ((RD(opc) == 0) && (RT(opc) == 0) && (SA(opc) == 0)) { static const char *name[] = { "jr", "mthi", 0, "mtlo" }; fnprintf(fn,"%-12s%s",name[FN(opc)&3],gpr[RS(opc)]); } else { unimp(fn,opc); } break; case 011: if ((SA(opc) == 0) && (RT(opc) == 0)) { if (RD(opc) == 31) { fnprintf(fn,"jalr %s",gpr[RS(opc)]); } else { fnprintf(fn,"jalr %s, %s",gpr[RD(opc)],gpr[RS(opc)]); } } else { unimp(fn,opc); } break; case 012: case 013: case 040: case 041: case 042: case 043: case 044: case 045: case 046: case 047: case 052: case 053: case 054: case 055: case 056: case 057: if (SA(opc) == 0) { static const char *name[] = { 0, 0, "movz", "movn", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "add", "addu", "sub", "subu", "and", "or", "xor", "nor", 0, 0, "slt", "sltu", "dadd", "daddu", "dsub", "dsubu" }; fnprintf(fn,"%-12s%s, %s, %s",name[FN(opc)-010],gpr[RD(opc)],gpr[RS(opc)],gpr[RT(opc)]); } else { unimp(fn,opc); } break; case 014: case 015: fnprintf(fn,"%-12s%#lx",(FN(opc)&1)?"break":"syscall",BREAKCODE(opc)); break; case 017: if ((RD(opc) == 0) && (RS(opc) == 0) && (RT(opc) == 0)) { if (SA(opc) == 0) { fnprintf(fn,"sync"); } else { fnprintf(fn,"sync %d",SA(opc)); } } else { unimp(fn,opc); } break; case 020: case 022: if ((RS(opc) == 0) && (RT(opc) == 0) && (SA(opc) == 0)) { fnprintf(fn,"mf%s %s",(FN(opc)&2)?"lo":"hi",gpr[RD(opc)]); } else { unimp(fn,opc); } break; case 030: case 031: case 032: case 033: case 034: case 035: case 036: case 037: if ((RD(opc) == 0) && (SA(opc) == 0)) { static const char *name[] = { "mult", "multu", "div", "divu", "dmult", "dmultu", "ddiv", "ddivu" }; fnprintf(fn,"%-12s%s, %s",name[FN(opc)&7],gpr[RS(opc)],gpr[RT(opc)]); } else { unimp(fn,opc); } break; case 060: case 061: case 062: case 063: case 064: case 066: { static const char *name[] = { "ge", "geu", "lt", "ltu", "eq", 0, "ne" }; fnprintf(fn,"t%-11s%s, %s ! code=%d",name[FN(opc)&7],gpr[RS(opc)],gpr[RT(opc)],CTRAPCODE(opc)); } break; case 074: case 076: case 077: if (RS(opc) == 0) { fnprintf(fn,"ds%-10s%s, %s, %d ! (ds%s32)",shifthow[FN(opc)&3],gpr[RD(opc)],gpr[RT(opc)],32+SA(opc),shifthow[FN(opc)&3]); } else { unimp(fn,opc); } break; case 005: case 016: case 025: case 050: case 051: case 065: case 067: case 071: case 075: unimp(fn,opc); break; } break; case 001: switch (RT(opc)) { case 000: case 001: case 002: case 003: case 020: case 021: case 022: case 023: fnprintf(fn,"b%sz%s%-*s%s, ",(RT(opc)&1)?"ge":"lt",(RT(opc)&020)?"al":"",8-((RT(opc)>>3)&2),(RT(opc)&02)?"l":"",gpr[RS(opc)]); print_symbol_or_hex(fn,BRANCHTARGET(addr+corebase+4,opc)); break; case 010: case 011: case 012: case 013: case 014: case 016: { static const char *name[] = { "tgei", "tgeiu", "tlti", "tltiu", "teqi", 0, "tnei" }; fnprintf(fn,"%-12s%s, %ld",name[RT(opc)-010],gpr[RS(opc)],IMM_S(opc)); } break; case 004: case 005: case 006: case 007: case 015: case 017: case 024: case 025: case 026: case 027: case 030: case 031: case 032: case 033: case 034: case 035: case 036: case 037: unimp(fn,opc); break; } break; case 002: fnprintf(fn,"j "); print_symbol_or_hex(fn,JUMPTARGET(addr+corebase+4,opc)); break; case 003: fnprintf(fn,"jal "); print_symbol_or_hex(fn,JUMPTARGET(addr+corebase+4,opc)); break; case 004: case 005: case 006: case 007: case 024: case 025: case 026: case 027: { static const char *cond[] = { 0, 0, 0, 0, "eq", "ne", "lez", "gtz", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "eql", "nel", "lezl", "gtzl" }; fnprintf(fn,"b%-11s%s, %s, ",cond[OPC(opc)],gpr[RS(opc)],gpr[RT(opc)]); print_symbol_or_hex(fn,BRANCHTARGET(addr+corebase+4,opc)); } break; case 010: case 011: case 012: case 013: case 014: case 015: case 016: case 030: case 031: { static const char *tbl[] = { "saddi", "saddiu", "sslti", "ssltiu", "uandi", "uori", "uxori", 0, 0, 0, 0, 0, 0, 0, 0, 0, "sdaddi", "sdaddiu" }; const char *op; op = tbl[OPC(opc)-010]; switch (*op) { case 's': fnprintf(fn,"%-12s%s, %s, %ld",op+1,gpr[RT(opc)],gpr[RS(opc)],IMM_S(opc)); break; case 'u': fnprintf(fn,"%-12s%s, %s, %#lx",op+1,gpr[RT(opc)],gpr[RS(opc)],IMM_Z(opc)); break; } } break; case 017: if (RS(opc) == 0) { fnprintf(fn,"lui %s, %ld",gpr[RT(opc)],IMM_S(opc)); if ( (RT(opc) == 28) && (addr+12 <= coresize) && ((corefetchu(addr+4,4) & 0xffff0000) == 0x279c0000) && /* addiu $gp, $gp, */ (corefetchu(addr+8,4) == 0x0399e021) ) /* addu $gp, $gp, $t9 */ { flags[addr] |= CFF_ENTRY; } } else { unimp(fn,opc); } break; case 020: fnprintf(fn,"cp0 op %07lx",opc&0x03ffffffLU); break; case 022: fnprintf(fn,"cp2 op %07lx",opc&0x03ffffffLU); break; case 021: switch (FF5(opc)) { case FF5_S: case FF5_D: switch (FN(opc)) { case 000: case 001: case 002: case 003: { static const char *name[] = { "add", "sub", "mul", "div" }; fnprintf(fn,"%s.%c %s, %s, %s",name[FN(opc)],ff5chr[FF5(opc)],fpr[FRD(opc)],fpr[FRS(opc)],fpr[FRT(opc)]); } break; case 004: case 005: case 006: case 007: case 010: case 011: case 012: case 013: case 014: case 015: case 016: case 017: case 025: case 026: case 044: case 045: if (FRT(opc) == 0) { static const char *name[] = { 0, 0, 0, 0, "sqrt", "abs", "mov", "neg", "round.l", "trunc.l", "ceil.l", "floor.l", "round.w", "trunc.w", "ceil.w", "floor.w", 0, 0, 0, 0, 0, "recip", "rsqrt", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "cvt.w", "cvt.l", 0, 0 }; fnprintf(fn,"%s.%-*c%s, %s",name[FN(opc)],11-(int)strlen(name[FN(opc)]),ff5chr[FF5(opc)],fpr[FRD(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; case 021: if (CMOVEL(opc) == 0) { fnprintf(fn,"mov%c.%c %s, %s, %d",CMOVETF(opc)?'t':'f',ff5chr[FF5(opc)],fpr[FRD(opc)],fpr[FRS(opc)],CMOVECC(opc)); } else { unimp(fn,opc); } break; case 022: case 023: fnprintf(fn,"mov%c.%c %s, %s, %s",(FN(opc)&1)?'n':'z',ff5chr[FF5(opc)],fpr[FRD(opc)],fpr[FRS(opc)],gpr[FRT(opc)]); break; case 040: if ((FRT(opc) == 0) && (FF5(opc) == FF5_D)) { fnprintf(fn,"cvt.s.d %s, %s",fpr[FRD(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; case 041: if ((FRT(opc) == 0) && (FF5(opc) == FF5_S)) { fnprintf(fn,"cvt.d.s %s, %s",fpr[FRD(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; case 060: case 061: case 062: case 063: case 064: case 065: case 066: case 067: case 070: case 071: case 072: case 073: case 074: case 075: case 076: case 077: if ((opc & 0xc0) == 0) { static const char *conds[] = { "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule", "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" }; fnprintf(fn,"c.%s.%-*c",conds[FN(opc)&017],9-(int)strlen(conds[FN(opc)&017]),ff5chr[FF5(opc)]); if (FCC(opc)) fnprintf(fn,"%d, ",FCC(opc)); fnprintf(fn,"%s, %s",fpr[FRS(opc)],fpr[FRT(opc)]); } else { unimp(fn,opc); } break; default: unimp(fn,opc); break; } break; case FF5_W: case FF5_L: switch (FN(opc)) { case 040: case 041: if (FRT(opc) == 0) { fnprintf(fn,"cvt.%c.%c %s, %s",(FN(opc)&1)?'d':'s',ff5chr[FF5(opc)],fpr[FRD(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; default: unimp(fn,opc); break; } break; case 000: case 004: if ((FRD(opc) == 0) && (FN(opc) == 0)) { fnprintf(fn,"m%cc1 %s, %s",(FF5(opc)&4)?'t':'f',gpr[FRT(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; case 001: case 005: if ((FRD(opc) == 0) && (FN(opc) == 0)) { fnprintf(fn,"dm%cc1 %s, %s",(FF5(opc)&4)?'t':'f',gpr[FRT(opc)],fpr[FRS(opc)]); } else { unimp(fn,opc); } break; case 002: case 006: if ((FRD(opc) == 0) && (FN(opc) == 0)) { fnprintf(fn,"c%cc1 %s, %s",(FF5(opc)&4)?'t':'f',gpr[FRT(opc)],fcr[FRS(opc)]); } else { unimp(fn,opc); } break; case 010: fnprintf(fn,"bc1%c%-8s",CMOVETF(opc)?'t':'f',CMOVEL(opc)?"l":""); if (CMOVECC(opc)) fnprintf(fn,"%d, ",CMOVECC(opc)); print_symbol_or_hex(fn,BRANCHTARGET(addr+corebase+4,opc)); break; default: unimp(fn,opc); break; } break; case 023: if (FN(opc) & 040) { static const char *name[] = { "madd", "msub", "nmadd", "nmsub" }; switch (FF3(opc)) { case FF3_S: case FF3_D: fnprintf(fn,"%s.%-*c%s, %s, %s, %s",name[(FN(opc)>>3)&3],11-(int)strlen(name[(FN(opc)>>3)&3]),ff3chr[FF3(opc)],fpr[FRD(opc)],fpr[FRR(opc)],fpr[FRS(opc)],fpr[FRT(opc)]); break; default: unimp(fn,opc); break; } } else { switch (FN(opc)) { case 000: case 001: if (FRS(opc) == 0) { fnprintf(fn,"l%cxc1 %s, %s(%s)",(FN(opc)&1)?'d':'w',fpr[FRD(opc)],gpr[FRX(opc)],gpr[FRB(opc)]); } else { unimp(fn,opc); } break; case 010: case 011: if (FRD(opc) == 0) { fnprintf(fn,"s%cxc1 %s, %s(%s)",(FN(opc)&1)?'d':'w',fpr[FRS(opc)],gpr[FRX(opc)],gpr[FRB(opc)]); } else { unimp(fn,opc); } break; case 017: if (FRD(opc) == 0) { fnprintf(fn,"prefx %s, %s(%s)",hints[RD(opc)],gpr[FRX(opc)],gpr[FRB(opc)]); } else { unimp(fn,opc); } break; default: unimp(fn,opc); break; } } break; case 032: case 033: case 040: case 041: case 042: case 043: case 044: case 045: case 046: case 047: case 050: case 051: case 052: case 053: case 054: case 055: case 056: case 060: case 061: case 062: case 064: case 065: case 066: case 067: case 070: case 071: case 072: case 074: case 075: case 076: case 077: { static const char *name[] = { 0, 0, "ldl", "ldr", 0, 0, 0, 0, "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", 0, "ll", "lwc1", "lwc2", 0, "lld", "ldc1", "ldc2", "ld", "sc", "swc1", "swc2", 0, "scd", "sdc1", "sdc2", "sd" }; fnprintf(fn,"%-12s%s, %ld(%s)",name[OPC(opc)-030],gpr[RT(opc)],IMM_S(opc),gpr[RS(opc)]); if ( (OPC(opc) == 043) && /* lw */ (RS(opc) == 28) ) /* $gp */ { ADDR a; a = addr; while (a >= 4) { a -= 4; if (! ISINST(flags[a])) { break; } else if (flags[a] & CFF_ENTRY) { ADDR p; p = (IMM_Z(corefetchu(a,4)) << 16) + IMM_S(corefetchu(a+4,4)) + a + IMM_S(opc); fnprintf(fn," ! "); print_symbol_or_hex(fn,p+corebase); if (p+4 <= coresize) { unsigned long int v; v = corefetchu(p,4); fnprintf(fn," -> "); if ( (v >= corebase+12) && (v < coreend) && ISINST(flags[v-corebase-12]) && (flags[v-corebase-12] & CFF_ENTRY) ) { print_symbol_or_hex(fn,v-12); fnprintf(fn," + 12"); } else { print_symbol_or_hex(fn,v); } } break; } } } } break; case 063: fnprintf(fn,"pref %s, %ld(%s)",hints[RD(opc)],IMM_S(opc),gpr[RB(opc)]); break; default: unimp(fn,opc); break; } if (addr & 3) { fnprintf(fn," {unaligned}"); return(1); } if (flg & CFF_INST_PARALLEL) { fnprintf(fn," {parallel}"); return(1); } flags[addr+1] = CF_PREV; flags[addr+2] = CF_PREV; flags[addr+3] = CF_PREV; return(4); } static void mips_init(void) { } static int mips_dis(ADDR addr, void (*fn)(char)) { int rv; switch (flags[addr-corebase]) { case CFO_ENTRY: flags[addr-corebase] = CF_INST; break; case CFO_PENTRY: flags[addr-corebase] = CF_INST | CFF_INST_PARALLEL; break; } 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 mipseb_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(0)<<8)|bp(1)); break; case 4: return((bp(0)<<24)|(bp(1)<<16)|(bp(2)<<8)|bp(3)); break; } abort(); } #undef bp static unsigned long int mipsel_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 *mipseb_names[] = { "MIPSEB", "mipseb", 0 }; MACHINE machine_mipseb = { &mipseb_names[0], 4, &mips_init, 0, &mips_dis, &mipseb_fetch, 0 }; static const char *mipsel_names[] = { "MIPSEL", "mipsel", 0 }; MACHINE machine_mipsel = { &mipsel_names[0], 4, &mips_init, 0, &mips_dis, &mipsel_fetch, 0 };