MIPS: Refactor simulator and add selection instructions for r6.
authordusan.milosavljevic <dusan.milosavljevic@imgtec.com>
Mon, 30 Mar 2015 17:36:56 +0000 (10:36 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 30 Mar 2015 17:37:13 +0000 (17:37 +0000)
TEST=
BUG=

Review URL: https://codereview.chromium.org/1046873004

Cr-Commit-Position: refs/heads/master@{#27530}

14 files changed:
src/mips/assembler-mips.cc
src/mips/constants-mips.cc
src/mips/disasm-mips.cc
src/mips/simulator-mips.cc
src/mips/simulator-mips.h
src/mips64/assembler-mips64.cc
src/mips64/constants-mips64.cc
src/mips64/disasm-mips64.cc
src/mips64/simulator-mips64.cc
src/mips64/simulator-mips64.h
test/cctest/test-assembler-mips.cc
test/cctest/test-assembler-mips64.cc
test/cctest/test-disasm-mips.cc
test/cctest/test-disasm-mips64.cc

index c26a8514bb1d35ee43df5efa6c088b599874ece3..7249f77e4be56378cdb22a4eceb4b8a005964094 100644 (file)
@@ -1920,6 +1920,34 @@ void Assembler::movf(Register rd, Register rs, uint16_t cc) {
 }
 
 
+void Assembler::seleqz(Register rs, Register rt, Register rd) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
+}
+
+
+void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister ft,
+                       FPURegister fs) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  DCHECK((fmt == D) || (fmt == S));
+  GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
+}
+
+
+void Assembler::selnez(Register rs, Register rt, Register rd) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
+}
+
+
+void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister ft,
+                       FPURegister fs) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  DCHECK((fmt == D) || (fmt == S));
+  GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
+}
+
+
 // Bit twiddling.
 void Assembler::clz(Register rd, Register rs) {
   if (!IsMipsArchVariant(kMips32r6)) {
index 30e4b2e003bce967e7c2ce868b6150797b529c02..419462311a4a0063e80f2922e92478fae70de539 100644 (file)
@@ -252,6 +252,8 @@ Instruction::Type Instruction::InstructionType() const {
         case MOVZ:
         case MOVN:
         case MOVCI:
+        case SELEQZ_S:
+        case SELNEZ_S:
           return kRegisterType;
         default:
           return kUnsupported;
@@ -280,6 +282,8 @@ Instruction::Type Instruction::InstructionType() const {
         case BC1:   // Branch on coprocessor condition.
         case BC1EQZ:
         case BC1NEZ:
+        case SELEQZ_C:
+        case SELNEZ_C:
           return kImmediateType;
         default:
           return kRegisterType;
index 4f725cff54a90d6cc1e768987e79e858c73c25ee..62ea55da0471585508e4f44bc16867969b530ff6 100644 (file)
@@ -99,7 +99,13 @@ class Decoder {
   void Format(Instruction* instr, const char* format);
   void Unknown(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 DecodeTypeRegister(Instruction* instr);
   void DecodeTypeImmediate(Instruction* instr);
   void DecodeTypeJump(Instruction* instr);
@@ -449,6 +455,357 @@ void Decoder::Unknown(Instruction* instr) {
 }
 
 
+void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
+  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 FLOOR_W_D:
+      Format(instr, "floor.w.d 'fd, 'fs");
+      break;
+    case CEIL_W_D:
+      Format(instr, "ceil.w.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::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 SRL:
+      if (instr->RsValue() == 0) {
+        Format(instr, "srl     'rd, 'rt, 'sa");
+      } else {
+        if (IsMipsArchVariant(kMips32r2)) {
+          Format(instr, "rotr    'rd, 'rt, 'sa");
+        } else {
+          Unknown(instr);
+        }
+      }
+      break;
+    case SRA:
+      Format(instr, "sra     'rd, 'rt, 'sa");
+      break;
+    case SLLV:
+      Format(instr, "sllv    'rd, 'rt, 'rs");
+      break;
+    case SRLV:
+      if (instr->SaValue() == 0) {
+        Format(instr, "srlv    'rd, 'rt, 'rs");
+      } else {
+        if (IsMipsArchVariant(kMips32r2)) {
+          Format(instr, "rotrv   'rd, 'rt, 'rs");
+        } else {
+          Unknown(instr);
+        }
+      }
+      break;
+    case SRAV:
+      Format(instr, "srav    '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 MULT:  // @Mips32r6 == MUL_MUH.
+      if (!IsMipsArchVariant(kMips32r6)) {
+        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:  // @Mips32r6 == MUL_MUH_U.
+      if (!IsMipsArchVariant(kMips32r6)) {
+        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:  // @Mips32r6 == DIV_MOD.
+      if (!IsMipsArchVariant(kMips32r6)) {
+        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 DIVU:  // @Mips32r6 == DIV_MOD_U.
+      if (!IsMipsArchVariant(kMips32r6)) {
+        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 ADD:
+      Format(instr, "add     'rd, 'rs, 'rt");
+      break;
+    case ADDU:
+      Format(instr, "addu    'rd, 'rs, 'rt");
+      break;
+    case SUB:
+      Format(instr, "sub     'rd, 'rs, 'rt");
+      break;
+    case SUBU:
+      Format(instr, "subu    '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:
+      Format(instr, "break, code: 'code");
+      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 (!IsMipsArchVariant(kMips32r6)) {
+        Format(instr, "clz     'rd, 'rs");
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
+  switch (instr->FunctionFieldRaw()) {
+    case INS: {
+      if (IsMipsArchVariant(kMips32r2)) {
+        Format(instr, "ins     'rt, 'rs, 'sa, 'ss2");
+      } else {
+        Unknown(instr);
+      }
+      break;
+    }
+    case EXT: {
+      if (IsMipsArchVariant(kMips32r2)) {
+        Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
+      } else {
+        Unknown(instr);
+      }
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void Decoder::DecodeTypeRegister(Instruction* instr) {
   switch (instr->OpcodeFieldRaw()) {
     case COP1:    // Coprocessor instructions.
@@ -476,83 +833,7 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
           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 FLOOR_W_D:
-              Format(instr, "floor.w.d 'fd, 'fs");
-              break;
-            case CEIL_W_D:
-              Format(instr, "ceil.w.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;
-          }
+          DecodeTypeRegisterDRsType(instr);
           break;
         case S:
           switch (instr->FunctionFieldRaw()) {
@@ -576,46 +857,7 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
           }
           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();
-          }
+          DecodeTypeRegisterLRsType(instr);
           break;
         case PS:
           UNIMPLEMENTED_MIPS();
@@ -634,225 +876,13 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
       }
       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 SRL:
-          if (instr->RsValue() == 0) {
-            Format(instr, "srl     'rd, 'rt, 'sa");
-          } else {
-            if (IsMipsArchVariant(kMips32r2)) {
-              Format(instr, "rotr    'rd, 'rt, 'sa");
-            } else {
-              Unknown(instr);
-            }
-          }
-          break;
-        case SRA:
-          Format(instr, "sra     'rd, 'rt, 'sa");
-          break;
-        case SLLV:
-          Format(instr, "sllv    'rd, 'rt, 'rs");
-          break;
-        case SRLV:
-          if (instr->SaValue() == 0) {
-            Format(instr, "srlv    'rd, 'rt, 'rs");
-          } else {
-            if (IsMipsArchVariant(kMips32r2)) {
-              Format(instr, "rotrv   'rd, 'rt, 'rs");
-            } else {
-              Unknown(instr);
-            }
-          }
-          break;
-        case SRAV:
-          Format(instr, "srav    '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 MULT:  // @Mips32r6 == MUL_MUH.
-          if (!IsMipsArchVariant(kMips32r6)) {
-            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:  // @Mips32r6 == MUL_MUH_U.
-          if (!IsMipsArchVariant(kMips32r6)) {
-            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:  // @Mips32r6 == DIV_MOD.
-          if (!IsMipsArchVariant(kMips32r6)) {
-            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 DIVU:  // @Mips32r6 == DIV_MOD_U.
-          if (!IsMipsArchVariant(kMips32r6)) {
-            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 ADD:
-          Format(instr, "add     'rd, 'rs, 'rt");
-          break;
-        case ADDU:
-          Format(instr, "addu    'rd, 'rs, 'rt");
-          break;
-        case SUB:
-          Format(instr, "sub     'rd, 'rs, 'rt");
-          break;
-        case SUBU:
-          Format(instr, "subu    '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:
-          Format(instr, "break, code: 'code");
-          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    'rd, 'rs, 'rt");
-          break;
-        case SELNEZ_S:
-          Format(instr, "selnez    'rd, 'rs, 'rt");
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterSPECIAL(instr);
       break;
     case SPECIAL2:
-      switch (instr->FunctionFieldRaw()) {
-        case MUL:
-          Format(instr, "mul     'rd, 'rs, 'rt");
-          break;
-        case CLZ:
-          if (!IsMipsArchVariant(kMips32r6)) {
-            Format(instr, "clz     'rd, 'rs");
-          }
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterSPECIAL2(instr);
       break;
     case SPECIAL3:
-      switch (instr->FunctionFieldRaw()) {
-        case INS: {
-          if (IsMipsArchVariant(kMips32r2)) {
-            Format(instr, "ins     'rt, 'rs, 'sa, 'ss2");
-          } else {
-            Unknown(instr);
-          }
-          break;
-        }
-        case EXT: {
-          if (IsMipsArchVariant(kMips32r2)) {
-            Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
-          } else {
-            Unknown(instr);
-          }
-          break;
-        }
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterSPECIAL3(instr);
       break;
     default:
       UNREACHABLE();
index 7ea38419358a600f8c6202f2f30bcdd5c6e350bb..2e4921c71059eb799228c38bfa7bf5886b192d6b 100644 (file)
@@ -2079,6 +2079,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
         case DIV:
         case DIVU:
           // div and divu never raise exceptions.
+        case SELEQZ_S:
+        case SELNEZ_S:
           break;
         default:
           UNREACHABLE();
@@ -2130,366 +2132,393 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
 }
 
 
-void Simulator::DecodeTypeRegister(Instruction* instr) {
-  // Instruction fields.
-  const Opcode   op     = instr->OpcodeFieldRaw();
-  const int32_t  rs_reg = instr->RsValue();
-  const int32_t  rs     = get_register(rs_reg);
-  const uint32_t rs_u   = static_cast<uint32_t>(rs);
-  const int32_t  rt_reg = instr->RtValue();
-  const int32_t  rt     = get_register(rt_reg);
-  const uint32_t rt_u   = static_cast<uint32_t>(rt);
-  const int32_t  rd_reg = instr->RdValue();
+void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
+                                          const int32_t& fr_reg,
+                                          const int32_t& fs_reg,
+                                          const int32_t& ft_reg,
+                                          const int32_t& fd_reg) {
+  double ft, fs;
+  uint32_t cc, fcsr_cc;
+  int64_t i64;
+  fs = get_fpu_register_double(fs_reg);
+  ft = get_fpu_register_double(ft_reg);
+  int64_t ft_int = static_cast<int64_t>(ft);
+  cc = instr->FCccValue();
+  fcsr_cc = get_fcsr_condition_bit(cc);
+  switch (instr->FunctionFieldRaw()) {
+    case SELEQZ_C:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0);
+      break;
+    case SELNEZ_C:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
+      break;
+    case ADD_D:
+      set_fpu_register_double(fd_reg, fs + ft);
+      break;
+    case SUB_D:
+      set_fpu_register_double(fd_reg, fs - ft);
+      break;
+    case MUL_D:
+      set_fpu_register_double(fd_reg, fs * ft);
+      break;
+    case DIV_D:
+      set_fpu_register_double(fd_reg, fs / ft);
+      break;
+    case ABS_D:
+      set_fpu_register_double(fd_reg, fabs(fs));
+      break;
+    case MOV_D:
+      set_fpu_register_double(fd_reg, fs);
+      break;
+    case NEG_D:
+      set_fpu_register_double(fd_reg, -fs);
+      break;
+    case SQRT_D:
+      set_fpu_register_double(fd_reg, fast_sqrt(fs));
+      break;
+    case C_UN_D:
+      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
+      break;
+    case C_EQ_D:
+      set_fcsr_bit(fcsr_cc, (fs == ft));
+      break;
+    case C_UEQ_D:
+      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case C_OLT_D:
+      set_fcsr_bit(fcsr_cc, (fs < ft));
+      break;
+    case C_ULT_D:
+      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case C_OLE_D:
+      set_fcsr_bit(fcsr_cc, (fs <= ft));
+      break;
+    case C_ULE_D:
+      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case CVT_W_D:  // Convert double to word.
+      // Rounding modes are not yet supported.
+      DCHECK((FCSR_ & 3) == 0);
+    // In rounding mode 0 it should behave like ROUND.
+    case ROUND_W_D:  // Round double to word (round half to even).
+    {
+      double rounded = std::floor(fs + 0.5);
+      int32_t result = static_cast<int32_t>(rounded);
+      if ((result & 1) != 0 && result - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        result--;
+      }
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case TRUNC_W_D:  // Truncate double to word (round towards 0).
+    {
+      double rounded = trunc(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case FLOOR_W_D:  // Round double to word towards negative infinity.
+    {
+      double rounded = std::floor(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case CEIL_W_D:  // Round double to word towards positive infinity.
+    {
+      double rounded = std::ceil(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case CVT_S_D:  // Convert double to float (single).
+      set_fpu_register_float(fd_reg, static_cast<float>(fs));
+      break;
+    case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
+      double rounded = trunc(fs);
+      i64 = static_cast<int64_t>(rounded);
+      if (IsFp64Mode()) {
+        set_fpu_register(fd_reg, i64);
+      } else {
+        set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+        set_fpu_register_word(fd_reg + 1, i64 >> 32);
+      }
+      break;
+    }
+    case TRUNC_L_D: {  // Mips32r2 instruction.
+      double rounded = trunc(fs);
+      i64 = static_cast<int64_t>(rounded);
+      if (IsFp64Mode()) {
+        set_fpu_register(fd_reg, i64);
+      } else {
+        set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+        set_fpu_register_word(fd_reg + 1, i64 >> 32);
+      }
+      break;
+    }
+    case ROUND_L_D: {  // Mips32r2 instruction.
+      double rounded = fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
+      i64 = static_cast<int64_t>(rounded);
+      if (IsFp64Mode()) {
+        set_fpu_register(fd_reg, i64);
+      } else {
+        set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+        set_fpu_register_word(fd_reg + 1, i64 >> 32);
+      }
+      break;
+    }
+    case FLOOR_L_D:  // Mips32r2 instruction.
+      i64 = static_cast<int64_t>(std::floor(fs));
+      if (IsFp64Mode()) {
+        set_fpu_register(fd_reg, i64);
+      } else {
+        set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+        set_fpu_register_word(fd_reg + 1, i64 >> 32);
+      }
+      break;
+    case CEIL_L_D:  // Mips32r2 instruction.
+      i64 = static_cast<int64_t>(std::ceil(fs));
+      if (IsFp64Mode()) {
+        set_fpu_register(fd_reg, i64);
+      } else {
+        set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+        set_fpu_register_word(fd_reg + 1, i64 >> 32);
+      }
+      break;
+    case C_F_D:
+      UNIMPLEMENTED_MIPS();
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
 
-  const int32_t  fr_reg = instr->FrValue();
-  const int32_t  fs_reg = instr->FsValue();
-  const int32_t  ft_reg = instr->FtValue();
-  const int32_t  fd_reg = instr->FdValue();
-  int64_t  i64hilo = 0;
-  uint64_t u64hilo = 0;
 
-  // ALU output.
-  // It should not be used as is. Instructions using it should always
-  // initialize it first.
-  int32_t alu_out = 0x12345678;
+void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
+                                          const int32_t& fd_reg,
+                                          const int32_t& fs_reg) {
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_S_W:  // Convert word to float (single).
+      alu_out = get_fpu_register_signed_word(fs_reg);
+      set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
+      break;
+    case CVT_D_W:  // Convert word to double.
+      alu_out = get_fpu_register_signed_word(fs_reg);
+      set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
+      break;
+    default:  // Mips64r6 CMP.S instructions unimplemented.
+      UNREACHABLE();
+  }
+}
 
-  // For break and trap instructions.
-  bool do_interrupt = false;
 
-  // For jr and jalr.
-  // Get current pc.
-  int32_t current_pc = get_pc();
-  // Next pc
-  int32_t next_pc = 0;
-  int32_t return_addr_reg = 31;
-
-  // Set up the variables if needed before executing the instruction.
-  ConfigureTypeRegister(instr,
-                        &alu_out,
-                        &i64hilo,
-                        &u64hilo,
-                        &next_pc,
-                        &return_addr_reg,
-                        &do_interrupt);
+void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
+                                          const int32_t& ft_reg,
+                                          const int32_t& fs_reg,
+                                          const int32_t& fd_reg) {
+  float f;
+  double ft = get_fpu_register_double(ft_reg);
+  int64_t ft_int = static_cast<int64_t>(ft);
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_D_S:
+      f = get_fpu_register_float(fs_reg);
+      set_fpu_register_double(fd_reg, static_cast<double>(f));
+      break;
+    case SELEQZ_C:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_fpu_register_double(
+          fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_double(fs_reg) : 0.0);
+      break;
+    case SELNEZ_C:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_fpu_register_double(
+          fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_double(fs_reg) : 0.0);
+      break;
+    default:
+      // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
+      // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
+      UNREACHABLE();
+  }
+}
 
-  // ---------- Raise exceptions triggered.
-  SignalExceptions();
 
-  // ---------- Execution.
-  switch (op) {
-    case COP1:
-      switch (instr->RsFieldRaw()) {
-        case CFC1:
-          set_register(rt_reg, alu_out);
-          break;
-        case MFC1:
-          set_register(rt_reg, alu_out);
-          break;
-        case MFHC1:
-          set_register(rt_reg, alu_out);
-          break;
-        case CTC1:
-          // At the moment only FCSR is supported.
-          DCHECK(fs_reg == kFCSRRegister);
-          FCSR_ = registers_[rt_reg];
-          break;
-        case MTC1:
-          // Hardware writes upper 32-bits to zero on mtc1.
-          set_fpu_register_hi_word(fs_reg, 0);
-          set_fpu_register_word(fs_reg, registers_[rt_reg]);
-          break;
-        case MTHC1:
-          set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
-          break;
-        case S:
-          float f;
-          switch (instr->FunctionFieldRaw()) {
-            case CVT_D_S:
-              f = get_fpu_register_float(fs_reg);
-              set_fpu_register_double(fd_reg, static_cast<double>(f));
-              break;
-            default:
-            // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
-            // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
-              UNREACHABLE();
-          }
-          break;
-        case D:
-          double ft, fs;
-          uint32_t cc, fcsr_cc;
-          int64_t  i64;
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          cc = instr->FCccValue();
-          fcsr_cc = get_fcsr_condition_bit(cc);
-          switch (instr->FunctionFieldRaw()) {
-            case ADD_D:
-              set_fpu_register_double(fd_reg, fs + ft);
-              break;
-            case SUB_D:
-              set_fpu_register_double(fd_reg, fs - ft);
-              break;
-            case MUL_D:
-              set_fpu_register_double(fd_reg, fs * ft);
-              break;
-            case DIV_D:
-              set_fpu_register_double(fd_reg, fs / ft);
-              break;
-            case ABS_D:
-              set_fpu_register_double(fd_reg, fabs(fs));
-              break;
-            case MOV_D:
-              set_fpu_register_double(fd_reg, fs);
-              break;
-            case NEG_D:
-              set_fpu_register_double(fd_reg, -fs);
-              break;
-            case SQRT_D:
-              set_fpu_register_double(fd_reg, fast_sqrt(fs));
-              break;
-            case C_UN_D:
-              set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
-              break;
-            case C_EQ_D:
-              set_fcsr_bit(fcsr_cc, (fs == ft));
-              break;
-            case C_UEQ_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case C_OLT_D:
-              set_fcsr_bit(fcsr_cc, (fs < ft));
-              break;
-            case C_ULT_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case C_OLE_D:
-              set_fcsr_bit(fcsr_cc, (fs <= ft));
-              break;
-            case C_ULE_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case CVT_W_D:   // Convert double to word.
-              // Rounding modes are not yet supported.
-              DCHECK((FCSR_ & 3) == 0);
-              // In rounding mode 0 it should behave like ROUND.
-            case ROUND_W_D:  // Round double to word (round half to even).
-              {
-                double rounded = std::floor(fs + 0.5);
-                int32_t result = static_cast<int32_t>(rounded);
-                if ((result & 1) != 0 && result - fs == 0.5) {
-                  // If the number is halfway between two integers,
-                  // round to the even one.
-                  result--;
-                }
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case TRUNC_W_D:  // Truncate double to word (round towards 0).
-              {
-                double rounded = trunc(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case FLOOR_W_D:  // Round double to word towards negative infinity.
-              {
-                double rounded = std::floor(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case CEIL_W_D:  // Round double to word towards positive infinity.
-              {
-                double rounded = std::ceil(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case CVT_S_D:  // Convert double to float (single).
-              set_fpu_register_float(fd_reg, static_cast<float>(fs));
-              break;
-            case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
-              double rounded = trunc(fs);
-              i64 = static_cast<int64_t>(rounded);
-              if (IsFp64Mode()) {
-                set_fpu_register(fd_reg, i64);
-              } else {
-                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
-                set_fpu_register_word(fd_reg + 1, i64 >> 32);
-              }
-              break;
-            }
-            case TRUNC_L_D: {  // Mips32r2 instruction.
-              double rounded = trunc(fs);
-              i64 = static_cast<int64_t>(rounded);
-              if (IsFp64Mode()) {
-                set_fpu_register(fd_reg, i64);
-              } else {
-                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
-                set_fpu_register_word(fd_reg + 1, i64 >> 32);
-              }
-              break;
-            }
-            case ROUND_L_D: {  // Mips32r2 instruction.
-              double rounded =
-                  fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
-              i64 = static_cast<int64_t>(rounded);
-              if (IsFp64Mode()) {
-                set_fpu_register(fd_reg, i64);
-              } else {
-                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
-                set_fpu_register_word(fd_reg + 1, i64 >> 32);
-              }
-              break;
-            }
-            case FLOOR_L_D:  // Mips32r2 instruction.
-              i64 = static_cast<int64_t>(std::floor(fs));
-              if (IsFp64Mode()) {
-                set_fpu_register(fd_reg, i64);
-              } else {
-                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
-                set_fpu_register_word(fd_reg + 1, i64 >> 32);
-              }
-              break;
-            case CEIL_L_D:  // Mips32r2 instruction.
-              i64 = static_cast<int64_t>(std::ceil(fs));
-              if (IsFp64Mode()) {
-                set_fpu_register(fd_reg, i64);
-              } else {
-                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
-                set_fpu_register_word(fd_reg + 1, i64 >> 32);
-              }
-              break;
-            case C_F_D:
-              UNIMPLEMENTED_MIPS();
-              break;
-            default:
-              UNREACHABLE();
-          }
-          break;
-        case W:
-          switch (instr->FunctionFieldRaw()) {
-            case CVT_S_W:   // Convert word to float (single).
-              alu_out = get_fpu_register_signed_word(fs_reg);
-              set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
-              break;
-            case CVT_D_W:   // Convert word to double.
-              alu_out = get_fpu_register_signed_word(fs_reg);
-              set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
-              break;
-            default:  // Mips64r6 CMP.S instructions unimplemented.
-              UNREACHABLE();
-          }
-          break;
-        case L:
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          switch (instr->FunctionFieldRaw()) {
-          case CVT_D_L:  // Mips32r2 instruction.
-            // Watch the signs here, we want 2 32-bit vals
-            // to make a sign-64.
-            if (IsFp64Mode()) {
-              i64 = get_fpu_register(fs_reg);
-            } else {
-              i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg));
-              i64 |= static_cast<int64_t>(
-                  get_fpu_register_word(fs_reg + 1)) << 32;
-            }
-            set_fpu_register_double(fd_reg, static_cast<double>(i64));
-            break;
-            case CVT_S_L:
-              UNIMPLEMENTED_MIPS();
-              break;
-            case CMP_AF:  // Mips64r6 CMP.D instructions.
-              UNIMPLEMENTED_MIPS();
-              break;
-            case CMP_UN:
-              if (std::isnan(fs) || std::isnan(ft)) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_EQ:
-              if (fs == ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_UEQ:
-              if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_LT:
-              if (fs < ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_ULT:
-              if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_LE:
-              if (fs <= ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_ULE:
-              if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
-              UNREACHABLE();
-          }
-          break;
-        default:
-          UNREACHABLE();
+void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
+                                          const int32_t& ft_reg,
+                                          const int32_t& fs_reg,
+                                          const int32_t& fd_reg) {
+  double fs = get_fpu_register_double(fs_reg);
+  double ft = get_fpu_register_double(ft_reg);
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_D_L:  // Mips32r2 instruction.
+      // Watch the signs here, we want 2 32-bit vals
+      // to make a sign-64.
+      int64_t i64;
+      if (IsFp64Mode()) {
+        i64 = get_fpu_register(fs_reg);
+      } else {
+        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg));
+        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg + 1)) << 32;
       }
+      set_fpu_register_double(fd_reg, static_cast<double>(i64));
       break;
-    case COP1X:
-      switch (instr->FunctionFieldRaw()) {
-        case MADD_D:
-          double fr, ft, fs;
-          fr = get_fpu_register_double(fr_reg);
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          set_fpu_register_double(fd_reg, fs * ft + fr);
-          break;
-        default:
-          UNREACHABLE();
+    case CVT_S_L:
+      UNIMPLEMENTED_MIPS();
+      break;
+    case CMP_AF:  // Mips64r6 CMP.D instructions.
+      UNIMPLEMENTED_MIPS();
+      break;
+    case CMP_UN:
+      if (std::isnan(fs) || std::isnan(ft)) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
       }
       break;
-    case SPECIAL:
-      switch (instr->FunctionFieldRaw()) {
+    case CMP_EQ:
+      if (fs == ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_UEQ:
+      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_LT:
+      if (fs < ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_ULT:
+      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_LE:
+      if (fs <= ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_ULE:
+      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterCOP1(
+    Instruction* instr, const int32_t& rs_reg, const int32_t& rs,
+    const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt,
+    const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg,
+    const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg,
+    int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt,
+    int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) {
+  switch (instr->RsFieldRaw()) {
+    case CFC1:
+      set_register(rt_reg, alu_out);
+      break;
+    case MFC1:
+      set_register(rt_reg, alu_out);
+      break;
+    case MFHC1:
+      set_register(rt_reg, alu_out);
+      break;
+    case CTC1:
+      // At the moment only FCSR is supported.
+      DCHECK(fs_reg == kFCSRRegister);
+      FCSR_ = registers_[rt_reg];
+      break;
+    case MTC1:
+      // Hardware writes upper 32-bits to zero on mtc1.
+      set_fpu_register_hi_word(fs_reg, 0);
+      set_fpu_register_word(fs_reg, registers_[rt_reg]);
+      break;
+    case MTHC1:
+      set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
+      break;
+    case S: {
+      DecodeTypeRegisterSRsType(instr, ft_reg, fs_reg, fd_reg);
+      break;
+    }
+    case D:
+      DecodeTypeRegisterDRsType(instr, fr_reg, fs_reg, ft_reg, fd_reg);
+      break;
+    case W:
+      DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg);
+      break;
+    case L:
+      DecodeTypeRegisterLRsType(instr, ft_reg, fs_reg, fd_reg);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr,
+                                        const int32_t& fr_reg,
+                                        const int32_t& fs_reg,
+                                        const int32_t& ft_reg,
+                                        const int32_t& fd_reg) {
+  switch (instr->FunctionFieldRaw()) {
+    case MADD_D:
+      double fr, ft, fs;
+      fr = get_fpu_register_double(fr_reg);
+      fs = get_fpu_register_double(fs_reg);
+      ft = get_fpu_register_double(ft_reg);
+      set_fpu_register_double(fd_reg, fs * ft + fr);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL(
+    Instruction* instr, const int32_t& rs_reg, const int32_t& rs,
+    const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt,
+    const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg,
+    const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg,
+    int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt,
+    int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) {
+  switch (instr->FunctionFieldRaw()) {
+    case SELEQZ_S:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_register(rd_reg, rt == 0 ? rs : 0);
+      break;
+    case SELNEZ_S:
+      DCHECK(IsMipsArchVariant(kMips32r6));
+      set_register(rd_reg, rt != 0 ? rs : 0);
+      break;
         case JR: {
           Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
               current_pc+Instruction::kInstrSize);
@@ -2638,32 +2667,105 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
         default:  // For other special opcodes we do the default operation.
           set_register(rd_reg, alu_out);
       }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
+                                           const int32_t& rd_reg,
+                                           int32_t& alu_out) {
+  switch (instr->FunctionFieldRaw()) {
+    case MUL:
+      set_register(rd_reg, alu_out);
+      // HI and LO are UNPREDICTABLE after the operation.
+      set_register(LO, Unpredictable);
+      set_register(HI, Unpredictable);
+      break;
+    default:  // For other special2 opcodes we do the default operation.
+      set_register(rd_reg, alu_out);
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
+                                           const int32_t& rt_reg,
+                                           int32_t& alu_out) {
+  switch (instr->FunctionFieldRaw()) {
+    case INS:
+      // Ins instr leaves result in Rt, rather than Rd.
+      set_register(rt_reg, alu_out);
+      break;
+    case EXT:
+      // Ext instr leaves result in Rt, rather than Rd.
+      set_register(rt_reg, alu_out);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegister(Instruction* instr) {
+  // Instruction fields.
+  const Opcode op = instr->OpcodeFieldRaw();
+  const int32_t rs_reg = instr->RsValue();
+  const int32_t rs = get_register(rs_reg);
+  const uint32_t rs_u = static_cast<uint32_t>(rs);
+  const int32_t rt_reg = instr->RtValue();
+  const int32_t rt = get_register(rt_reg);
+  const uint32_t rt_u = static_cast<uint32_t>(rt);
+  const int32_t rd_reg = instr->RdValue();
+
+  const int32_t fr_reg = instr->FrValue();
+  const int32_t fs_reg = instr->FsValue();
+  const int32_t ft_reg = instr->FtValue();
+  const int32_t fd_reg = instr->FdValue();
+  int64_t i64hilo = 0;
+  uint64_t u64hilo = 0;
+
+  // ALU output.
+  // It should not be used as is. Instructions using it should always
+  // initialize it first.
+  int32_t alu_out = 0x12345678;
+
+  // For break and trap instructions.
+  bool do_interrupt = false;
+
+  // For jr and jalr.
+  // Get current pc.
+  int32_t current_pc = get_pc();
+  // Next pc
+  int32_t next_pc = 0;
+  int32_t return_addr_reg = 31;
+
+  // Set up the variables if needed before executing the instruction.
+  ConfigureTypeRegister(instr, &alu_out, &i64hilo, &u64hilo, &next_pc,
+                        &return_addr_reg, &do_interrupt);
+
+  // ---------- Raise exceptions triggered.
+  SignalExceptions();
+
+  // ---------- Execution.
+  switch (op) {
+    case COP1:
+      DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg,
+                             fr_reg, fs_reg, ft_reg, fd_reg, i64hilo, u64hilo,
+                             alu_out, do_interrupt, current_pc, next_pc,
+                             return_addr_reg);
+      break;
+    case COP1X:
+      DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg);
+      break;
+    case SPECIAL:
+      DecodeTypeRegisterSPECIAL(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u,
+                                rd_reg, fr_reg, fs_reg, ft_reg, fd_reg, i64hilo,
+                                u64hilo, alu_out, do_interrupt, current_pc,
+                                next_pc, return_addr_reg);
       break;
     case SPECIAL2:
-      switch (instr->FunctionFieldRaw()) {
-        case MUL:
-          set_register(rd_reg, alu_out);
-          // HI and LO are UNPREDICTABLE after the operation.
-          set_register(LO, Unpredictable);
-          set_register(HI, Unpredictable);
-          break;
-        default:  // For other special2 opcodes we do the default operation.
-          set_register(rd_reg, alu_out);
-      }
+      DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
       break;
     case SPECIAL3:
-      switch (instr->FunctionFieldRaw()) {
-        case INS:
-          // Ins instr leaves result in Rt, rather than Rd.
-          set_register(rt_reg, alu_out);
-          break;
-        case EXT:
-          // Ext instr leaves result in Rt, rather than Rd.
-          set_register(rt_reg, alu_out);
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out);
       break;
     // Unimplemented opcodes raised an error in the configuration step before,
     // so we can use the default here to set the destination register in common
index 85f64779f12551fd6c77c3304f82aeb8d3128c08..c1022061b7b7c2efe98eac64f2cea4e2ce29e3e6 100644 (file)
@@ -265,6 +265,47 @@ class Simulator {
   // Executing is handled based on the instruction type.
   void DecodeTypeRegister(Instruction* instr);
 
+  // Called from DecodeTypeRegisterCOP1
+  void DecodeTypeRegisterDRsType(Instruction* instr, const int32_t& fr_reg,
+                                 const int32_t& fs_reg, const int32_t& ft_reg,
+                                 const int32_t& fd_reg);
+  void DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
+                                 const int32_t& fd_reg, const int32_t& fs_reg);
+  void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t& ft_reg,
+                                 const int32_t& fs_reg, const int32_t& fd_reg);
+  void DecodeTypeRegisterLRsType(Instruction* instr, const int32_t& ft_reg,
+                                 const int32_t& fs_reg, const int32_t& fd_reg);
+
+  // Functions called from DeocodeTypeRegister
+  void DecodeTypeRegisterCOP1(
+      Instruction* instr, const int32_t& rs_reg, const int32_t& rs,
+      const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt,
+      const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg,
+      const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg,
+      int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt,
+      int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg);
+
+
+  void DecodeTypeRegisterCOP1X(Instruction* instr, const int32_t& fr_reg,
+                               const int32_t& fs_reg, const int32_t& ft_reg,
+                               const int32_t& fd_reg);
+
+
+  void DecodeTypeRegisterSPECIAL(
+      Instruction* instr, const int32_t& rs_reg, const int32_t& rs,
+      const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt,
+      const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg,
+      const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg,
+      int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt,
+      int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg);
+
+
+  void DecodeTypeRegisterSPECIAL2(Instruction* instr, const int32_t& rd_reg,
+                                  int32_t& alu_out);
+
+  void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int32_t& rt_reg,
+                                  int32_t& alu_out);
+
   // Helper function for DecodeTypeRegister.
   void ConfigureTypeRegister(Instruction* instr,
                              int32_t* alu_out,
index 9501371b6395dc787aaa8c03738d80864f6e6696..5c1677de3c6a424cac6dd6ef9101e027dff05412 100644 (file)
@@ -2139,13 +2139,8 @@ void Assembler::seleqz(Register rs, Register rt, Register rd) {
 // FPR.
 void Assembler::seleqz(SecondaryField fmt, FPURegister fd,
     FPURegister ft, FPURegister fs) {
-  DCHECK(kArchVariant == kMips64r6);
-  DCHECK(fmt == D);
-  DCHECK(fmt == S);
-
-  Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
-      fs.code() << kFsShift | fd.code() << kFdShift | SELEQZ_C;
-  emit(instr);
+  DCHECK((fmt == D) || (fmt == S));
+  GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
 }
 
 
@@ -2160,12 +2155,8 @@ void Assembler::selnez(Register rs, Register rt, Register rd) {
 void Assembler::selnez(SecondaryField fmt, FPURegister fd,
     FPURegister ft, FPURegister fs) {
   DCHECK(kArchVariant == kMips64r6);
-  DCHECK(fmt == D);
-  DCHECK(fmt == S);
-
-  Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
-      fs.code() << kFsShift | fd.code() << kFdShift | SELNEZ_C;
-  emit(instr);
+  DCHECK((fmt == D) || (fmt == S));
+  GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
 }
 
 
index dd34c57bfd14cb4ed33d67a3ac8a0a1350135f6d..6a26c2bd5b5dd335ad5d7c62298f4f1085e55997 100644 (file)
@@ -269,6 +269,8 @@ Instruction::Type Instruction::InstructionType() const {
         case MOVZ:
         case MOVN:
         case MOVCI:
+        case SELEQZ_S:
+        case SELNEZ_S:
           return kRegisterType;
         default:
           return kUnsupported;
index 3f0642db2c02d691fcd5fcba8d8b96c50410e62e..fc83955fe350ded4f5dbf8b95bc90aaee6411cc5 100644 (file)
@@ -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:
index 9ca57f6948743c6a2442b85f6e46a4ac763b8e35..bf4c2066c31b445898700fb127394ee6066624d1 100644 (file)
@@ -2206,6 +2206,9 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
         case DDIVU:
           // div and divu never raise exceptions.
           break;
+        case SELEQZ_S:
+        case SELNEZ_S:
+          break;
         default:
           UNREACHABLE();
       }
@@ -2267,6 +2270,561 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
 }
 
 
+void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
+                                          const int32_t& fs_reg,
+                                          const int64_t& fd_reg) {
+  float f;
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_D_S:
+      f = get_fpu_register_float(fs_reg);
+      set_fpu_register_double(fd_reg, static_cast<double>(f));
+      break;
+    default:
+      // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
+      // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
+                                          const int32_t& fs_reg,
+                                          const int64_t& ft_reg,
+                                          const int32_t& fd_reg) {
+  double ft, fs;
+  uint32_t cc, fcsr_cc;
+  fs = get_fpu_register_double(fs_reg);
+  ft = get_fpu_register_double(ft_reg);
+  cc = instr->FCccValue();
+  fcsr_cc = get_fcsr_condition_bit(cc);
+  int64_t ft_int = static_cast<int64_t>(ft);
+  switch (instr->FunctionFieldRaw()) {
+    case SELEQZ_C:
+      DCHECK(kArchVariant == kMips64r6);
+      set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0);
+      break;
+    case SELNEZ_C:
+      DCHECK(kArchVariant == kMips64r6);
+      set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
+      break;
+    case ADD_D:
+      set_fpu_register_double(fd_reg, fs + ft);
+      break;
+    case SUB_D:
+      set_fpu_register_double(fd_reg, fs - ft);
+      break;
+    case MUL_D:
+      set_fpu_register_double(fd_reg, fs * ft);
+      break;
+    case DIV_D:
+      set_fpu_register_double(fd_reg, fs / ft);
+      break;
+    case ABS_D:
+      set_fpu_register_double(fd_reg, fabs(fs));
+      break;
+    case MOV_D:
+      set_fpu_register_double(fd_reg, fs);
+      break;
+    case NEG_D:
+      set_fpu_register_double(fd_reg, -fs);
+      break;
+    case SQRT_D:
+      set_fpu_register_double(fd_reg, fast_sqrt(fs));
+      break;
+    case C_UN_D:
+      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
+      break;
+    case C_EQ_D:
+      set_fcsr_bit(fcsr_cc, (fs == ft));
+      break;
+    case C_UEQ_D:
+      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case C_OLT_D:
+      set_fcsr_bit(fcsr_cc, (fs < ft));
+      break;
+    case C_ULT_D:
+      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case C_OLE_D:
+      set_fcsr_bit(fcsr_cc, (fs <= ft));
+      break;
+    case C_ULE_D:
+      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
+      break;
+    case CVT_W_D:  // Convert double to word.
+      // Rounding modes are not yet supported.
+      DCHECK((FCSR_ & 3) == 0);
+    // In rounding mode 0 it should behave like ROUND.
+    // No break.
+    case ROUND_W_D:  // Round double to word (round half to even).
+    {
+      double rounded = std::floor(fs + 0.5);
+      int32_t result = static_cast<int32_t>(rounded);
+      if ((result & 1) != 0 && result - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        result--;
+      }
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case TRUNC_W_D:  // Truncate double to word (round towards 0).
+    {
+      double rounded = trunc(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case FLOOR_W_D:  // Round double to word towards negative infinity.
+    {
+      double rounded = std::floor(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case CEIL_W_D:  // Round double to word towards positive infinity.
+    {
+      double rounded = std::ceil(fs);
+      int32_t result = static_cast<int32_t>(rounded);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPUInvalidResult);
+      }
+    } break;
+    case CVT_S_D:  // Convert double to float (single).
+      set_fpu_register_float(fd_reg, static_cast<float>(fs));
+      break;
+    case CVT_L_D:  // Mips64r2: Truncate double to 64-bit long-word.
+      // Rounding modes are not yet supported.
+      DCHECK((FCSR_ & 3) == 0);
+    // In rounding mode 0 it should behave like ROUND.
+    // No break.
+    case ROUND_L_D: {  // Mips64r2 instruction.
+      // check error cases
+      double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
+      int64_t result = static_cast<int64_t>(rounded);
+      set_fpu_register(fd_reg, result);
+      if (set_fcsr_round64_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
+      }
+      break;
+    }
+    case TRUNC_L_D: {  // Mips64r2 instruction.
+      double rounded = trunc(fs);
+      int64_t result = static_cast<int64_t>(rounded);
+      set_fpu_register(fd_reg, result);
+      if (set_fcsr_round64_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
+      }
+      break;
+    }
+    case FLOOR_L_D: {  // Mips64r2 instruction.
+      double rounded = floor(fs);
+      int64_t result = static_cast<int64_t>(rounded);
+      set_fpu_register(fd_reg, result);
+      if (set_fcsr_round64_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
+      }
+      break;
+    }
+    case CEIL_L_D: {  // Mips64r2 instruction.
+      double rounded = ceil(fs);
+      int64_t result = static_cast<int64_t>(rounded);
+      set_fpu_register(fd_reg, result);
+      if (set_fcsr_round64_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
+      }
+      break;
+    }
+    case C_F_D:
+      UNIMPLEMENTED_MIPS();
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterWRsType(Instruction* instr,
+                                          const int32_t& fs_reg,
+                                          const int32_t& fd_reg,
+                                          int64_t& alu_out) {
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_S_W:  // Convert word to float (single).
+      alu_out = get_fpu_register_signed_word(fs_reg);
+      set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
+      break;
+    case CVT_D_W:  // Convert word to double.
+      alu_out = get_fpu_register_signed_word(fs_reg);
+      set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
+      break;
+    default:  // Mips64r6 CMP.S instructions unimplemented.
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
+                                          const int32_t& fs_reg,
+                                          const int32_t& fd_reg,
+                                          const int32_t& ft_reg) {
+  double fs = get_fpu_register_double(fs_reg);
+  double ft = get_fpu_register_double(ft_reg);
+  int64_t i64;
+  switch (instr->FunctionFieldRaw()) {
+    case CVT_D_L:  // Mips32r2 instruction.
+      i64 = get_fpu_register(fs_reg);
+      set_fpu_register_double(fd_reg, static_cast<double>(i64));
+      break;
+    case CVT_S_L:
+      UNIMPLEMENTED_MIPS();
+      break;
+    case CMP_AF:  // Mips64r6 CMP.D instructions.
+      UNIMPLEMENTED_MIPS();
+      break;
+    case CMP_UN:
+      if (std::isnan(fs) || std::isnan(ft)) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_EQ:
+      if (fs == ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_UEQ:
+      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_LT:
+      if (fs < ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_ULT:
+      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_LE:
+      if (fs <= ft) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_ULE:
+      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterCOP1(
+    Instruction* instr, const int64_t& rs_reg, const int64_t& rs,
+    const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt,
+    const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg,
+    const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg,
+    int64_t& alu_out) {
+  switch (instr->RsFieldRaw()) {
+    case BC1:  // Branch on coprocessor condition.
+    case BC1EQZ:
+    case BC1NEZ:
+      UNREACHABLE();
+      break;
+    case CFC1:
+      set_register(rt_reg, alu_out);
+      break;
+    case MFC1:
+    case DMFC1:
+    case MFHC1:
+      set_register(rt_reg, alu_out);
+      break;
+    case CTC1:
+      // At the moment only FCSR is supported.
+      DCHECK(fs_reg == kFCSRRegister);
+      FCSR_ = registers_[rt_reg];
+      break;
+    case MTC1:
+      // Hardware writes upper 32-bits to zero on mtc1.
+      set_fpu_register_hi_word(fs_reg, 0);
+      set_fpu_register_word(fs_reg, registers_[rt_reg]);
+      break;
+    case DMTC1:
+      set_fpu_register(fs_reg, registers_[rt_reg]);
+      break;
+    case MTHC1:
+      set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
+      break;
+    case S:
+      DecodeTypeRegisterSRsType(instr, fs_reg, fd_reg);
+      break;
+    case D:
+      DecodeTypeRegisterDRsType(instr, fs_reg, ft_reg, fd_reg);
+      break;
+    case W:
+      DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, alu_out);
+      break;
+    case L:
+      DecodeTypeRegisterLRsType(instr, fs_reg, fd_reg, ft_reg);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr,
+                                        const int32_t& fr_reg,
+                                        const int32_t& fs_reg,
+                                        const int32_t& ft_reg,
+                                        const int64_t& fd_reg) {
+  switch (instr->FunctionFieldRaw()) {
+    case MADD_D:
+      double fr, ft, fs;
+      fr = get_fpu_register_double(fr_reg);
+      fs = get_fpu_register_double(fs_reg);
+      ft = get_fpu_register_double(ft_reg);
+      set_fpu_register_double(fd_reg, fs * ft + fr);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL(
+    Instruction* instr, const int64_t& rs_reg, const int64_t& rs,
+    const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt,
+    const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg,
+    const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg,
+    int64_t& i64hilo, uint64_t& u64hilo, int64_t& alu_out, bool& do_interrupt,
+    int64_t& current_pc, int64_t& next_pc, int64_t& return_addr_reg,
+    int64_t& i128resultH, int64_t& i128resultL) {
+  switch (instr->FunctionFieldRaw()) {
+    case SELEQZ_S:
+      DCHECK(kArchVariant == kMips64r6);
+      set_register(rd_reg, rt == 0 ? rs : 0);
+      break;
+    case SELNEZ_S:
+      DCHECK(kArchVariant == kMips64r6);
+      set_register(rd_reg, rt != 0 ? rs : 0);
+      break;
+    case JR: {
+      Instruction* branch_delay_instr =
+          reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
+      BranchDelayInstructionDecode(branch_delay_instr);
+      set_pc(next_pc);
+      pc_modified_ = true;
+      break;
+    }
+    case JALR: {
+      Instruction* branch_delay_instr =
+          reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
+      BranchDelayInstructionDecode(branch_delay_instr);
+      set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
+      set_pc(next_pc);
+      pc_modified_ = true;
+      break;
+    }
+    // Instructions using HI and LO registers.
+    case MULT:
+      if (kArchVariant != kMips64r6) {
+        set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
+        set_register(HI, static_cast<int32_t>(i64hilo >> 32));
+      } else {
+        switch (instr->SaValue()) {
+          case MUL_OP:
+            set_register(rd_reg, static_cast<int32_t>(i64hilo & 0xffffffff));
+            break;
+          case MUH_OP:
+            set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32));
+            break;
+          default:
+            UNIMPLEMENTED_MIPS();
+            break;
+        }
+      }
+      break;
+    case MULTU:
+      set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
+      set_register(HI, static_cast<int32_t>(u64hilo >> 32));
+      break;
+    case DMULT:  // DMULT == D_MUL_MUH.
+      if (kArchVariant != kMips64r6) {
+        set_register(LO, static_cast<int64_t>(i128resultL));
+        set_register(HI, static_cast<int64_t>(i128resultH));
+      } else {
+        switch (instr->SaValue()) {
+          case MUL_OP:
+            set_register(rd_reg, static_cast<int64_t>(i128resultL));
+            break;
+          case MUH_OP:
+            set_register(rd_reg, static_cast<int64_t>(i128resultH));
+            break;
+          default:
+            UNIMPLEMENTED_MIPS();
+            break;
+        }
+      }
+      break;
+    case DMULTU:
+      UNIMPLEMENTED_MIPS();
+      break;
+    case DSLL:
+      set_register(rd_reg, alu_out);
+      break;
+    case DIV:
+    case DDIV:
+      switch (kArchVariant) {
+        case kMips64r2:
+          // Divide by zero and overflow was not checked in the
+          // configuration step - div and divu do not raise exceptions. On
+          // division by 0 the result will be UNPREDICTABLE. On overflow
+          // (INT_MIN/-1), return INT_MIN which is what the hardware does.
+          if (rs == INT_MIN && rt == -1) {
+            set_register(LO, INT_MIN);
+            set_register(HI, 0);
+          } else if (rt != 0) {
+            set_register(LO, rs / rt);
+            set_register(HI, rs % rt);
+          }
+          break;
+        case kMips64r6:
+          switch (instr->SaValue()) {
+            case DIV_OP:
+              if (rs == INT_MIN && rt == -1) {
+                set_register(rd_reg, INT_MIN);
+              } else if (rt != 0) {
+                set_register(rd_reg, rs / rt);
+              }
+              break;
+            case MOD_OP:
+              if (rs == INT_MIN && rt == -1) {
+                set_register(rd_reg, 0);
+              } else if (rt != 0) {
+                set_register(rd_reg, rs % rt);
+              }
+              break;
+            default:
+              UNIMPLEMENTED_MIPS();
+              break;
+          }
+          break;
+        default:
+          break;
+      }
+      break;
+    case DIVU:
+      if (rt_u != 0) {
+        set_register(LO, rs_u / rt_u);
+        set_register(HI, rs_u % rt_u);
+      }
+      break;
+    // Break and trap instructions.
+    case BREAK:
+    case TGE:
+    case TGEU:
+    case TLT:
+    case TLTU:
+    case TEQ:
+    case TNE:
+      if (do_interrupt) {
+        SoftwareInterrupt(instr);
+      }
+      break;
+    // Conditional moves.
+    case MOVN:
+      if (rt) {
+        set_register(rd_reg, rs);
+        TraceRegWr(rs);
+      }
+      break;
+    case MOVCI: {
+      uint32_t cc = instr->FBccValue();
+      uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
+      if (instr->Bit(16)) {  // Read Tf bit.
+        if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
+      } else {
+        if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
+      }
+      break;
+    }
+    case MOVZ:
+      if (!rt) {
+        set_register(rd_reg, rs);
+        TraceRegWr(rs);
+      }
+      break;
+    default:  // For other special opcodes we do the default operation.
+      set_register(rd_reg, alu_out);
+      TraceRegWr(alu_out);
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
+                                           const int64_t& rd_reg,
+                                           int64_t& alu_out) {
+  switch (instr->FunctionFieldRaw()) {
+    case MUL:
+      set_register(rd_reg, alu_out);
+      TraceRegWr(alu_out);
+      // HI and LO are UNPREDICTABLE after the operation.
+      set_register(LO, Unpredictable);
+      set_register(HI, Unpredictable);
+      break;
+    default:  // For other special2 opcodes we do the default operation.
+      set_register(rd_reg, alu_out);
+  }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
+                                           const int64_t& rt_reg,
+                                           int64_t& alu_out) {
+  switch (instr->FunctionFieldRaw()) {
+    case INS:
+      // Ins instr leaves result in Rt, rather than Rd.
+      set_register(rt_reg, alu_out);
+      TraceRegWr(alu_out);
+      break;
+    case EXT:
+    case DEXT:
+      // Dext/Ext instr leaves result in Rt, rather than Rd.
+      set_register(rt_reg, alu_out);
+      TraceRegWr(alu_out);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void Simulator::DecodeTypeRegister(Instruction* instr) {
   // Instruction fields.
   const Opcode   op     = instr->OpcodeFieldRaw();
@@ -2320,490 +2878,23 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
   // ---------- Execution.
   switch (op) {
     case COP1:
-      switch (instr->RsFieldRaw()) {
-        case BC1:   // Branch on coprocessor condition.
-        case BC1EQZ:
-        case BC1NEZ:
-          UNREACHABLE();
-          break;
-        case CFC1:
-          set_register(rt_reg, alu_out);
-          break;
-        case MFC1:
-        case DMFC1:
-        case MFHC1:
-          set_register(rt_reg, alu_out);
-          break;
-        case CTC1:
-          // At the moment only FCSR is supported.
-          DCHECK(fs_reg == kFCSRRegister);
-          FCSR_ = registers_[rt_reg];
-          break;
-        case MTC1:
-          // Hardware writes upper 32-bits to zero on mtc1.
-          set_fpu_register_hi_word(fs_reg, 0);
-          set_fpu_register_word(fs_reg, registers_[rt_reg]);
-          break;
-        case DMTC1:
-          set_fpu_register(fs_reg, registers_[rt_reg]);
-          break;
-        case MTHC1:
-          set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
-          break;
-        case S:
-          float f;
-          switch (instr->FunctionFieldRaw()) {
-            case CVT_D_S:
-              f = get_fpu_register_float(fs_reg);
-              set_fpu_register_double(fd_reg, static_cast<double>(f));
-              break;
-            default:
-            // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
-            // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
-              UNREACHABLE();
-          }
-          break;
-        case D:
-          double ft, fs;
-          uint32_t cc, fcsr_cc;
-          int64_t  i64;
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          cc = instr->FCccValue();
-          fcsr_cc = get_fcsr_condition_bit(cc);
-          switch (instr->FunctionFieldRaw()) {
-            case ADD_D:
-              set_fpu_register_double(fd_reg, fs + ft);
-              break;
-            case SUB_D:
-              set_fpu_register_double(fd_reg, fs - ft);
-              break;
-            case MUL_D:
-              set_fpu_register_double(fd_reg, fs * ft);
-              break;
-            case DIV_D:
-              set_fpu_register_double(fd_reg, fs / ft);
-              break;
-            case ABS_D:
-              set_fpu_register_double(fd_reg, fabs(fs));
-              break;
-            case MOV_D:
-              set_fpu_register_double(fd_reg, fs);
-              break;
-            case NEG_D:
-              set_fpu_register_double(fd_reg, -fs);
-              break;
-            case SQRT_D:
-              set_fpu_register_double(fd_reg, fast_sqrt(fs));
-              break;
-            case C_UN_D:
-              set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
-              break;
-            case C_EQ_D:
-              set_fcsr_bit(fcsr_cc, (fs == ft));
-              break;
-            case C_UEQ_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case C_OLT_D:
-              set_fcsr_bit(fcsr_cc, (fs < ft));
-              break;
-            case C_ULT_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case C_OLE_D:
-              set_fcsr_bit(fcsr_cc, (fs <= ft));
-              break;
-            case C_ULE_D:
-              set_fcsr_bit(fcsr_cc,
-                           (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
-              break;
-            case CVT_W_D:   // Convert double to word.
-              // Rounding modes are not yet supported.
-              DCHECK((FCSR_ & 3) == 0);
-              // In rounding mode 0 it should behave like ROUND.
-              // No break.
-            case ROUND_W_D:  // Round double to word (round half to even).
-              {
-                double rounded = std::floor(fs + 0.5);
-                int32_t result = static_cast<int32_t>(rounded);
-                if ((result & 1) != 0 && result - fs == 0.5) {
-                  // If the number is halfway between two integers,
-                  // round to the even one.
-                  result--;
-                }
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case TRUNC_W_D:  // Truncate double to word (round towards 0).
-              {
-                double rounded = trunc(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case FLOOR_W_D:  // Round double to word towards negative infinity.
-              {
-                double rounded = std::floor(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case CEIL_W_D:  // Round double to word towards positive infinity.
-              {
-                double rounded = std::ceil(fs);
-                int32_t result = static_cast<int32_t>(rounded);
-                set_fpu_register_word(fd_reg, result);
-                if (set_fcsr_round_error(fs, rounded)) {
-                  set_fpu_register(fd_reg, kFPUInvalidResult);
-                }
-              }
-              break;
-            case CVT_S_D:  // Convert double to float (single).
-              set_fpu_register_float(fd_reg, static_cast<float>(fs));
-              break;
-            case CVT_L_D:   // Mips64r2: Truncate double to 64-bit long-word.
-              // Rounding modes are not yet supported.
-              DCHECK((FCSR_ & 3) == 0);
-              // In rounding mode 0 it should behave like ROUND.
-              // No break.
-            case ROUND_L_D: {  // Mips64r2 instruction.
-              // check error cases
-              double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
-              int64_t result = static_cast<int64_t>(rounded);
-              set_fpu_register(fd_reg, result);
-              if (set_fcsr_round64_error(fs, rounded)) {
-                set_fpu_register(fd_reg, kFPU64InvalidResult);
-              }
-              break;
-            }
-            case TRUNC_L_D: {  // Mips64r2 instruction.
-              double rounded = trunc(fs);
-              int64_t result = static_cast<int64_t>(rounded);
-              set_fpu_register(fd_reg, result);
-              if (set_fcsr_round64_error(fs, rounded)) {
-                set_fpu_register(fd_reg, kFPU64InvalidResult);
-              }
-              break;
-            }
-            case FLOOR_L_D: {  // Mips64r2 instruction.
-              double rounded = floor(fs);
-              int64_t result = static_cast<int64_t>(rounded);
-              set_fpu_register(fd_reg, result);
-              if (set_fcsr_round64_error(fs, rounded)) {
-                set_fpu_register(fd_reg, kFPU64InvalidResult);
-              }
-              break;
-            }
-            case CEIL_L_D: {  // Mips64r2 instruction.
-              double rounded = ceil(fs);
-              int64_t result = static_cast<int64_t>(rounded);
-              set_fpu_register(fd_reg, result);
-              if (set_fcsr_round64_error(fs, rounded)) {
-                set_fpu_register(fd_reg, kFPU64InvalidResult);
-              }
-              break;
-            }
-            case C_F_D:
-              UNIMPLEMENTED_MIPS();
-              break;
-            default:
-              UNREACHABLE();
-          }
-          break;
-        case W:
-          switch (instr->FunctionFieldRaw()) {
-            case CVT_S_W:   // Convert word to float (single).
-              alu_out = get_fpu_register_signed_word(fs_reg);
-              set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
-              break;
-            case CVT_D_W:   // Convert word to double.
-              alu_out = get_fpu_register_signed_word(fs_reg);
-              set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
-              break;
-            default:  // Mips64r6 CMP.S instructions unimplemented.
-              UNREACHABLE();
-          }
-          break;
-        case L:
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          switch (instr->FunctionFieldRaw()) {
-            case CVT_D_L:  // Mips32r2 instruction.
-              i64 = get_fpu_register(fs_reg);
-              set_fpu_register_double(fd_reg, static_cast<double>(i64));
-              break;
-            case CVT_S_L:
-              UNIMPLEMENTED_MIPS();
-              break;
-            case CMP_AF:  // Mips64r6 CMP.D instructions.
-              UNIMPLEMENTED_MIPS();
-              break;
-            case CMP_UN:
-              if (std::isnan(fs) || std::isnan(ft)) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_EQ:
-              if (fs == ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_UEQ:
-              if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_LT:
-              if (fs < ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_ULT:
-              if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_LE:
-              if (fs <= ft) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            case CMP_ULE:
-              if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
-                set_fpu_register(fd_reg, -1);
-              } else {
-                set_fpu_register(fd_reg, 0);
-              }
-              break;
-            default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED
-              UNREACHABLE();
-          }
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg,
+                             fr_reg, fs_reg, ft_reg, fd_reg, alu_out);
       break;
     case COP1X:
-      switch (instr->FunctionFieldRaw()) {
-        case MADD_D:
-          double fr, ft, fs;
-          fr = get_fpu_register_double(fr_reg);
-          fs = get_fpu_register_double(fs_reg);
-          ft = get_fpu_register_double(ft_reg);
-          set_fpu_register_double(fd_reg, fs * ft + fr);
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg);
       break;
     case SPECIAL:
-      switch (instr->FunctionFieldRaw()) {
-        case JR: {
-          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
-              current_pc+Instruction::kInstrSize);
-          BranchDelayInstructionDecode(branch_delay_instr);
-          set_pc(next_pc);
-          pc_modified_ = true;
-          break;
-        }
-        case JALR: {
-          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
-              current_pc+Instruction::kInstrSize);
-          BranchDelayInstructionDecode(branch_delay_instr);
-          set_register(return_addr_reg,
-                       current_pc + 2 * Instruction::kInstrSize);
-          set_pc(next_pc);
-          pc_modified_ = true;
-          break;
-        }
-        // Instructions using HI and LO registers.
-        case MULT:
-          if (kArchVariant != kMips64r6) {
-            set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
-            set_register(HI, static_cast<int32_t>(i64hilo >> 32));
-          } else {
-            switch (instr->SaValue()) {
-              case MUL_OP:
-                set_register(rd_reg,
-                    static_cast<int32_t>(i64hilo & 0xffffffff));
-                break;
-              case MUH_OP:
-                set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32));
-                break;
-              default:
-                UNIMPLEMENTED_MIPS();
-                break;
-            }
-          }
-          break;
-        case MULTU:
-          set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
-          set_register(HI, static_cast<int32_t>(u64hilo >> 32));
-          break;
-        case DMULT:  // DMULT == D_MUL_MUH.
-          if (kArchVariant != kMips64r6) {
-            set_register(LO, static_cast<int64_t>(i128resultL));
-            set_register(HI, static_cast<int64_t>(i128resultH));
-          } else {
-            switch (instr->SaValue()) {
-              case MUL_OP:
-                set_register(rd_reg, static_cast<int64_t>(i128resultL));
-                break;
-              case MUH_OP:
-                set_register(rd_reg, static_cast<int64_t>(i128resultH));
-                break;
-              default:
-                UNIMPLEMENTED_MIPS();
-                break;
-            }
-          }
-          break;
-        case DMULTU:
-          UNIMPLEMENTED_MIPS();
-          break;
-        case DSLL:
-          set_register(rd_reg, alu_out);
-          break;
-        case DIV:
-        case DDIV:
-          switch (kArchVariant) {
-            case kMips64r2:
-              // Divide by zero and overflow was not checked in the
-              // configuration step - div and divu do not raise exceptions. On
-              // division by 0 the result will be UNPREDICTABLE. On overflow
-              // (INT_MIN/-1), return INT_MIN which is what the hardware does.
-              if (rs == INT_MIN && rt == -1) {
-                set_register(LO, INT_MIN);
-                set_register(HI, 0);
-              } else if (rt != 0) {
-                set_register(LO, rs / rt);
-                set_register(HI, rs % rt);
-              }
-              break;
-            case kMips64r6:
-              switch (instr->SaValue()) {
-                case DIV_OP:
-                  if (rs == INT_MIN && rt == -1) {
-                    set_register(rd_reg, INT_MIN);
-                  } else if (rt != 0) {
-                    set_register(rd_reg, rs / rt);
-                  }
-                  break;
-                case MOD_OP:
-                  if (rs == INT_MIN && rt == -1) {
-                    set_register(rd_reg, 0);
-                  } else if (rt != 0) {
-                    set_register(rd_reg, rs % rt);
-                  }
-                  break;
-                default:
-                  UNIMPLEMENTED_MIPS();
-                  break;
-              }
-              break;
-            default:
-              break;
-          }
-          break;
-        case DIVU:
-          if (rt_u != 0) {
-            set_register(LO, rs_u / rt_u);
-            set_register(HI, rs_u % rt_u);
-          }
-          break;
-        // Break and trap instructions.
-        case BREAK:
-        case TGE:
-        case TGEU:
-        case TLT:
-        case TLTU:
-        case TEQ:
-        case TNE:
-          if (do_interrupt) {
-            SoftwareInterrupt(instr);
-          }
-          break;
-        // Conditional moves.
-        case MOVN:
-          if (rt) {
-            set_register(rd_reg, rs);
-            TraceRegWr(rs);
-          }
-          break;
-        case MOVCI: {
-          uint32_t cc = instr->FBccValue();
-          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
-          if (instr->Bit(16)) {  // Read Tf bit.
-            if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
-          } else {
-            if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
-          }
-          break;
-        }
-        case MOVZ:
-          if (!rt) {
-            set_register(rd_reg, rs);
-            TraceRegWr(rs);
-          }
-          break;
-        default:  // For other special opcodes we do the default operation.
-          set_register(rd_reg, alu_out);
-          TraceRegWr(alu_out);
-      }
+      DecodeTypeRegisterSPECIAL(
+          instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, fr_reg, fs_reg,
+          ft_reg, fd_reg, i64hilo, u64hilo, alu_out, do_interrupt, current_pc,
+          next_pc, return_addr_reg, i128resultH, i128resultL);
       break;
     case SPECIAL2:
-      switch (instr->FunctionFieldRaw()) {
-        case MUL:
-          set_register(rd_reg, alu_out);
-          TraceRegWr(alu_out);
-          // HI and LO are UNPREDICTABLE after the operation.
-          set_register(LO, Unpredictable);
-          set_register(HI, Unpredictable);
-          break;
-        default:  // For other special2 opcodes we do the default operation.
-          set_register(rd_reg, alu_out);
-      }
+      DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
       break;
     case SPECIAL3:
-      switch (instr->FunctionFieldRaw()) {
-        case INS:
-          // Ins instr leaves result in Rt, rather than Rd.
-          set_register(rt_reg, alu_out);
-          TraceRegWr(alu_out);
-          break;
-        case EXT:
-        case DEXT:
-          // Dext/Ext instr leaves result in Rt, rather than Rd.
-          set_register(rt_reg, alu_out);
-          TraceRegWr(alu_out);
-          break;
-        default:
-          UNREACHABLE();
-      }
+      DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out);
       break;
     // Unimplemented opcodes raised an error in the configuration step before,
     // so we can use the default here to set the destination register in common
index 3087dcdab82232dc81de53ad67993c9db92395f6..237a244dbf2ea6fabea9ef843fa0016ec05e0949 100644 (file)
@@ -312,6 +312,45 @@ class Simulator {
   inline int32_t SetDoubleHIW(double* addr);
   inline int32_t SetDoubleLOW(double* addr);
 
+  // functions called from DecodeTypeRegister
+  void DecodeTypeRegisterCOP1(Instruction* instr, const int64_t& rs_reg,
+                              const int64_t& rs, const uint64_t& rs_u,
+                              const int64_t& rt_reg, const int64_t& rt,
+                              const uint64_t& rt_u, const int64_t& rd_reg,
+                              const int32_t& fr_reg, const int32_t& fs_reg,
+                              const int32_t& ft_reg, const int64_t& fd_reg,
+                              int64_t& alu_out);
+
+  void DecodeTypeRegisterCOP1X(Instruction* instr, const int32_t& fr_reg,
+                               const int32_t& fs_reg, const int32_t& ft_reg,
+                               const int64_t& fd_reg);
+
+  void DecodeTypeRegisterSPECIAL(
+      Instruction* instr, const int64_t& rs_reg, const int64_t& rs,
+      const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt,
+      const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg,
+      const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg,
+      int64_t& i64hilo, uint64_t& u64hilo, int64_t& alu_out, bool& do_interrupt,
+      int64_t& current_pc, int64_t& next_pc, int64_t& return_addr_reg,
+      int64_t& i128resultH, int64_t& i128resultL);
+
+  void DecodeTypeRegisterSPECIAL2(Instruction* instr, const int64_t& rd_reg,
+                                  int64_t& alu_out);
+
+  void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int64_t& rt_reg,
+                                  int64_t& alu_out);
+
+  void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t& fs_reg,
+                                 const int64_t& fd_reg);
+
+  void DecodeTypeRegisterDRsType(Instruction* instr, const int32_t& fs_reg,
+                                 const int64_t& ft_reg, const int32_t& fd_reg);
+
+  void DecodeTypeRegisterWRsType(Instruction* instr, const int32_t& fs_reg,
+                                 const int32_t& fd_reg, int64_t& alu_out);
+
+  void DecodeTypeRegisterLRsType(Instruction* instr, const int32_t& fs_reg,
+                                 const int32_t& fd_reg, const int32_t& ft_reg);
   // Executing is handled based on the instruction type.
   void DecodeTypeRegister(Instruction* instr);
 
index 730de9d45492978b6b8435d017dd8179ba65f70a..d29419e2ff18f18f37e7d1c7476f373e2e749c80 100644 (file)
@@ -48,6 +48,93 @@ typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
 
 
 #define __ assm.
+TEST(MIPS16) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test {
+    int a;
+    int b;
+    int c;
+    int d;
+    double e;
+    double f;
+    double g;
+    double h;
+    double i;
+    double j;
+    double k;
+    double l;
+  } Test;
+
+  Test test;
+  // integer part of test
+  __ addiu(t1, zero_reg, 1);                      // t1=1
+  __ seleqz(t1, zero_reg, t3);                    // t3=1
+  __ sw(t3, MemOperand(a0, OFFSET_OF(Test, a)));  // a=1
+  __ seleqz(t1, t1, t2);                          // t2=0
+  __ sw(t2, MemOperand(a0, OFFSET_OF(Test, b)));  // b=0
+  __ selnez(t1, zero_reg, t3);                    // t3=1;
+  __ sw(t3, MemOperand(a0, OFFSET_OF(Test, c)));  // c=0
+  __ selnez(t1, t1, t3);                          // t3=1
+  __ sw(t3, MemOperand(a0, OFFSET_OF(Test, d)));  // d=1
+  // floating point part of test S format
+  __ li(t0, 0x80);
+  __ mtc1(t0, f4);
+  __ cvt_d_w(f4, f4);  // f4=0x80
+  __ li(t0, 0xf3);
+  __ mtc1(t0, f6);
+  __ cvt_d_w(f6, f6);                                // f6=0xf3
+  __ seleqz(S, f8, f4, f6);                          // f8=0xf3
+  __ seleqz(S, f10, f6, f6);                         // f10=0
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, e)));   // e=0xf3
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, f)));  // f=0
+  __ selnez(S, f8, f4, f6);                          // f8=0
+  __ selnez(S, f10, f6, f6);                         // f10=0xf3*/
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, g)));   // g=0
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, h)));  // h=0xf3
+
+  __ li(t0, 0x80);
+  __ mtc1(t0, f4);
+  __ cvt_d_w(f4, f4);  // f4=0x80
+  __ li(t0, 0xf3);
+  __ mtc1(t0, f6);
+  __ cvt_d_w(f6, f6);                                // f6=0xf3
+  __ seleqz(D, f8, f4, f6);                          // f8=0xf3
+  __ seleqz(D, f10, f6, f6);                         // f10=0
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, i)));   // i=0xf3
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, j)));  // j=0
+  __ selnez(S, f8, f4, f6);                          // f8=0
+  __ selnez(S, f10, f6, f6);                         // f10=0xf3*/
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, k)));   // k=0
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, l)));  // l=0xf3
+  __ jr(ra);
+  __ nop();
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+
+  CHECK_EQ(test.a, 1);
+  CHECK_EQ(test.b, 0);
+  CHECK_EQ(test.c, 0);
+  CHECK_EQ(test.d, 1);
+
+  CHECK_EQ(test.e, 0xf3);
+  CHECK_EQ(test.f, 0x0);
+  CHECK_EQ(test.g, 0);
+  CHECK_EQ(test.h, 0xf3);
+
+  CHECK_EQ(test.i, 0xf3);
+  CHECK_EQ(test.j, 0x0);
+  CHECK_EQ(test.k, 0);
+  CHECK_EQ(test.l, 0xf3);
+}
 
 
 TEST(MIPS0) {
index e55fb24282376422c2c077f6cdb8b76eff5e5ed1..dd8841a26a84be03a2d5259d000ca74767bae58d 100644 (file)
@@ -48,6 +48,72 @@ typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
 
 #define __ assm.
 
+TEST(MIPS17) {
+  if (kArchVariant == kMips64r6) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+    MacroAssembler assm(isolate, NULL, 0);
+
+    typedef struct test {
+      int a;
+      int b;
+      int c;
+      int d;
+      double i;
+      double j;
+      double k;
+      double l;
+    } Test;
+
+    Test test;
+    // integer part of test
+    __ addiu(t1, zero_reg, 1);                      // t1=1
+    __ seleqz(t1, zero_reg, t3);                    // t3=1
+    __ sw(t3, MemOperand(a0, OFFSET_OF(Test, a)));  // a=1
+    __ seleqz(t1, t1, t2);                          // t2=0
+    __ sw(t2, MemOperand(a0, OFFSET_OF(Test, b)));  // b=0
+    __ selnez(t1, zero_reg, t3);                    // t3=1;
+    __ sw(t3, MemOperand(a0, OFFSET_OF(Test, c)));  // c=0
+    __ selnez(t1, t1, t3);                          // t3=1
+    __ sw(t3, MemOperand(a0, OFFSET_OF(Test, d)));  // d=1
+    // floating point part of test
+    __ li(t0, 0x80);
+    __ mtc1(t0, f4);
+    __ cvt_d_w(f4, f4);  // f4=0x80
+    __ li(t0, 0xf3);
+    __ mtc1(t0, f6);
+    __ cvt_d_w(f6, f6);                                // f6=0xf3
+    __ seleqz(D, f8, f4, f6);                          // f8=0xf3
+    __ seleqz(D, f10, f6, f6);                         // f10=0
+    __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, i)));   // i=0xf3
+    __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, j)));  // j=0
+    __ selnez(D, f8, f4, f6);                          // f8=0
+    __ selnez(D, f10, f6, f6);                         // f10=0xf3*/
+    __ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, k)));   // k=0
+    __ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, l)));  // l=0xf3
+    __ jr(ra);
+    __ nop();
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+
+    CHECK_EQ(test.a, 1);
+    CHECK_EQ(test.b, 0);
+    CHECK_EQ(test.c, 0);
+    CHECK_EQ(test.d, 1);
+
+    CHECK_EQ(test.i, 0xf3);
+    CHECK_EQ(test.j, 0x0);
+    CHECK_EQ(test.k, 0);
+    CHECK_EQ(test.l, 0xf3);
+  }
+}
+
 
 TEST(MIPS0) {
   CcTest::InitializeVM();
index ca928a61eb68b40206bf2e21bcc1bda8d8bd27f1..1023ca445cc85a64c5422548e9b7276fea29f5ad 100644 (file)
@@ -90,6 +90,20 @@ bool DisassembleAndCompare(byte* pc, const char* compare_string) {
 if (failure) { \
     V8_Fatal(__FILE__, __LINE__, "MIPS Disassembler tests failed.\n"); \
   }
+//  tests only seleqz, selnez, seleqz.fmt and selnez.fmt
+TEST(Type1) {
+  SET_UP();
+  if (IsMipsArchVariant(kMips32r6)) {
+    COMPARE(seleqz(a0, a1, a2), "00853035       seleqz    a0, a1, a2");
+    COMPARE(selnez(a0, a1, a2), "00853037       selnez    a0, a1, a2");
+
+    COMPARE(seleqz(S, f0, f1, f2), "45000894       seleqz.S    f0, f1, f2");
+    COMPARE(selnez(S, f0, f1, f2), "45000897       selnez.S    f0, f1, f2");
+    COMPARE(seleqz(D, f3, f4, f5), "00853035       seleqz.D    f3, f4, f5");
+    COMPARE(selnez(D, f3, f4, f5), "00853037       selnez.D    f3, f4, f5");
+  }
+  VERIFY_RUN();
+}
 
 
 TEST(Type0) {
index a2a93c611a70fda632b5d4ee47ff2b6bc6b7b4b0..638cfee3b82a9998caf1efc680a60f6ba02f9f15 100644 (file)
@@ -92,6 +92,25 @@ if (failure) { \
   }
 
 
+TEST(Type1) {
+  if (kArchVariant == kMips64r6) {
+    SET_UP();
+    COMPARE(seleqz(a0, a1, a2), "00853035       seleqz    a0, a1, a2");
+    COMPARE(selnez(a0, a1, a2), "00853037       selnez    a0, a1, a2");
+
+
+    COMPARE(seleqz(D, f3, f4, f5), "462428d4       seleqz.D    f4, f5, f3");
+    COMPARE(selnez(D, f3, f4, f5), "462428d7       selnez.D    f4, f5, f3");
+
+    /*COMPARE(min(D, f3, f4, f5),
+          "462428dc       min.D    f4, f5, f3");
+    COMPARE(max(D, f3, f4, f5),
+          "462428de       max.D    f4, f5, f3");*/
+    VERIFY_RUN();
+  }
+}
+
+
 TEST(Type0) {
   SET_UP();