Cog/Frameworks/HighlyExperimental/HighlyExperimental/Core/r3000dis.c
2013-09-30 03:36:30 -07:00

265 lines
10 KiB
C

/////////////////////////////////////////////////////////////////////////////
//
// r3000dis - R3000 disassembler
//
/////////////////////////////////////////////////////////////////////////////
#ifndef EMU_COMPILE
#error "Hi I forgot to set EMU_COMPILE"
#endif
#include "r3000dis.h"
/////////////////////////////////////////////////////////////////////////////
#define INS_S (uint32)((ins>>21)&0x1F)
#define INS_T (uint32)((ins>>16)&0x1F)
#define INS_D (uint32)((ins>>11)&0x1F)
#define INS_H (uint32)((ins>>6)&0x1F)
#define INS_I (uint32)(ins&0xFFFF)
#define SIGNED16(x) ((sint32)(((sint16)(x))))
#define REL_I (pc+4+(((sint32)(SIGNED16(INS_I)))<<2))
#define ABS_I ((pc&0xF0000000)|((ins<<2)&0x0FFFFFFC))
#define RICH_CODE_REGISTER ('R'-64)
#define RICH_CODE_ADDRESS ('A'-64)
/////////////////////////////////////////////////////////////////////////////
//
// Returns negative on unknown instuction
// dest must have 256 bytes available
//
sint32 EMU_CALL r3000dis(char *dest, uint32 rich, uint32 pc, uint32 ins) {
sint32 delayslot = 0;
static const char *regname[32] = {
"$0" ,"$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 *C0regname[32] = {
"C0_0","C0_1","C0_2","C0_3","C0_4","C0_5","C0_6","C0_7",
"C0_8","C0_9","C0_10","C0_11","C0_status","C0_cause","C0_epc","C0_prid",
"C0_16","C0_17","C0_18","C0_19","C0_20","C0_21","C0_22","C0_23",
"C0_24","C0_25","C0_26","C0_27","C0_28","C0_29","C0_30","C0_31"
};
const char *fmt;
int j, col = 0;
if(ins < 0x04000000) {
switch(ins & 0x3F) {
case 0x00:
if(!ins) fmt = "nop"; goto ok;
if(INS_D==INS_T) fmt = "sll D,H"; goto ok;
if(!INS_H) fmt = "move D,T"; goto ok;
fmt = "sll D,T,H"; goto ok;
case 0x02:
if(INS_D==INS_T) fmt = "srl D,H"; goto ok;
if(!INS_H) fmt = "move D,T"; goto ok;
fmt = "srl D,T,H"; goto ok;
case 0x03:
if(INS_D==INS_T) fmt = "sra D,H"; goto ok;
if(!INS_H) fmt = "move D,T"; goto ok;
fmt = "sra D,T,H"; goto ok;
case 0x04:
if(INS_D==INS_T) fmt = "sllv D,S"; goto ok;
if(!INS_S) fmt = "move D,T"; goto ok;
fmt = "sllv D,T,S"; goto ok;
case 0x06:
if(INS_D==INS_T) fmt = "srlv D,S"; goto ok;
if(!INS_S) fmt = "move D,T"; goto ok;
fmt = "srlv D,T,S"; goto ok;
case 0x07:
if(INS_D==INS_T) fmt = "srav D,S"; goto ok;
if(!INS_S) fmt = "move D,T"; goto ok;
fmt = "srav D,T,S"; goto ok;
case 0x08: fmt = "jr S"; goto okdelayslot;
case 0x09:
if(INS_D==31) fmt = "jalr S"; goto okdelayslot;
fmt = "jalr D,S"; goto okdelayslot;
case 0x0C: fmt = "syscall"; goto ok;
case 0x10: fmt = "mfhi D"; goto ok;
case 0x11: fmt = "mthi S"; goto ok;
case 0x12: fmt = "mflo D"; goto ok;
case 0x13: fmt = "mtlo S"; goto ok;
case 0x18: fmt = "mult S,T"; goto ok;
case 0x19: fmt = "multu S,T"; goto ok;
case 0x1A: fmt = "div S,T"; goto ok;
case 0x1B: fmt = "divu S,T"; goto ok;
case 0x20:
if(INS_D==INS_S) fmt = "add D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
if(!INS_S) fmt = "move D,T"; goto ok;
fmt = "add D,S,T"; goto ok;
case 0x21:
if(INS_D==INS_S) fmt = "addu D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
if(!INS_S) fmt = "move D,T"; goto ok;
fmt = "addu D,S,T"; goto ok;
case 0x22:
if(INS_D==INS_S) fmt = "sub D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
if(!INS_S) {
if(INS_D==INS_T) fmt = "neg D"; goto ok;
fmt = "neg D,T"; goto ok;
}
fmt = "sub D,S,T"; goto ok;
case 0x23:
if(INS_D==INS_S) fmt = "subu D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
if(!INS_S) {
if(INS_D==INS_T) fmt = "negu D"; goto ok;
fmt = "negu D,T"; goto ok;
}
fmt = "subu D,S,T"; goto ok;
case 0x24:
if(INS_D==INS_S) fmt = "and D,T"; goto ok;
fmt = "and D,S,T"; goto ok;
case 0x25:
if(INS_D==INS_S) fmt = "or D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
fmt = "or D,S,T"; goto ok;
case 0x26:
if(INS_D==INS_S) fmt = "xor D,T"; goto ok;
if(!INS_T) fmt = "move D,S"; goto ok;
fmt = "xor D,S,T"; goto ok;
case 0x27:
if(!INS_T) {
if(INS_D==INS_S) fmt = "not D"; goto ok;
fmt = "not D,S"; goto ok;
} else if(!INS_S) {
if(INS_D==INS_T) fmt = "not D"; goto ok;
fmt = "not D,T"; goto ok;
} else {
if(INS_D==INS_S) fmt = "nor D,T"; goto ok;
fmt = "nor D,S,T"; goto ok;
}
case 0x2A: fmt = "slt D,S,T"; goto ok;
case 0x2B: fmt = "sltu D,S,T"; goto ok;
default: goto invalid;
}
} else {
switch(ins >> 26) {
case 0x01:
switch(INS_T) {
case 0x00: fmt = "bltz S,B"; goto okdelayslot;
case 0x01: fmt = "bgez S,B"; goto okdelayslot;
case 0x10: fmt = "bltzal S,B"; goto okdelayslot;
case 0x11: fmt = "bgezal S,B"; goto okdelayslot;
default: goto invalid;
}
break;
case 0x02: fmt = "j J"; goto okdelayslot;
case 0x03: fmt = "jal J"; goto okdelayslot;
case 0x04:
if(INS_S==INS_T) fmt = "b B"; goto okdelayslot;
fmt = "beq S,T,B"; goto okdelayslot;
case 0x05: fmt = "bne S,T,B"; goto okdelayslot;
case 0x06:
if(!INS_S) fmt = "b B"; goto okdelayslot;
fmt = "blez S,B"; goto okdelayslot;
case 0x07: fmt = "bgtz S,B"; goto okdelayslot;
case 0x08:
if(INS_T==INS_S) fmt = "addi T,I"; goto ok;
if(!INS_S) fmt = "li T,I"; goto ok;
if(!INS_I) fmt = "move T,S"; goto ok;
fmt = "addi T,S,I"; goto ok;
case 0x09:
if(INS_T==INS_S) fmt = "addiu T,I"; goto ok;
if(!INS_S) fmt = "li T,I"; goto ok;
if(!INS_I) fmt = "move T,S"; goto ok;
fmt = "addiu T,S,I"; goto ok;
case 0x0A: fmt = "slti T,S,I"; goto ok;
case 0x0B: fmt = "sltiu T,S,I"; goto ok;
case 0x0C:
if(INS_T==INS_S) fmt = "andi T,I"; goto ok;
fmt = "andi T,S,I"; goto ok;
case 0x0D:
if(INS_T==INS_S) fmt = "ori T,I"; goto ok;
fmt = "ori T,S,I"; goto ok;
case 0x0E:
if(INS_T==INS_S) fmt = "xori T,I"; goto ok;
fmt = "xori T,S,I"; goto ok;
case 0x0F: fmt = "lui T,I"; goto ok;
case 0x10:
switch(INS_S) {
case 0x00: fmt = "mfc0 T,CD"; goto ok;
case 0x04: fmt = "mtc0 T,CD"; goto ok;
case 0x10: fmt = "rfe"; goto ok;
default: goto invalid;
}
break;
case 0x20:
if(!INS_I) fmt = "lb T,(S)"; goto ok;
fmt = "lb T,I(S)"; goto ok;
case 0x21:
if(!INS_I) fmt = "lh T,(S)"; goto ok;
fmt = "lh T,I(S)"; goto ok;
case 0x22:
if(!INS_I) fmt = "lwl T,(S)"; goto ok;
fmt = "lwl T,I(S)"; goto ok;
case 0x23:
if(!INS_I) fmt = "lw T,(S)"; goto ok;
fmt = "lw T,I(S)"; goto ok;
case 0x24:
if(!INS_I) fmt = "lbu T,(S)"; goto ok;
fmt = "lbu T,I(S)"; goto ok;
case 0x25:
if(!INS_I) fmt = "lhu T,(S)"; goto ok;
fmt = "lhu T,I(S)"; goto ok;
case 0x26:
if(!INS_I) fmt = "lwr T,(S)"; goto ok;
fmt = "lwr T,I(S)"; goto ok;
case 0x28:
if(!INS_I) fmt = "sb T,(S)"; goto ok;
fmt = "sb T,I(S)"; goto ok;
case 0x29:
if(!INS_I) fmt = "sh T,(S)"; goto ok;
fmt = "sh T,I(S)"; goto ok;
case 0x2A:
if(!INS_I) fmt = "swl T,(S)"; goto ok;
fmt = "swl T,I(S)"; goto ok;
case 0x2B:
if(!INS_I) fmt = "sw T,(S)"; goto ok;
fmt = "sw T,I(S)"; goto ok;
case 0x2E:
if(!INS_I) fmt = "swr T,(S)"; goto ok;
fmt = "swr T,I(S)"; goto ok;
default: goto invalid;
}
}
invalid:
*dest = 0;
return -1;
okdelayslot:
delayslot = 1;
ok:
for(; *fmt; fmt++) {
switch(*fmt) {
case 'S': if(rich) dest[col++] = RICH_CODE_REGISTER; strcpy(dest+col, regname[INS_S]); while(dest[col]) col++; break;
case 'T': if(rich) dest[col++] = RICH_CODE_REGISTER; strcpy(dest+col, regname[INS_T]); while(dest[col]) col++; break;
case 'D': if(rich) dest[col++] = RICH_CODE_REGISTER; strcpy(dest+col, regname[INS_D]); while(dest[col]) col++; break;
case 'H': sprintf(dest+col, "%d", INS_H); while(dest[col]) col++; break;
case 'I': sprintf(dest+col, "0x%04X", INS_I); while(dest[col]) col++; break;
case 'B': if(rich) dest[col++] = RICH_CODE_ADDRESS; sprintf(dest+col, "0x%08X", REL_I); while(dest[col]) col++; break;
case 'J': if(rich) dest[col++] = RICH_CODE_ADDRESS; sprintf(dest+col, "0x%08X", ABS_I); while(dest[col]) col++; break;
case 'C':
fmt++;
if(rich) dest[col++] = RICH_CODE_REGISTER;
j = 0;
switch(*fmt) {
case 'D': j = INS_D; break;
}
strcpy(dest+col, C0regname[j]); while(dest[col]) col++;
break;
case ' ': while(col < 6) dest[col++] = ' '; break;
case ',': dest[col++] = ','; dest[col++] = ' '; break;
default: dest[col++] = *fmt; break;
}
}
dest[col] = 0;
return delayslot ? 1 : 0;
}
/////////////////////////////////////////////////////////////////////////////