| Index: src/mips64/disasm-mips64.cc
|
| diff --git a/src/mips64/disasm-mips64.cc b/src/mips64/disasm-mips64.cc
|
| index 3f0642db2c02d691fcd5fcba8d8b96c50410e62e..fc83955fe350ded4f5dbf8b95bc90aaee6411cc5 100644
|
| --- a/src/mips64/disasm-mips64.cc
|
| +++ b/src/mips64/disasm-mips64.cc
|
| @@ -101,8 +101,23 @@ class Decoder {
|
| int DecodeBreakInstr(Instruction* instr);
|
|
|
| // Each of these functions decodes one particular instruction type.
|
| + void DecodeTypeRegisterDRsType(Instruction* instr);
|
| + void DecodeTypeRegisterLRsType(Instruction* instr);
|
| + void DecodeTypeRegisterSPECIAL(Instruction* instr);
|
| + void DecodeTypeRegisterSPECIAL2(Instruction* instr);
|
| + void DecodeTypeRegisterSPECIAL3(Instruction* instr);
|
| + void DecodeTypeRegisterCOP1(Instruction* instr);
|
| + void DecodeTypeRegisterCOP1X(Instruction* instr);
|
| int DecodeTypeRegister(Instruction* instr);
|
| +
|
| + void DecodeTypeImmediateCOP1W(Instruction* instr);
|
| + void DecodeTypeImmediateCOP1L(Instruction* instr);
|
| + void DecodeTypeImmediateCOP1S(Instruction* instr);
|
| + void DecodeTypeImmediateCOP1D(Instruction* instr);
|
| + void DecodeTypeImmediateCOP1(Instruction* instr);
|
| + void DecodeTypeImmediateREGIMM(Instruction* instr);
|
| void DecodeTypeImmediate(Instruction* instr);
|
| +
|
| void DecodeTypeJump(Instruction* instr);
|
|
|
| const disasm::NameConverter& converter_;
|
| @@ -474,503 +489,547 @@ int Decoder::DecodeBreakInstr(Instruction* instr) {
|
| }
|
|
|
|
|
| -int Decoder::DecodeTypeRegister(Instruction* instr) {
|
| - switch (instr->OpcodeFieldRaw()) {
|
| - case COP1: // Coprocessor instructions.
|
| - switch (instr->RsFieldRaw()) {
|
| - case MFC1:
|
| - Format(instr, "mfc1 'rt, 'fs");
|
| - break;
|
| - case DMFC1:
|
| - Format(instr, "dmfc1 'rt, 'fs");
|
| - break;
|
| - case MFHC1:
|
| - Format(instr, "mfhc1 'rt, 'fs");
|
| - break;
|
| - case MTC1:
|
| - Format(instr, "mtc1 'rt, 'fs");
|
| - break;
|
| - case DMTC1:
|
| - Format(instr, "dmtc1 'rt, 'fs");
|
| - break;
|
| - // These are called "fs" too, although they are not FPU registers.
|
| - case CTC1:
|
| - Format(instr, "ctc1 'rt, 'fs");
|
| - break;
|
| - case CFC1:
|
| - Format(instr, "cfc1 'rt, 'fs");
|
| - break;
|
| - case MTHC1:
|
| - Format(instr, "mthc1 'rt, 'fs");
|
| - break;
|
| - case D:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case ADD_D:
|
| - Format(instr, "add.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case SUB_D:
|
| - Format(instr, "sub.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case MUL_D:
|
| - Format(instr, "mul.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case DIV_D:
|
| - Format(instr, "div.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case ABS_D:
|
| - Format(instr, "abs.d 'fd, 'fs");
|
| - break;
|
| - case MOV_D:
|
| - Format(instr, "mov.d 'fd, 'fs");
|
| - break;
|
| - case NEG_D:
|
| - Format(instr, "neg.d 'fd, 'fs");
|
| - break;
|
| - case SQRT_D:
|
| - Format(instr, "sqrt.d 'fd, 'fs");
|
| - break;
|
| - case CVT_W_D:
|
| - Format(instr, "cvt.w.d 'fd, 'fs");
|
| - break;
|
| - case CVT_L_D:
|
| - Format(instr, "cvt.l.d 'fd, 'fs");
|
| - break;
|
| - case TRUNC_W_D:
|
| - Format(instr, "trunc.w.d 'fd, 'fs");
|
| - break;
|
| - case TRUNC_L_D:
|
| - Format(instr, "trunc.l.d 'fd, 'fs");
|
| - break;
|
| - case ROUND_W_D:
|
| - Format(instr, "round.w.d 'fd, 'fs");
|
| - break;
|
| - case ROUND_L_D:
|
| - Format(instr, "round.l.d 'fd, 'fs");
|
| - break;
|
| - case FLOOR_W_D:
|
| - Format(instr, "floor.w.d 'fd, 'fs");
|
| - break;
|
| - case FLOOR_L_D:
|
| - Format(instr, "floor.l.d 'fd, 'fs");
|
| - break;
|
| - case CEIL_W_D:
|
| - Format(instr, "ceil.w.d 'fd, 'fs");
|
| - break;
|
| - case CEIL_L_D:
|
| - Format(instr, "ceil.l.d 'fd, 'fs");
|
| - break;
|
| - case CVT_S_D:
|
| - Format(instr, "cvt.s.d 'fd, 'fs");
|
| - break;
|
| - case C_F_D:
|
| - Format(instr, "c.f.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_UN_D:
|
| - Format(instr, "c.un.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_EQ_D:
|
| - Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_UEQ_D:
|
| - Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_OLT_D:
|
| - Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_ULT_D:
|
| - Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_OLE_D:
|
| - Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - case C_ULE_D:
|
| - Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
|
| - break;
|
| - default:
|
| - Format(instr, "unknown.cop1.d");
|
| - break;
|
| - }
|
| - break;
|
| - case W:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case CVT_D_W: // Convert word to double.
|
| - Format(instr, "cvt.d.w 'fd, 'fs");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - case L:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case CVT_D_L:
|
| - Format(instr, "cvt.d.l 'fd, 'fs");
|
| - break;
|
| - case CVT_S_L:
|
| - Format(instr, "cvt.s.l 'fd, 'fs");
|
| - break;
|
| - case CMP_UN:
|
| - Format(instr, "cmp.un.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_EQ:
|
| - Format(instr, "cmp.eq.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_UEQ:
|
| - Format(instr, "cmp.ueq.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_LT:
|
| - Format(instr, "cmp.lt.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_ULT:
|
| - Format(instr, "cmp.ult.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_LE:
|
| - Format(instr, "cmp.le.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_ULE:
|
| - Format(instr, "cmp.ule.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_OR:
|
| - Format(instr, "cmp.or.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_UNE:
|
| - Format(instr, "cmp.une.d 'fd, 'fs, 'ft");
|
| - break;
|
| - case CMP_NE:
|
| - Format(instr, "cmp.ne.d 'fd, 'fs, 'ft");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| +void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case SELEQZ_C:
|
| + Format(instr, "seleqz.D 'ft, 'fs, 'fd");
|
| break;
|
| - case COP1X:
|
| + case SELNEZ_C:
|
| + Format(instr, "selnez.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case ADD_D:
|
| + Format(instr, "add.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case SUB_D:
|
| + Format(instr, "sub.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case MUL_D:
|
| + Format(instr, "mul.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case DIV_D:
|
| + Format(instr, "div.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case ABS_D:
|
| + Format(instr, "abs.d 'fd, 'fs");
|
| + break;
|
| + case MOV_D:
|
| + Format(instr, "mov.d 'fd, 'fs");
|
| + break;
|
| + case NEG_D:
|
| + Format(instr, "neg.d 'fd, 'fs");
|
| + break;
|
| + case SQRT_D:
|
| + Format(instr, "sqrt.d 'fd, 'fs");
|
| + break;
|
| + case CVT_W_D:
|
| + Format(instr, "cvt.w.d 'fd, 'fs");
|
| + break;
|
| + case CVT_L_D:
|
| + Format(instr, "cvt.l.d 'fd, 'fs");
|
| + break;
|
| + case TRUNC_W_D:
|
| + Format(instr, "trunc.w.d 'fd, 'fs");
|
| + break;
|
| + case TRUNC_L_D:
|
| + Format(instr, "trunc.l.d 'fd, 'fs");
|
| + break;
|
| + case ROUND_W_D:
|
| + Format(instr, "round.w.d 'fd, 'fs");
|
| + break;
|
| + case ROUND_L_D:
|
| + Format(instr, "round.l.d 'fd, 'fs");
|
| + break;
|
| + case FLOOR_W_D:
|
| + Format(instr, "floor.w.d 'fd, 'fs");
|
| + break;
|
| + case FLOOR_L_D:
|
| + Format(instr, "floor.l.d 'fd, 'fs");
|
| + break;
|
| + case CEIL_W_D:
|
| + Format(instr, "ceil.w.d 'fd, 'fs");
|
| + break;
|
| + case CEIL_L_D:
|
| + Format(instr, "ceil.l.d 'fd, 'fs");
|
| + break;
|
| + case CVT_S_D:
|
| + Format(instr, "cvt.s.d 'fd, 'fs");
|
| + break;
|
| + case C_F_D:
|
| + Format(instr, "c.f.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_UN_D:
|
| + Format(instr, "c.un.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_EQ_D:
|
| + Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_UEQ_D:
|
| + Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_OLT_D:
|
| + Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_ULT_D:
|
| + Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_OLE_D:
|
| + Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + case C_ULE_D:
|
| + Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
|
| + break;
|
| + default:
|
| + Format(instr, "unknown.cop1.d");
|
| + break;
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case CVT_D_L:
|
| + Format(instr, "cvt.d.l 'fd, 'fs");
|
| + break;
|
| + case CVT_S_L:
|
| + Format(instr, "cvt.s.l 'fd, 'fs");
|
| + break;
|
| + case CMP_UN:
|
| + Format(instr, "cmp.un.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_EQ:
|
| + Format(instr, "cmp.eq.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_UEQ:
|
| + Format(instr, "cmp.ueq.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_LT:
|
| + Format(instr, "cmp.lt.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_ULT:
|
| + Format(instr, "cmp.ult.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_LE:
|
| + Format(instr, "cmp.le.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_ULE:
|
| + Format(instr, "cmp.ule.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_OR:
|
| + Format(instr, "cmp.or.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_UNE:
|
| + Format(instr, "cmp.une.d 'fd, 'fs, 'ft");
|
| + break;
|
| + case CMP_NE:
|
| + Format(instr, "cmp.ne.d 'fd, 'fs, 'ft");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegisterCOP1(Instruction* instr) {
|
| + switch (instr->RsFieldRaw()) {
|
| + case MFC1:
|
| + Format(instr, "mfc1 'rt, 'fs");
|
| + break;
|
| + case DMFC1:
|
| + Format(instr, "dmfc1 'rt, 'fs");
|
| + break;
|
| + case MFHC1:
|
| + Format(instr, "mfhc1 'rt, 'fs");
|
| + break;
|
| + case MTC1:
|
| + Format(instr, "mtc1 'rt, 'fs");
|
| + break;
|
| + case DMTC1:
|
| + Format(instr, "dmtc1 'rt, 'fs");
|
| + break;
|
| + // These are called "fs" too, although they are not FPU registers.
|
| + case CTC1:
|
| + Format(instr, "ctc1 'rt, 'fs");
|
| + break;
|
| + case CFC1:
|
| + Format(instr, "cfc1 'rt, 'fs");
|
| + break;
|
| + case MTHC1:
|
| + Format(instr, "mthc1 'rt, 'fs");
|
| + break;
|
| + case D:
|
| + DecodeTypeRegisterDRsType(instr);
|
| + break;
|
| + case W:
|
| switch (instr->FunctionFieldRaw()) {
|
| - case MADD_D:
|
| - Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
|
| + case CVT_D_W: // Convert word to double.
|
| + Format(instr, "cvt.d.w 'fd, 'fs");
|
| break;
|
| default:
|
| UNREACHABLE();
|
| }
|
| break;
|
| - case SPECIAL:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case JR:
|
| - Format(instr, "jr 'rs");
|
| - break;
|
| - case JALR:
|
| - Format(instr, "jalr 'rs");
|
| - break;
|
| - case SLL:
|
| - if (0x0 == static_cast<int>(instr->InstructionBits()))
|
| - Format(instr, "nop");
|
| - else
|
| - Format(instr, "sll 'rd, 'rt, 'sa");
|
| - break;
|
| - case DSLL:
|
| - Format(instr, "dsll 'rd, 'rt, 'sa");
|
| - break;
|
| - case D_MUL_MUH: // Equals to DMUL.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "dmult 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == MUL_OP) {
|
| - Format(instr, "dmul 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "dmuh 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case DSLL32:
|
| - Format(instr, "dsll32 'rd, 'rt, 'sa");
|
| - break;
|
| - case SRL:
|
| - if (instr->RsValue() == 0) {
|
| - Format(instr, "srl 'rd, 'rt, 'sa");
|
| - } else {
|
| - if (kArchVariant == kMips64r2) {
|
| - Format(instr, "rotr 'rd, 'rt, 'sa");
|
| - } else {
|
| - Unknown(instr);
|
| - }
|
| - }
|
| - break;
|
| - case DSRL:
|
| - if (instr->RsValue() == 0) {
|
| - Format(instr, "dsrl 'rd, 'rt, 'sa");
|
| - } else {
|
| - if (kArchVariant == kMips64r2) {
|
| - Format(instr, "drotr 'rd, 'rt, 'sa");
|
| - } else {
|
| - Unknown(instr);
|
| - }
|
| - }
|
| - break;
|
| - case DSRL32:
|
| - Format(instr, "dsrl32 'rd, 'rt, 'sa");
|
| - break;
|
| - case SRA:
|
| - Format(instr, "sra 'rd, 'rt, 'sa");
|
| - break;
|
| - case DSRA:
|
| - Format(instr, "dsra 'rd, 'rt, 'sa");
|
| - break;
|
| - case DSRA32:
|
| - Format(instr, "dsra32 'rd, 'rt, 'sa");
|
| - break;
|
| - case SLLV:
|
| - Format(instr, "sllv 'rd, 'rt, 'rs");
|
| - break;
|
| - case DSLLV:
|
| - Format(instr, "dsllv 'rd, 'rt, 'rs");
|
| - break;
|
| - case SRLV:
|
| - if (instr->SaValue() == 0) {
|
| - Format(instr, "srlv 'rd, 'rt, 'rs");
|
| - } else {
|
| - if (kArchVariant == kMips64r2) {
|
| - Format(instr, "rotrv 'rd, 'rt, 'rs");
|
| - } else {
|
| - Unknown(instr);
|
| - }
|
| - }
|
| - break;
|
| - case DSRLV:
|
| - if (instr->SaValue() == 0) {
|
| - Format(instr, "dsrlv 'rd, 'rt, 'rs");
|
| - } else {
|
| - if (kArchVariant == kMips64r2) {
|
| - Format(instr, "drotrv 'rd, 'rt, 'rs");
|
| - } else {
|
| - Unknown(instr);
|
| - }
|
| - }
|
| - break;
|
| - case SRAV:
|
| - Format(instr, "srav 'rd, 'rt, 'rs");
|
| - break;
|
| - case DSRAV:
|
| - Format(instr, "dsrav 'rd, 'rt, 'rs");
|
| - break;
|
| - case MFHI:
|
| - if (instr->Bits(25, 16) == 0) {
|
| - Format(instr, "mfhi 'rd");
|
| - } else {
|
| - if ((instr->FunctionFieldRaw() == CLZ_R6)
|
| - && (instr->FdValue() == 1)) {
|
| - Format(instr, "clz 'rd, 'rs");
|
| - } else if ((instr->FunctionFieldRaw() == CLO_R6)
|
| - && (instr->FdValue() == 1)) {
|
| - Format(instr, "clo 'rd, 'rs");
|
| - }
|
| - }
|
| - break;
|
| - case MFLO:
|
| - Format(instr, "mflo 'rd");
|
| - break;
|
| - case D_MUL_MUH_U: // Equals to DMULTU.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "dmultu 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == MUL_OP) {
|
| - Format(instr, "dmulu 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "dmuhu 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case MULT: // @Mips64r6 == MUL_MUH.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "mult 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == MUL_OP) {
|
| - Format(instr, "mul 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "muh 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case MULTU: // @Mips64r6 == MUL_MUH_U.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "multu 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == MUL_OP) {
|
| - Format(instr, "mulu 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "muhu 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| + case L:
|
| + DecodeTypeRegisterLRsType(instr);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
|
|
| - break;
|
| - case DIV: // @Mips64r6 == DIV_MOD.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "div 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == DIV_OP) {
|
| - Format(instr, "div 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "mod 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case DDIV: // @Mips64r6 == D_DIV_MOD.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "ddiv 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == DIV_OP) {
|
| - Format(instr, "ddiv 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "dmod 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case DIVU: // @Mips64r6 == DIV_MOD_U.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "divu 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == DIV_OP) {
|
| - Format(instr, "divu 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "modu 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case DDIVU: // @Mips64r6 == D_DIV_MOD_U.
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "ddivu 'rs, 'rt");
|
| - } else {
|
| - if (instr->SaValue() == DIV_OP) {
|
| - Format(instr, "ddivu 'rd, 'rs, 'rt");
|
| - } else {
|
| - Format(instr, "dmodu 'rd, 'rs, 'rt");
|
| - }
|
| - }
|
| - break;
|
| - case ADD:
|
| - Format(instr, "add 'rd, 'rs, 'rt");
|
| - break;
|
| - case DADD:
|
| - Format(instr, "dadd 'rd, 'rs, 'rt");
|
| - break;
|
| - case ADDU:
|
| - Format(instr, "addu 'rd, 'rs, 'rt");
|
| - break;
|
| - case DADDU:
|
| - Format(instr, "daddu 'rd, 'rs, 'rt");
|
| - break;
|
| - case SUB:
|
| - Format(instr, "sub 'rd, 'rs, 'rt");
|
| - break;
|
| - case DSUB:
|
| - Format(instr, "dsub 'rd, 'rs, 'rt");
|
| - break;
|
| - case SUBU:
|
| - Format(instr, "subu 'rd, 'rs, 'rt");
|
| - break;
|
| - case DSUBU:
|
| - Format(instr, "dsubu 'rd, 'rs, 'rt");
|
| - break;
|
| - case AND:
|
| - Format(instr, "and 'rd, 'rs, 'rt");
|
| - break;
|
| - case OR:
|
| - if (0 == instr->RsValue()) {
|
| - Format(instr, "mov 'rd, 'rt");
|
| - } else if (0 == instr->RtValue()) {
|
| - Format(instr, "mov 'rd, 'rs");
|
| - } else {
|
| - Format(instr, "or 'rd, 'rs, 'rt");
|
| - }
|
| - break;
|
| - case XOR:
|
| - Format(instr, "xor 'rd, 'rs, 'rt");
|
| - break;
|
| - case NOR:
|
| - Format(instr, "nor 'rd, 'rs, 'rt");
|
| - break;
|
| - case SLT:
|
| - Format(instr, "slt 'rd, 'rs, 'rt");
|
| - break;
|
| - case SLTU:
|
| - Format(instr, "sltu 'rd, 'rs, 'rt");
|
| - break;
|
| - case BREAK:
|
| - return DecodeBreakInstr(instr);
|
| - case TGE:
|
| - Format(instr, "tge 'rs, 'rt, code: 'code");
|
| - break;
|
| - case TGEU:
|
| - Format(instr, "tgeu 'rs, 'rt, code: 'code");
|
| - break;
|
| - case TLT:
|
| - Format(instr, "tlt 'rs, 'rt, code: 'code");
|
| - break;
|
| - case TLTU:
|
| - Format(instr, "tltu 'rs, 'rt, code: 'code");
|
| - break;
|
| - case TEQ:
|
| - Format(instr, "teq 'rs, 'rt, code: 'code");
|
| - break;
|
| - case TNE:
|
| - Format(instr, "tne 'rs, 'rt, code: 'code");
|
| - break;
|
| - case MOVZ:
|
| - Format(instr, "movz 'rd, 'rs, 'rt");
|
| - break;
|
| - case MOVN:
|
| - Format(instr, "movn 'rd, 'rs, 'rt");
|
| - break;
|
| - case MOVCI:
|
| - if (instr->Bit(16)) {
|
| - Format(instr, "movt 'rd, 'rs, 'bc");
|
| - } else {
|
| - Format(instr, "movf 'rd, 'rs, 'bc");
|
| - }
|
| - break;
|
| - case SELEQZ_S:
|
| - Format(instr, "seleqz 'rd, 'rs, 'rt");
|
| - break;
|
| - case SELNEZ_S:
|
| - Format(instr, "selnez 'rd, 'rs, 'rt");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| +
|
| +void Decoder::DecodeTypeRegisterCOP1X(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case MADD_D:
|
| + Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case JR:
|
| + Format(instr, "jr 'rs");
|
| + break;
|
| + case JALR:
|
| + Format(instr, "jalr 'rs");
|
| + break;
|
| + case SLL:
|
| + if (0x0 == static_cast<int>(instr->InstructionBits()))
|
| + Format(instr, "nop");
|
| + else
|
| + Format(instr, "sll 'rd, 'rt, 'sa");
|
| + break;
|
| + case DSLL:
|
| + Format(instr, "dsll 'rd, 'rt, 'sa");
|
| + break;
|
| + case D_MUL_MUH: // Equals to DMUL.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "dmult 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == MUL_OP) {
|
| + Format(instr, "dmul 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "dmuh 'rd, 'rs, 'rt");
|
| + }
|
| }
|
| break;
|
| - case SPECIAL2:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case MUL:
|
| - Format(instr, "mul 'rd, 'rs, 'rt");
|
| - break;
|
| - case CLZ:
|
| - if (kArchVariant != kMips64r6) {
|
| - Format(instr, "clz 'rd, 'rs");
|
| - }
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| + case DSLL32:
|
| + Format(instr, "dsll32 'rd, 'rt, 'sa");
|
| + break;
|
| + case SRL:
|
| + if (instr->RsValue() == 0) {
|
| + Format(instr, "srl 'rd, 'rt, 'sa");
|
| + } else {
|
| + if (kArchVariant == kMips64r2) {
|
| + Format(instr, "rotr 'rd, 'rt, 'sa");
|
| + } else {
|
| + Unknown(instr);
|
| + }
|
| }
|
| break;
|
| - case SPECIAL3:
|
| - switch (instr->FunctionFieldRaw()) {
|
| - case INS: {
|
| - Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
|
| - break;
|
| + case DSRL:
|
| + if (instr->RsValue() == 0) {
|
| + Format(instr, "dsrl 'rd, 'rt, 'sa");
|
| + } else {
|
| + if (kArchVariant == kMips64r2) {
|
| + Format(instr, "drotr 'rd, 'rt, 'sa");
|
| + } else {
|
| + Unknown(instr);
|
| }
|
| - case EXT: {
|
| - Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
|
| - break;
|
| + }
|
| + break;
|
| + case DSRL32:
|
| + Format(instr, "dsrl32 'rd, 'rt, 'sa");
|
| + break;
|
| + case SRA:
|
| + Format(instr, "sra 'rd, 'rt, 'sa");
|
| + break;
|
| + case DSRA:
|
| + Format(instr, "dsra 'rd, 'rt, 'sa");
|
| + break;
|
| + case DSRA32:
|
| + Format(instr, "dsra32 'rd, 'rt, 'sa");
|
| + break;
|
| + case SLLV:
|
| + Format(instr, "sllv 'rd, 'rt, 'rs");
|
| + break;
|
| + case DSLLV:
|
| + Format(instr, "dsllv 'rd, 'rt, 'rs");
|
| + break;
|
| + case SRLV:
|
| + if (instr->SaValue() == 0) {
|
| + Format(instr, "srlv 'rd, 'rt, 'rs");
|
| + } else {
|
| + if (kArchVariant == kMips64r2) {
|
| + Format(instr, "rotrv 'rd, 'rt, 'rs");
|
| + } else {
|
| + Unknown(instr);
|
| }
|
| - case DEXT: {
|
| - Format(instr, "dext 'rt, 'rs, 'sa, 'ss1");
|
| - break;
|
| + }
|
| + break;
|
| + case DSRLV:
|
| + if (instr->SaValue() == 0) {
|
| + Format(instr, "dsrlv 'rd, 'rt, 'rs");
|
| + } else {
|
| + if (kArchVariant == kMips64r2) {
|
| + Format(instr, "drotrv 'rd, 'rt, 'rs");
|
| + } else {
|
| + Unknown(instr);
|
| + }
|
| + }
|
| + break;
|
| + case SRAV:
|
| + Format(instr, "srav 'rd, 'rt, 'rs");
|
| + break;
|
| + case DSRAV:
|
| + Format(instr, "dsrav 'rd, 'rt, 'rs");
|
| + break;
|
| + case MFHI:
|
| + if (instr->Bits(25, 16) == 0) {
|
| + Format(instr, "mfhi 'rd");
|
| + } else {
|
| + if ((instr->FunctionFieldRaw() == CLZ_R6) && (instr->FdValue() == 1)) {
|
| + Format(instr, "clz 'rd, 'rs");
|
| + } else if ((instr->FunctionFieldRaw() == CLO_R6) &&
|
| + (instr->FdValue() == 1)) {
|
| + Format(instr, "clo 'rd, 'rs");
|
| }
|
| + }
|
| + break;
|
| + case MFLO:
|
| + Format(instr, "mflo 'rd");
|
| + break;
|
| + case D_MUL_MUH_U: // Equals to DMULTU.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "dmultu 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == MUL_OP) {
|
| + Format(instr, "dmulu 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "dmuhu 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case MULT: // @Mips64r6 == MUL_MUH.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "mult 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == MUL_OP) {
|
| + Format(instr, "mul 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "muh 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case MULTU: // @Mips64r6 == MUL_MUH_U.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "multu 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == MUL_OP) {
|
| + Format(instr, "mulu 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "muhu 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| +
|
| + break;
|
| + case DIV: // @Mips64r6 == DIV_MOD.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "div 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == DIV_OP) {
|
| + Format(instr, "div 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "mod 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case DDIV: // @Mips64r6 == D_DIV_MOD.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "ddiv 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == DIV_OP) {
|
| + Format(instr, "ddiv 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "dmod 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case DIVU: // @Mips64r6 == DIV_MOD_U.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "divu 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == DIV_OP) {
|
| + Format(instr, "divu 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "modu 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case DDIVU: // @Mips64r6 == D_DIV_MOD_U.
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "ddivu 'rs, 'rt");
|
| + } else {
|
| + if (instr->SaValue() == DIV_OP) {
|
| + Format(instr, "ddivu 'rd, 'rs, 'rt");
|
| + } else {
|
| + Format(instr, "dmodu 'rd, 'rs, 'rt");
|
| + }
|
| + }
|
| + break;
|
| + case ADD:
|
| + Format(instr, "add 'rd, 'rs, 'rt");
|
| + break;
|
| + case DADD:
|
| + Format(instr, "dadd 'rd, 'rs, 'rt");
|
| + break;
|
| + case ADDU:
|
| + Format(instr, "addu 'rd, 'rs, 'rt");
|
| + break;
|
| + case DADDU:
|
| + Format(instr, "daddu 'rd, 'rs, 'rt");
|
| + break;
|
| + case SUB:
|
| + Format(instr, "sub 'rd, 'rs, 'rt");
|
| + break;
|
| + case DSUB:
|
| + Format(instr, "dsub 'rd, 'rs, 'rt");
|
| + break;
|
| + case SUBU:
|
| + Format(instr, "subu 'rd, 'rs, 'rt");
|
| + break;
|
| + case DSUBU:
|
| + Format(instr, "dsubu 'rd, 'rs, 'rt");
|
| + break;
|
| + case AND:
|
| + Format(instr, "and 'rd, 'rs, 'rt");
|
| + break;
|
| + case OR:
|
| + if (0 == instr->RsValue()) {
|
| + Format(instr, "mov 'rd, 'rt");
|
| + } else if (0 == instr->RtValue()) {
|
| + Format(instr, "mov 'rd, 'rs");
|
| + } else {
|
| + Format(instr, "or 'rd, 'rs, 'rt");
|
| + }
|
| + break;
|
| + case XOR:
|
| + Format(instr, "xor 'rd, 'rs, 'rt");
|
| + break;
|
| + case NOR:
|
| + Format(instr, "nor 'rd, 'rs, 'rt");
|
| + break;
|
| + case SLT:
|
| + Format(instr, "slt 'rd, 'rs, 'rt");
|
| + break;
|
| + case SLTU:
|
| + Format(instr, "sltu 'rd, 'rs, 'rt");
|
| + break;
|
| + case TGE:
|
| + Format(instr, "tge 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TGEU:
|
| + Format(instr, "tgeu 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TLT:
|
| + Format(instr, "tlt 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TLTU:
|
| + Format(instr, "tltu 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TEQ:
|
| + Format(instr, "teq 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TNE:
|
| + Format(instr, "tne 'rs, 'rt, code: 'code");
|
| + break;
|
| + case MOVZ:
|
| + Format(instr, "movz 'rd, 'rs, 'rt");
|
| + break;
|
| + case MOVN:
|
| + Format(instr, "movn 'rd, 'rs, 'rt");
|
| + break;
|
| + case MOVCI:
|
| + if (instr->Bit(16)) {
|
| + Format(instr, "movt 'rd, 'rs, 'bc");
|
| + } else {
|
| + Format(instr, "movf 'rd, 'rs, 'bc");
|
| + }
|
| + break;
|
| + case SELEQZ_S:
|
| + Format(instr, "seleqz 'rs, 'rt, 'rd");
|
| + break;
|
| + case SELNEZ_S:
|
| + Format(instr, "selnez 'rs, 'rt, 'rd");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegisterSPECIAL2(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case MUL:
|
| + Format(instr, "mul 'rd, 'rs, 'rt");
|
| + break;
|
| + case CLZ:
|
| + if (kArchVariant != kMips64r6) {
|
| + Format(instr, "clz 'rd, 'rs");
|
| + }
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case INS: {
|
| + Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
|
| + break;
|
| + }
|
| + case EXT: {
|
| + Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
|
| + break;
|
| + }
|
| + case DEXT: {
|
| + Format(instr, "dext 'rt, 'rs, 'sa, 'ss1");
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +int Decoder::DecodeTypeRegister(Instruction* instr) {
|
| + switch (instr->OpcodeFieldRaw()) {
|
| + case COP1: // Coprocessor instructions.
|
| + DecodeTypeRegisterCOP1(instr);
|
| + break;
|
| + case COP1X:
|
| + DecodeTypeRegisterCOP1X(instr);
|
| + break;
|
| + case SPECIAL:
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case BREAK:
|
| + return DecodeBreakInstr(instr);
|
| default:
|
| - UNREACHABLE();
|
| + DecodeTypeRegisterSPECIAL(instr);
|
| + break;
|
| }
|
| break;
|
| + case SPECIAL2:
|
| + DecodeTypeRegisterSPECIAL2(instr);
|
| + break;
|
| + case SPECIAL3:
|
| + DecodeTypeRegisterSPECIAL3(instr);
|
| + break;
|
| default:
|
| UNREACHABLE();
|
| }
|
| @@ -978,187 +1037,216 @@ int Decoder::DecodeTypeRegister(Instruction* instr) {
|
| }
|
|
|
|
|
| +void Decoder::DecodeTypeImmediateCOP1D(Instruction* instr) {
|
| + switch (instr->FunctionValue()) {
|
| + case SEL:
|
| + Format(instr, "sel.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case SELEQZ_C:
|
| + Format(instr, "seleqz.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case SELNEZ_C:
|
| + Format(instr, "selnez.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case MIN:
|
| + Format(instr, "min.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case MINA:
|
| + Format(instr, "mina.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case MAX:
|
| + Format(instr, "max.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case MAXA:
|
| + Format(instr, "maxa.D 'ft, 'fs, 'fd");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediateCOP1L(Instruction* instr) {
|
| + switch (instr->FunctionValue()) {
|
| + case CMP_AF:
|
| + Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UN:
|
| + Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_EQ:
|
| + Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UEQ:
|
| + Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_LT:
|
| + Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_ULT:
|
| + Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_LE:
|
| + Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_ULE:
|
| + Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_OR:
|
| + Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UNE:
|
| + Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_NE:
|
| + Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediateCOP1S(Instruction* instr) {
|
| + switch (instr->FunctionValue()) {
|
| + case SEL:
|
| + Format(instr, "sel.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case SELEQZ_C:
|
| + Format(instr, "seleqz.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case SELNEZ_C:
|
| + Format(instr, "selnez.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case MIN:
|
| + Format(instr, "min.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case MINA:
|
| + Format(instr, "mina.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case MAX:
|
| + Format(instr, "max.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case MAXA:
|
| + Format(instr, "maxa.S 'ft, 'fs, 'fd");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediateCOP1W(Instruction* instr) {
|
| + switch (instr->FunctionValue()) {
|
| + case CMP_AF:
|
| + Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UN:
|
| + Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_EQ:
|
| + Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UEQ:
|
| + Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_LT:
|
| + Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_ULT:
|
| + Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_LE:
|
| + Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_ULE:
|
| + Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_OR:
|
| + Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_UNE:
|
| + Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
|
| + break;
|
| + case CMP_NE:
|
| + Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediateCOP1(Instruction* instr) {
|
| + switch (instr->RsFieldRaw()) {
|
| + case BC1:
|
| + if (instr->FBtrueValue()) {
|
| + Format(instr, "bc1t 'bc, 'imm16u");
|
| + } else {
|
| + Format(instr, "bc1f 'bc, 'imm16u");
|
| + }
|
| + break;
|
| + case BC1EQZ:
|
| + Format(instr, "bc1eqz 'ft, 'imm16u");
|
| + break;
|
| + case BC1NEZ:
|
| + Format(instr, "bc1nez 'ft, 'imm16u");
|
| + break;
|
| + case W: // CMP.S instruction.
|
| + DecodeTypeImmediateCOP1W(instr);
|
| + break;
|
| + case L: // CMP.D instruction.
|
| + DecodeTypeImmediateCOP1L(instr);
|
| + break;
|
| + case S:
|
| + DecodeTypeImmediateCOP1S(instr);
|
| + break;
|
| + case D:
|
| + DecodeTypeImmediateCOP1D(instr);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediateREGIMM(Instruction* instr) {
|
| + switch (instr->RtFieldRaw()) {
|
| + case BLTZ:
|
| + Format(instr, "bltz 'rs, 'imm16u");
|
| + break;
|
| + case BLTZAL:
|
| + Format(instr, "bltzal 'rs, 'imm16u");
|
| + break;
|
| + case BGEZ:
|
| + Format(instr, "bgez 'rs, 'imm16u");
|
| + break;
|
| + case BGEZAL:
|
| + Format(instr, "bgezal 'rs, 'imm16u");
|
| + break;
|
| + case BGEZALL:
|
| + Format(instr, "bgezall 'rs, 'imm16u");
|
| + break;
|
| + case DAHI:
|
| + Format(instr, "dahi 'rs, 'imm16u");
|
| + break;
|
| + case DATI:
|
| + Format(instr, "dati 'rs, 'imm16u");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
| switch (instr->OpcodeFieldRaw()) {
|
| case COP1:
|
| - switch (instr->RsFieldRaw()) {
|
| - case BC1:
|
| - if (instr->FBtrueValue()) {
|
| - Format(instr, "bc1t 'bc, 'imm16u");
|
| - } else {
|
| - Format(instr, "bc1f 'bc, 'imm16u");
|
| - }
|
| - break;
|
| - case BC1EQZ:
|
| - Format(instr, "bc1eqz 'ft, 'imm16u");
|
| - break;
|
| - case BC1NEZ:
|
| - Format(instr, "bc1nez 'ft, 'imm16u");
|
| - break;
|
| - case W: // CMP.S instruction.
|
| - switch (instr->FunctionValue()) {
|
| - case CMP_AF:
|
| - Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UN:
|
| - Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_EQ:
|
| - Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UEQ:
|
| - Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_LT:
|
| - Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_ULT:
|
| - Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_LE:
|
| - Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_ULE:
|
| - Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_OR:
|
| - Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UNE:
|
| - Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_NE:
|
| - Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - case L: // CMP.D instruction.
|
| - switch (instr->FunctionValue()) {
|
| - case CMP_AF:
|
| - Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UN:
|
| - Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_EQ:
|
| - Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UEQ:
|
| - Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_LT:
|
| - Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_ULT:
|
| - Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_LE:
|
| - Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_ULE:
|
| - Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_OR:
|
| - Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_UNE:
|
| - Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case CMP_NE:
|
| - Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - case S:
|
| - switch (instr->FunctionValue()) {
|
| - case SEL:
|
| - Format(instr, "sel.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case SELEQZ_C:
|
| - Format(instr, "seleqz.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case SELNEZ_C:
|
| - Format(instr, "selnez.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case MIN:
|
| - Format(instr, "min.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case MINA:
|
| - Format(instr, "mina.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case MAX:
|
| - Format(instr, "max.S 'ft, 'fs, 'fd");
|
| - break;
|
| - case MAXA:
|
| - Format(instr, "maxa.S 'ft, 'fs, 'fd");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - case D:
|
| - switch (instr->FunctionValue()) {
|
| - case SEL:
|
| - Format(instr, "sel.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case SELEQZ_C:
|
| - Format(instr, "seleqz.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case SELNEZ_C:
|
| - Format(instr, "selnez.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case MIN:
|
| - Format(instr, "min.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case MINA:
|
| - Format(instr, "mina.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case MAX:
|
| - Format(instr, "max.D 'ft, 'fs, 'fd");
|
| - break;
|
| - case MAXA:
|
| - Format(instr, "maxa.D 'ft, 'fs, 'fd");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -
|
| + DecodeTypeImmediateCOP1(instr);
|
| break; // Case COP1.
|
| // ------------- REGIMM class.
|
| case REGIMM:
|
| - switch (instr->RtFieldRaw()) {
|
| - case BLTZ:
|
| - Format(instr, "bltz 'rs, 'imm16u");
|
| - break;
|
| - case BLTZAL:
|
| - Format(instr, "bltzal 'rs, 'imm16u");
|
| - break;
|
| - case BGEZ:
|
| - Format(instr, "bgez 'rs, 'imm16u");
|
| - break;
|
| - case BGEZAL:
|
| - Format(instr, "bgezal 'rs, 'imm16u");
|
| - break;
|
| - case BGEZALL:
|
| - Format(instr, "bgezall 'rs, 'imm16u");
|
| - break;
|
| - case DAHI:
|
| - Format(instr, "dahi 'rs, 'imm16u");
|
| - break;
|
| - case DATI:
|
| - Format(instr, "dati 'rs, 'imm16u");
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| +
|
| break; // Case REGIMM.
|
| // ------------- Branch instructions.
|
| case BEQ:
|
|
|