MIPS64: Optimize simulator.
authorbalazs.kilvady <balazs.kilvady@imgtec.com>
Fri, 18 Sep 2015 11:08:17 +0000 (04:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 18 Sep 2015 11:08:32 +0000 (11:08 +0000)
Port 09f41681ef83fe9e9d79748e2a60f16b70d5934c

Original commit message:
The patch decreases the calls of huge switch instructions making the
DecodeType*() functions to work in one phase and optimizing
Instruction::InstructionType(). Speed gain in release full check is
about 33% (6:13 s -> 4:09 s) and in optdebug full test is about 50%
(12:29 -> 6:17)

BUG=

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

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

src/mips64/constants-mips64.cc
src/mips64/constants-mips64.h
src/mips64/disasm-mips64.cc
src/mips64/simulator-mips64.cc
src/mips64/simulator-mips64.h

index b43601c5cf3d8fe5c10fdefd4ef5933df05c2ff2..efabfe4f264c94f045386edd8a66874afd1b9380 100644 (file)
@@ -219,191 +219,6 @@ bool Instruction::IsTrap() const {
 }
 
 
-Instruction::Type Instruction::InstructionType() const {
-  switch (OpcodeFieldRaw()) {
-    case SPECIAL:
-      switch (FunctionFieldRaw()) {
-        case JR:
-        case JALR:
-        case BREAK:
-        case SLL:
-        case DSLL:
-        case DSLL32:
-        case SRL:
-        case DSRL:
-        case DSRL32:
-        case SRA:
-        case DSRA:
-        case DSRA32:
-        case SLLV:
-        case DSLLV:
-        case SRLV:
-        case DSRLV:
-        case SRAV:
-        case DSRAV:
-        case MFHI:
-        case MFLO:
-        case MULT:
-        case DMULT:
-        case MULTU:
-        case DMULTU:
-        case DIV:
-        case DDIV:
-        case DIVU:
-        case DDIVU:
-        case ADD:
-        case DADD:
-        case ADDU:
-        case DADDU:
-        case SUB:
-        case DSUB:
-        case SUBU:
-        case DSUBU:
-        case AND:
-        case OR:
-        case XOR:
-        case NOR:
-        case SLT:
-        case SLTU:
-        case TGE:
-        case TGEU:
-        case TLT:
-        case TLTU:
-        case TEQ:
-        case TNE:
-        case MOVZ:
-        case MOVN:
-        case MOVCI:
-        case SELEQZ_S:
-        case SELNEZ_S:
-          return kRegisterType;
-        default:
-          return kUnsupported;
-      }
-      break;
-    case SPECIAL2:
-      switch (FunctionFieldRaw()) {
-        case MUL:
-        case CLZ:
-          return kRegisterType;
-        default:
-          return kUnsupported;
-      }
-      break;
-    case SPECIAL3:
-      switch (FunctionFieldRaw()) {
-        case INS:
-        case EXT:
-        case DEXT:
-          return kRegisterType;
-        case BSHFL: {
-          int sa = SaFieldRaw() >> kSaShift;
-          switch (sa) {
-            case BITSWAP:
-              return kRegisterType;
-            case WSBH:
-            case SEB:
-            case SEH:
-              return kUnsupported;
-          }
-          sa >>= kBp2Bits;
-          switch (sa) {
-            case ALIGN:
-              return kRegisterType;
-            default:
-              return kUnsupported;
-          }
-        }
-        case DBSHFL: {
-          int sa = SaFieldRaw() >> kSaShift;
-          switch (sa) {
-            case DBITSWAP:
-              return kRegisterType;
-            case DSBH:
-            case DSHD:
-              return kUnsupported;
-          }
-          sa = SaFieldRaw() >> kSaShift;
-          sa >>= kBp3Bits;
-          switch (sa) {
-            case DALIGN:
-              return kRegisterType;
-            default:
-              return kUnsupported;
-          }
-        }
-        default:
-          return kUnsupported;
-      }
-      break;
-    case COP1:    // Coprocessor instructions.
-      switch (RsFieldRawNoAssert()) {
-        case BC1:   // Branch on coprocessor condition.
-        case BC1EQZ:
-        case BC1NEZ:
-          return kImmediateType;
-        default:
-          return kRegisterType;
-      }
-      break;
-    case COP1X:
-      return kRegisterType;
-    // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
-    case REGIMM:
-    case BEQ:
-    case BNE:
-    case BLEZ:
-    case BGTZ:
-    case ADDI:
-    case DADDI:
-    case ADDIU:
-    case DADDIU:
-    case SLTI:
-    case SLTIU:
-    case ANDI:
-    case ORI:
-    case XORI:
-    case LUI:
-    case BEQL:
-    case BNEL:
-    case BLEZL:
-    case BGTZL:
-    case POP66:
-    case POP76:
-    case LB:
-    case LH:
-    case LWL:
-    case LW:
-    case LWU:
-    case LD:
-    case LBU:
-    case LHU:
-    case LWR:
-    case SB:
-    case SH:
-    case SWL:
-    case SW:
-    case SD:
-    case SWR:
-    case LWC1:
-    case LDC1:
-    case SWC1:
-    case SDC1:
-    case PCREL:
-    case BC:
-    case BALC:
-      return kImmediateType;
-    // 26 bits immediate type instructions. e.g.: j imm26.
-    case J:
-    case JAL:
-      return kJumpType;
-    default:
-      return kUnsupported;
-  }
-  return kUnsupported;
-}
-
-
 }  // namespace internal
 }  // namespace v8
 
index 898a4dbb1d19418e2a767646cc03b4c3a1c13395..51e665f7ec869459bab0cfb3ff6b86d0a042062f 100644 (file)
@@ -888,8 +888,67 @@ class Instruction {
     kUnsupported = -1
   };
 
+  enum TypeChecks { NORMAL, EXTRA };
+
+
+#define OpcodeToBitNumber(opcode) \
+  (1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift))
+
+  static const uint64_t kOpcodeImmediateTypeMask =
+      OpcodeToBitNumber(REGIMM) | OpcodeToBitNumber(BEQ) |
+      OpcodeToBitNumber(BNE) | OpcodeToBitNumber(BLEZ) |
+      OpcodeToBitNumber(BGTZ) | OpcodeToBitNumber(ADDI) |
+      OpcodeToBitNumber(DADDI) | OpcodeToBitNumber(ADDIU) |
+      OpcodeToBitNumber(DADDIU) | OpcodeToBitNumber(SLTI) |
+      OpcodeToBitNumber(SLTIU) | OpcodeToBitNumber(ANDI) |
+      OpcodeToBitNumber(ORI) | OpcodeToBitNumber(XORI) |
+      OpcodeToBitNumber(LUI) | OpcodeToBitNumber(BEQL) |
+      OpcodeToBitNumber(BNEL) | OpcodeToBitNumber(BLEZL) |
+      OpcodeToBitNumber(BGTZL) | OpcodeToBitNumber(POP66) |
+      OpcodeToBitNumber(POP76) | OpcodeToBitNumber(LB) | OpcodeToBitNumber(LH) |
+      OpcodeToBitNumber(LWL) | OpcodeToBitNumber(LW) | OpcodeToBitNumber(LWU) |
+      OpcodeToBitNumber(LD) | OpcodeToBitNumber(LBU) | OpcodeToBitNumber(LHU) |
+      OpcodeToBitNumber(LWR) | OpcodeToBitNumber(SB) | OpcodeToBitNumber(SH) |
+      OpcodeToBitNumber(SWL) | OpcodeToBitNumber(SW) | OpcodeToBitNumber(SD) |
+      OpcodeToBitNumber(SWR) | OpcodeToBitNumber(LWC1) |
+      OpcodeToBitNumber(LDC1) | OpcodeToBitNumber(SWC1) |
+      OpcodeToBitNumber(SDC1) | OpcodeToBitNumber(PCREL) |
+      OpcodeToBitNumber(BC) | OpcodeToBitNumber(BALC);
+
+#define FunctionFieldToBitNumber(function) (1ULL << function)
+
+  static const uint64_t kFunctionFieldRegisterTypeMask =
+      FunctionFieldToBitNumber(JR) | FunctionFieldToBitNumber(JALR) |
+      FunctionFieldToBitNumber(BREAK) | FunctionFieldToBitNumber(SLL) |
+      FunctionFieldToBitNumber(DSLL) | FunctionFieldToBitNumber(DSLL32) |
+      FunctionFieldToBitNumber(SRL) | FunctionFieldToBitNumber(DSRL) |
+      FunctionFieldToBitNumber(DSRL32) | FunctionFieldToBitNumber(SRA) |
+      FunctionFieldToBitNumber(DSRA) | FunctionFieldToBitNumber(DSRA32) |
+      FunctionFieldToBitNumber(SLLV) | FunctionFieldToBitNumber(DSLLV) |
+      FunctionFieldToBitNumber(SRLV) | FunctionFieldToBitNumber(DSRLV) |
+      FunctionFieldToBitNumber(SRAV) | FunctionFieldToBitNumber(DSRAV) |
+      FunctionFieldToBitNumber(MFHI) | FunctionFieldToBitNumber(MFLO) |
+      FunctionFieldToBitNumber(MULT) | FunctionFieldToBitNumber(DMULT) |
+      FunctionFieldToBitNumber(MULTU) | FunctionFieldToBitNumber(DMULTU) |
+      FunctionFieldToBitNumber(DIV) | FunctionFieldToBitNumber(DDIV) |
+      FunctionFieldToBitNumber(DIVU) | FunctionFieldToBitNumber(DDIVU) |
+      FunctionFieldToBitNumber(ADD) | FunctionFieldToBitNumber(DADD) |
+      FunctionFieldToBitNumber(ADDU) | FunctionFieldToBitNumber(DADDU) |
+      FunctionFieldToBitNumber(SUB) | FunctionFieldToBitNumber(DSUB) |
+      FunctionFieldToBitNumber(SUBU) | FunctionFieldToBitNumber(DSUBU) |
+      FunctionFieldToBitNumber(AND) | FunctionFieldToBitNumber(OR) |
+      FunctionFieldToBitNumber(XOR) | FunctionFieldToBitNumber(NOR) |
+      FunctionFieldToBitNumber(SLT) | FunctionFieldToBitNumber(SLTU) |
+      FunctionFieldToBitNumber(TGE) | FunctionFieldToBitNumber(TGEU) |
+      FunctionFieldToBitNumber(TLT) | FunctionFieldToBitNumber(TLTU) |
+      FunctionFieldToBitNumber(TEQ) | FunctionFieldToBitNumber(TNE) |
+      FunctionFieldToBitNumber(MOVZ) | FunctionFieldToBitNumber(MOVN) |
+      FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
+      FunctionFieldToBitNumber(SELNEZ_S);
+
+
   // Get the encoding type of the instruction.
-  Type InstructionType() const;
+  inline Type InstructionType(TypeChecks checks = NORMAL) const;
 
 
   // Accessors for the different named fields used in the MIPS encoding.
@@ -1078,6 +1137,111 @@ const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize * 2;
 const int kInvalidStackOffset = -1;
 const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
 
+
+Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
+  if (checks == EXTRA) {
+    if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) {
+      return kImmediateType;
+    }
+  }
+  switch (OpcodeFieldRaw()) {
+    case SPECIAL:
+      if (checks == EXTRA) {
+        if (FunctionFieldToBitNumber(FunctionFieldRaw()) &
+            kFunctionFieldRegisterTypeMask) {
+          return kRegisterType;
+        } else {
+          return kUnsupported;
+        }
+      } else {
+        return kRegisterType;
+      }
+      break;
+    case SPECIAL2:
+      switch (FunctionFieldRaw()) {
+        case MUL:
+        case CLZ:
+          return kRegisterType;
+        default:
+          return kUnsupported;
+      }
+      break;
+    case SPECIAL3:
+      switch (FunctionFieldRaw()) {
+        case INS:
+        case EXT:
+        case DEXT:
+          return kRegisterType;
+        case BSHFL: {
+          int sa = SaFieldRaw() >> kSaShift;
+          switch (sa) {
+            case BITSWAP:
+              return kRegisterType;
+            case WSBH:
+            case SEB:
+            case SEH:
+              return kUnsupported;
+          }
+          sa >>= kBp2Bits;
+          switch (sa) {
+            case ALIGN:
+              return kRegisterType;
+            default:
+              return kUnsupported;
+          }
+        }
+        case DBSHFL: {
+          int sa = SaFieldRaw() >> kSaShift;
+          switch (sa) {
+            case DBITSWAP:
+              return kRegisterType;
+            case DSBH:
+            case DSHD:
+              return kUnsupported;
+          }
+          sa = SaFieldRaw() >> kSaShift;
+          sa >>= kBp3Bits;
+          switch (sa) {
+            case DALIGN:
+              return kRegisterType;
+            default:
+              return kUnsupported;
+          }
+        }
+        default:
+          return kUnsupported;
+      }
+      break;
+    case COP1:  // Coprocessor instructions.
+      switch (RsFieldRawNoAssert()) {
+        case BC1:  // Branch on coprocessor condition.
+        case BC1EQZ:
+        case BC1NEZ:
+          return kImmediateType;
+        default:
+          return kRegisterType;
+      }
+      break;
+    case COP1X:
+      return kRegisterType;
+
+    // 26 bits immediate type instructions. e.g.: j imm26.
+    case J:
+    case JAL:
+      return kJumpType;
+
+    default:
+      if (checks == NORMAL) {
+        return kImmediateType;
+      } else {
+        return kUnsupported;
+      }
+  }
+  return kUnsupported;
+}
+
+#undef OpcodeToBitNumber
+#undef FunctionFieldToBitNumber
 } }   // namespace v8::internal
 
 #endif    // #ifndef V8_MIPS_CONSTANTS_H_
index 9639cef4dce59608c5a1eb3b11f6a84bbf283489..ffab261cd11f07c05cb280a95613ae816cd43228 100644 (file)
@@ -1828,7 +1828,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
                               "%08x       ",
                               instr->InstructionBits());
-  switch (instr->InstructionType()) {
+  switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
     case Instruction::kRegisterType: {
       return DecodeTypeRegister(instr);
     }
index 9a0d8fdce8bd359b8701ac56c45396e100eecdc0..00db0c82d2f2c3769e01e9cf05f2325902cd7f89 100644 (file)
@@ -909,9 +909,6 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
   registers_[pc] = bad_ra;
   registers_[ra] = bad_ra;
   InitializeCoverage();
-  for (int i = 0; i < kNumExceptions; i++) {
-    exceptions[i] = 0;
-  }
 
   last_debugger_input_ = NULL;
 }
@@ -2175,495 +2172,25 @@ void Simulator::PrintStopInfo(uint64_t code) {
 }
 
 
-void Simulator::SignalExceptions() {
-  for (int i = 1; i < kNumExceptions; i++) {
-    if (exceptions[i] != 0) {
-      V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
-    }
-  }
+void Simulator::SignalException(Exception e) {
+  V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
+           static_cast<int>(e));
 }
 
 
 // Handle execution based on instruction types.
 
-void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
-                                      int64_t* i64hilo, uint64_t* u64hilo,
-                                      int64_t* next_pc, int* return_addr_reg,
-                                      bool* do_interrupt, int64_t* i128resultH,
-                                      int64_t* i128resultL) {
-  // Every local variable declared here needs to be const.
-  // This is to make sure that changed values are sent back to
-  // DecodeTypeRegister correctly.
-
-  // Instruction fields.
-  const Opcode   op     = instr->OpcodeFieldRaw();
-  const int32_t  rs_reg = instr->RsValue();
-  const int64_t  rs     = get_register(rs_reg);
-  const uint64_t rs_u   = static_cast<uint64_t>(rs);
-  const int32_t  rt_reg = instr->RtValue();
-  const int64_t  rt     = get_register(rt_reg);
-  const uint64_t rt_u   = static_cast<uint64_t>(rt);
-  const int32_t  rd_reg = instr->RdValue();
-  const uint64_t sa     = instr->SaValue();
-  const uint8_t bp2 = instr->Bp2Value();
-  const uint8_t bp3 = instr->Bp3Value();
-
-  const int32_t  fs_reg = instr->FsValue();
-
-
-  // ---------- Configuration.
-  switch (op) {
-    case COP1:    // Coprocessor instructions.
-      switch (instr->RsFieldRaw()) {
-        case CFC1:
-          // At the moment only FCSR is supported.
-          DCHECK(fs_reg == kFCSRRegister);
-          *alu_out = FCSR_;
-          break;
-        case MFC1:
-          *alu_out = static_cast<int64_t>(get_fpu_register_word(fs_reg));
-          break;
-        case DMFC1:
-          *alu_out = get_fpu_register(fs_reg);
-          break;
-        case MFHC1:
-          *alu_out = get_fpu_register_hi_word(fs_reg);
-          break;
-        case CTC1:
-        case MTC1:
-        case DMTC1:
-        case MTHC1:
-        case S:
-        case D:
-        case W:
-        case L:
-        case PS:
-          // Do everything in the execution step.
-          break;
-        default:
-        // BC1 BC1EQZ BC1NEZ handled in DecodeTypeImmed, should never come here.
-           UNREACHABLE();
-      }
-      break;
-    case COP1X:
-      break;
-    case SPECIAL:
-      switch (instr->FunctionFieldRaw()) {
-        case JR:
-        case JALR:
-          *next_pc = get_register(instr->RsValue());
-          *return_addr_reg = instr->RdValue();
-          break;
-        case SLL:
-          *alu_out = static_cast<int32_t>(rt) << sa;
-          break;
-        case DSLL:
-          *alu_out = rt << sa;
-          break;
-        case DSLL32:
-          *alu_out = rt << sa << 32;
-          break;
-        case SRL:
-          if (rs_reg == 0) {
-            // Regular logical right shift of a word by a fixed number of
-            // bits instruction. RS field is always equal to 0.
-            // Sign-extend the 32-bit result.
-            *alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u) >> sa);
-          } else {
-            // Logical right-rotate of a word by a fixed number of bits. This
-            // is special case of SRL instruction, added in MIPS32 Release 2.
-            // RS field is equal to 00001.
-            *alu_out = static_cast<int32_t>(
-                base::bits::RotateRight32(static_cast<const uint32_t>(rt_u),
-                                          static_cast<const uint32_t>(sa)));
-          }
-          break;
-        case DSRL:
-          *alu_out = rt_u >> sa;
-          break;
-        case DSRL32:
-          *alu_out = rt_u >> sa >> 32;
-          break;
-        case SRA:
-          *alu_out = (int32_t)rt >> sa;
-          break;
-        case DSRA:
-          *alu_out = rt >> sa;
-          break;
-        case DSRA32:
-          *alu_out = rt >> sa >> 32;
-          break;
-        case SLLV:
-          *alu_out = (int32_t)rt << rs;
-          break;
-        case DSLLV:
-          *alu_out = rt << rs;
-          break;
-        case SRLV:
-          if (sa == 0) {
-            // Regular logical right-shift of a word by a variable number of
-            // bits instruction. SA field is always equal to 0.
-            *alu_out = static_cast<int32_t>((uint32_t)rt_u >> rs);
-          } else {
-            // Logical right-rotate of a word by a variable number of bits.
-            // This is special case od SRLV instruction, added in MIPS32
-            // Release 2. SA field is equal to 00001.
-            *alu_out = static_cast<int32_t>(
-                base::bits::RotateRight32(static_cast<const uint32_t>(rt_u),
-                                          static_cast<const uint32_t>(rs_u)));
-          }
-          break;
-        case DSRLV:
-          if (sa == 0) {
-            // Regular logical right-shift of a word by a variable number of
-            // bits instruction. SA field is always equal to 0.
-            *alu_out = rt_u >> rs;
-          } else {
-            // Logical right-rotate of a word by a variable number of bits.
-            // This is special case od SRLV instruction, added in MIPS32
-            // Release 2. SA field is equal to 00001.
-            *alu_out =
-                base::bits::RotateRight32(static_cast<const uint32_t>(rt_u),
-                                          static_cast<const uint32_t>(rs_u));
-          }
-          break;
-        case SRAV:
-          *alu_out = (int32_t)rt >> rs;
-          break;
-        case DSRAV:
-          *alu_out = rt >> rs;
-          break;
-        case MFHI:  // MFHI == CLZ on R6.
-          if (kArchVariant != kMips64r6) {
-            DCHECK(instr->SaValue() == 0);
-            *alu_out = get_register(HI);
-          } else {
-            // MIPS spec: If no bits were set in GPR rs, the result written to
-            // GPR rd is 32.
-            DCHECK(instr->SaValue() == 1);
-            *alu_out =
-                base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u));
-          }
-          break;
-        case MFLO:
-          *alu_out = get_register(LO);
-          break;
-        case MULT: {  // MULT == D_MUL_MUH.
-          int32_t rs_lo = static_cast<int32_t>(rs);
-          int32_t rt_lo = static_cast<int32_t>(rt);
-          *i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
-          break;
-        }
-        case MULTU:
-          *u64hilo = static_cast<uint64_t>(rs_u & 0xffffffff) *
-                     static_cast<uint64_t>(rt_u & 0xffffffff);
-          break;
-        case DMULT:  // DMULT == D_MUL_MUH.
-          if (kArchVariant != kMips64r6) {
-            *i128resultH = MultiplyHighSigned(rs, rt);
-            *i128resultL = rs * rt;
-          } else {
-            switch (instr->SaValue()) {
-              case MUL_OP:
-                *i128resultL = rs * rt;
-                break;
-              case MUH_OP:
-                *i128resultH = MultiplyHighSigned(rs, rt);
-                break;
-              default:
-                UNIMPLEMENTED_MIPS();
-                break;
-            }
-          }
-          break;
-        case DMULTU:
-          UNIMPLEMENTED_MIPS();
-          break;
-        case ADD:
-        case DADD:
-          if (HaveSameSign(rs, rt)) {
-            if (rs > 0) {
-              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
-            } else if (rs < 0) {
-              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
-            }
-          }
-          *alu_out = rs + rt;
-          break;
-        case ADDU: {
-          int32_t alu32_out = static_cast<int32_t>(rs + rt);
-          // Sign-extend result of 32bit operation into 64bit register.
-          *alu_out = static_cast<int64_t>(alu32_out);
-          break;
-        }
-        case DADDU:
-          *alu_out = rs + rt;
-          break;
-        case SUB:
-        case DSUB:
-          if (!HaveSameSign(rs, rt)) {
-            if (rs > 0) {
-              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
-            } else if (rs < 0) {
-              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
-            }
-          }
-          *alu_out = rs - rt;
-          break;
-        case SUBU: {
-          int32_t alu32_out = static_cast<int32_t>(rs - rt);
-          // Sign-extend result of 32bit operation into 64bit register.
-          *alu_out = static_cast<int64_t>(alu32_out);
-          break;
-        }
-        case DSUBU:
-          *alu_out = rs - rt;
-          break;
-        case AND:
-          *alu_out = rs & rt;
-          break;
-        case OR:
-          *alu_out = rs | rt;
-          break;
-        case XOR:
-          *alu_out = rs ^ rt;
-          break;
-        case NOR:
-          *alu_out = ~(rs | rt);
-          break;
-        case SLT:
-          *alu_out = rs < rt ? 1 : 0;
-          break;
-        case SLTU:
-          *alu_out = rs_u < rt_u ? 1 : 0;
-          break;
-        // Break and trap instructions.
-        case BREAK:
-
-          *do_interrupt = true;
-          break;
-        case TGE:
-          *do_interrupt = rs >= rt;
-          break;
-        case TGEU:
-          *do_interrupt = rs_u >= rt_u;
-          break;
-        case TLT:
-          *do_interrupt = rs < rt;
-          break;
-        case TLTU:
-          *do_interrupt = rs_u < rt_u;
-          break;
-        case TEQ:
-          *do_interrupt = rs == rt;
-          break;
-        case TNE:
-          *do_interrupt = rs != rt;
-          break;
-        case MOVN:
-        case MOVZ:
-        case MOVCI:
-          // No action taken on decode.
-          break;
-        case DIV:
-        case DIVU:
-        case DDIV:
-        case DDIVU:
-          // div and divu never raise exceptions.
-          break;
-        case SELEQZ_S:
-        case SELNEZ_S:
-          break;
-        default:
-          UNREACHABLE();
-      }
-      break;
-    case SPECIAL2:
-      switch (instr->FunctionFieldRaw()) {
-        case MUL:
-          // Only the lower 32 bits are kept.
-          *alu_out = (int32_t)rs_u * (int32_t)rt_u;
-          break;
-        case CLZ:
-          // MIPS32 spec: If no bits were set in GPR rs, the result written to
-          // GPR rd is 32.
-          *alu_out =
-              base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u));
-          break;
-        default:
-          UNREACHABLE();
-      }
-      break;
-    case SPECIAL3:
-      switch (instr->FunctionFieldRaw()) {
-        case INS: {   // Mips32r2 instruction.
-          // Interpret rd field as 5-bit msb of insert.
-          uint16_t msb = rd_reg;
-          // Interpret sa field as 5-bit lsb of insert.
-          uint16_t lsb = sa;
-          uint16_t size = msb - lsb + 1;
-          uint64_t mask = (1ULL << size) - 1;
-          *alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
-          break;
-        }
-        case EXT: {   // Mips32r2 instruction.
-          // Interpret rd field as 5-bit msb of extract.
-          uint16_t msb = rd_reg;
-          // Interpret sa field as 5-bit lsb of extract.
-          uint16_t lsb = sa;
-          uint16_t size = msb + 1;
-          uint64_t mask = (1ULL << size) - 1;
-          *alu_out = static_cast<int32_t>((rs_u & (mask << lsb)) >> lsb);
-          break;
-        }
-        case DEXT: {  // Mips32r2 instruction.
-          // Interpret rd field as 5-bit msb of extract.
-          uint16_t msb = rd_reg;
-          // Interpret sa field as 5-bit lsb of extract.
-          uint16_t lsb = sa;
-          uint16_t size = msb + 1;
-          uint64_t mask = (1ULL << size) - 1;
-          *alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb);
-          break;
-        }
-        case BSHFL: {
-          int sa = instr->SaFieldRaw() >> kSaShift;
-          switch (sa) {
-            case BITSWAP: {
-              uint32_t input = static_cast<uint32_t>(rt);
-              uint32_t output = 0;
-              uint8_t i_byte, o_byte;
-
-              // Reverse the bit in byte for each individual byte
-              for (int i = 0; i < 4; i++) {
-                output = output >> 8;
-                i_byte = input & 0xff;
-
-                // Fast way to reverse bits in byte
-                // Devised by Sean Anderson, July 13, 2001
-                o_byte =
-                    static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
-                                          (i_byte * 0x8020LU & 0x88440LU)) *
-                                             0x10101LU >>
-                                         16);
-
-                output = output | (static_cast<uint32_t>(o_byte << 24));
-                input = input >> 8;
-              }
-
-              *alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
-              break;
-            }
-            case SEB:
-            case SEH:
-            case WSBH:
-              UNREACHABLE();
-              break;
-            default: {
-              sa >>= kBp2Bits;
-              switch (sa) {
-                case ALIGN: {
-                  if (bp2 == 0) {
-                    *alu_out = static_cast<int32_t>(rt);
-                  } else {
-                    uint64_t rt_hi = rt << (8 * bp2);
-                    uint64_t rs_lo = rs >> (8 * (4 - bp2));
-                    *alu_out = static_cast<int32_t>(rt_hi | rs_lo);
-                  }
-                  break;
-                }
-                default:
-                  UNREACHABLE();
-                  break;
-              }
-              break;
-            }
-          }
-          break;
-        }
-        case DBSHFL: {
-          int sa = instr->SaFieldRaw() >> kSaShift;
-          switch (sa) {
-            case DBITSWAP: {
-              switch (instr->SaFieldRaw() >> kSaShift) {
-                case DBITSWAP_SA: {  // Mips64r6
-                  uint64_t input = static_cast<uint64_t>(rt);
-                  uint64_t output = 0;
-                  uint8_t i_byte, o_byte;
-
-                  // Reverse the bit in byte for each individual byte
-                  for (int i = 0; i < 8; i++) {
-                    output = output >> 8;
-                    i_byte = input & 0xff;
-
-                    // Fast way to reverse bits in byte
-                    // Devised by Sean Anderson, July 13, 2001
-                    o_byte =
-                        static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
-                                              (i_byte * 0x8020LU & 0x88440LU)) *
-                                                 0x10101LU >>
-                                             16);
-
-                    output = output | ((static_cast<uint64_t>(o_byte) << 56));
-                    input = input >> 8;
-                  }
-
-                  *alu_out = static_cast<int64_t>(output);
-                  break;
-                }
-              }
-              break;
-            }
-            case DSBH:
-            case DSHD:
-              UNREACHABLE();
-              break;
-            default: {
-              sa >>= kBp3Bits;
-              switch (sa) {
-                case DALIGN: {
-                  if (bp3 == 0) {
-                    *alu_out = static_cast<int64_t>(rt);
-                  } else {
-                    uint64_t rt_hi = rt << (8 * bp3);
-                    uint64_t rs_lo = rs >> (8 * (8 - bp3));
-                    *alu_out = static_cast<int64_t>(rt_hi | rs_lo);
-                  }
-                  break;
-                }
-                default:
-                  UNREACHABLE();
-                  break;
-              }
-              break;
-            }
-          }
-          break;
-        }
-        default:
-          UNREACHABLE();
-      }
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
-                                          const int32_t fs_reg,
-                                          const int32_t ft_reg,
-                                          const int32_t fd_reg) {
+void Simulator::DecodeTypeRegisterSRsType() {
   float fs, ft, fd;
-  fs = get_fpu_register_float(fs_reg);
-  ft = get_fpu_register_float(ft_reg);
-  fd = get_fpu_register_float(fd_reg);
+  fs = get_fpu_register_float(fs_reg());
+  ft = get_fpu_register_float(ft_reg());
+  fd = get_fpu_register_float(fd_reg());
   int32_t ft_int = bit_cast<int32_t>(ft);
   int32_t fd_int = bit_cast<int32_t>(fd);
   uint32_t cc, fcsr_cc;
-  cc = instr->FCccValue();
+  cc = get_instr()->FCccValue();
   fcsr_cc = get_fcsr_condition_bit(cc);
-  switch (instr->FunctionFieldRaw()) {
+  switch (get_instr()->FunctionFieldRaw()) {
     case RINT: {
       DCHECK(kArchVariant == kMips64r6);
       float result, temp_result;
@@ -2696,44 +2223,44 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
           result = lower;
           break;
       }
-      set_fpu_register_float(fd_reg, result);
+      set_fpu_register_float(fd_reg(), result);
       if (result != fs) {
         set_fcsr_bit(kFCSRInexactFlagBit, true);
       }
       break;
     }
     case ADD_S:
-      set_fpu_register_float(fd_reg, fs + ft);
+      set_fpu_register_float(fd_reg(), fs + ft);
       break;
     case SUB_S:
-      set_fpu_register_float(fd_reg, fs - ft);
+      set_fpu_register_float(fd_reg(), fs - ft);
       break;
     case MUL_S:
-      set_fpu_register_float(fd_reg, fs * ft);
+      set_fpu_register_float(fd_reg(), fs * ft);
       break;
     case DIV_S:
-      set_fpu_register_float(fd_reg, fs / ft);
+      set_fpu_register_float(fd_reg(), fs / ft);
       break;
     case ABS_S:
-      set_fpu_register_float(fd_reg, fabs(fs));
+      set_fpu_register_float(fd_reg(), fabs(fs));
       break;
     case MOV_S:
-      set_fpu_register_float(fd_reg, fs);
+      set_fpu_register_float(fd_reg(), fs);
       break;
     case NEG_S:
-      set_fpu_register_float(fd_reg, -fs);
+      set_fpu_register_float(fd_reg(), -fs);
       break;
     case SQRT_S:
-      set_fpu_register_float(fd_reg, fast_sqrt(fs));
+      set_fpu_register_float(fd_reg(), fast_sqrt(fs));
       break;
     case RSQRT_S: {
       float result = 1.0 / fast_sqrt(fs);
-      set_fpu_register_float(fd_reg, result);
+      set_fpu_register_float(fd_reg(), result);
       break;
     }
     case RECIP_S: {
       float result = 1.0 / fs;
-      set_fpu_register_float(fd_reg, result);
+      set_fpu_register_float(fd_reg(), result);
       break;
     }
     case C_F_D:
@@ -2761,7 +2288,7 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
       break;
     case CVT_D_S:
-      set_fpu_register_double(fd_reg, static_cast<double>(fs));
+      set_fpu_register_double(fd_reg(), static_cast<double>(fs));
       break;
     case CLASS_S: {  // Mips64r6 instruction
       // Convert float input to uint32_t for easier bit manipulation
@@ -2824,7 +2351,7 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       DCHECK(result != 0);
 
       fResult = bit_cast<float>(result);
-      set_fpu_register_float(fd_reg, fResult);
+      set_fpu_register_float(fd_reg(), fResult);
 
       break;
     }
@@ -2832,9 +2359,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       float rounded;
       int64_t result;
       round64_according_to_fcsr(fs, rounded, result, fs);
-      set_fpu_register(fd_reg, result);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
@@ -2842,26 +2369,26 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       float rounded;
       int32_t result;
       round_according_to_fcsr(fs, rounded, result, fs);
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+        set_fpu_register_word(fd_reg(), kFPUInvalidResult);
       }
       break;
     }
     case TRUNC_W_S: {  // Truncate single to word (round towards 0).
       float rounded = trunc(fs);
       int32_t result = static_cast<int32_t>(rounded);
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+        set_fpu_register_word(fd_reg(), kFPUInvalidResult);
       }
     } break;
     case TRUNC_L_S: {  // Mips64r2 instruction.
       float rounded = trunc(fs);
       int64_t result = static_cast<int64_t>(rounded);
-      set_fpu_register(fd_reg, result);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
@@ -2873,9 +2400,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
         // round to the even one.
         result--;
       }
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+        set_fpu_register_word(fd_reg(), kFPUInvalidResult);
       }
       break;
     }
@@ -2888,18 +2415,18 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
         result--;
       }
       int64_t i64 = static_cast<int64_t>(result);
-      set_fpu_register(fd_reg, i64);
+      set_fpu_register(fd_reg(), i64);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
     case FLOOR_L_S: {  // Mips64r2 instruction.
       float rounded = floor(fs);
       int64_t result = static_cast<int64_t>(rounded);
-      set_fpu_register(fd_reg, result);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
@@ -2907,38 +2434,38 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
     {
       float rounded = std::floor(fs);
       int32_t result = static_cast<int32_t>(rounded);
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+        set_fpu_register_word(fd_reg(), kFPUInvalidResult);
       }
     } break;
     case CEIL_W_S:  // Round double to word towards positive infinity.
     {
       float rounded = std::ceil(fs);
       int32_t result = static_cast<int32_t>(rounded);
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        set_fpu_register(fd_reg(), kFPUInvalidResult);
       }
     } break;
     case CEIL_L_S: {  // Mips64r2 instruction.
       float rounded = ceil(fs);
       int64_t result = static_cast<int64_t>(rounded);
-      set_fpu_register(fd_reg, result);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
     case MINA:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_float(fs_reg);
+      fs = get_fpu_register_float(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, ft);
+        set_fpu_register_float(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else {
         float result;
         if (fabs(fs) > fabs(ft)) {
@@ -2948,18 +2475,18 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
         } else {
           result = (fs > ft ? fs : ft);
         }
-        set_fpu_register_float(fd_reg, result);
+        set_fpu_register_float(fd_reg(), result);
       }
       break;
     case MAXA:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_float(fs_reg);
+      fs = get_fpu_register_float(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, ft);
+        set_fpu_register_float(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else {
         float result;
         if (fabs(fs) < fabs(ft)) {
@@ -2969,78 +2496,76 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
         } else {
           result = (fs > ft ? fs : ft);
         }
-        set_fpu_register_float(fd_reg, result);
+        set_fpu_register_float(fd_reg(), result);
       }
       break;
     case MIN:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_float(fs_reg);
+      fs = get_fpu_register_float(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, ft);
+        set_fpu_register_float(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else {
-        set_fpu_register_float(fd_reg, (fs >= ft) ? ft : fs);
+        set_fpu_register_float(fd_reg(), (fs >= ft) ? ft : fs);
       }
       break;
     case MAX:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_float(fs_reg);
+      fs = get_fpu_register_float(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, ft);
+        set_fpu_register_float(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_float(fd_reg, fs);
+        set_fpu_register_float(fd_reg(), fs);
       } else {
-        set_fpu_register_float(fd_reg, (fs <= ft) ? ft : fs);
+        set_fpu_register_float(fd_reg(), (fs <= ft) ? ft : fs);
       }
       break;
     case SEL:
       DCHECK(kArchVariant == kMips64r6);
-      set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
+      set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
       break;
     case SELEQZ_C:
       DCHECK(kArchVariant == kMips64r6);
-      set_fpu_register_float(
-          fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg) : 0.0);
+      set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
+                                           ? get_fpu_register_float(fs_reg())
+                                           : 0.0);
       break;
     case SELNEZ_C:
       DCHECK(kArchVariant == kMips64r6);
-      set_fpu_register_float(
-          fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg) : 0.0);
+      set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
+                                           ? get_fpu_register_float(fs_reg())
+                                           : 0.0);
       break;
     case MOVZ_C: {
       DCHECK(kArchVariant == kMips64r2);
-      int32_t rt_reg = instr->RtValue();
-      int64_t rt = get_register(rt_reg);
-      if (rt == 0) {
-        set_fpu_register_float(fd_reg, fs);
+      if (rt() == 0) {
+        set_fpu_register_float(fd_reg(), fs);
       }
       break;
     }
     case MOVN_C: {
       DCHECK(kArchVariant == kMips64r2);
-      int32_t rt_reg = instr->RtValue();
-      int64_t rt = get_register(rt_reg);
-      if (rt != 0) {
-        set_fpu_register_float(fd_reg, fs);
+      if (rt() != 0) {
+        set_fpu_register_float(fd_reg(), fs);
       }
       break;
     }
     case MOVF: {
       // Same function field for MOVT.D and MOVF.D
-      uint32_t ft_cc = (ft_reg >> 2) & 0x7;
+      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
       ft_cc = get_fcsr_condition_bit(ft_cc);
 
-      if (instr->Bit(16)) {  // Read Tf bit.
+      if (get_instr()->Bit(16)) {  // Read Tf bit.
         // MOVT.D
-        if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs);
+        if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
       } else {
         // MOVF.D
-        if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs);
+        if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
       }
       break;
     }
@@ -3052,21 +2577,19 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
 }
 
 
-void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
-                                          const int32_t fs_reg,
-                                          const int32_t ft_reg,
-                                          const int32_t fd_reg) {
+void Simulator::DecodeTypeRegisterDRsType() {
   double ft, fs, fd;
   uint32_t cc, fcsr_cc;
-  fs = get_fpu_register_double(fs_reg);
-  ft = (instr->FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg)
-                                           : 0.0;
-  fd = get_fpu_register_double(fd_reg);
-  cc = instr->FCccValue();
+  fs = get_fpu_register_double(fs_reg());
+  ft = (get_instr()->FunctionFieldRaw() != MOVF)
+           ? get_fpu_register_double(ft_reg())
+           : 0.0;
+  fd = get_fpu_register_double(fd_reg());
+  cc = get_instr()->FCccValue();
   fcsr_cc = get_fcsr_condition_bit(cc);
   int64_t ft_int = bit_cast<int64_t>(ft);
   int64_t fd_int = bit_cast<int64_t>(fd);
-  switch (instr->FunctionFieldRaw()) {
+  switch (get_instr()->FunctionFieldRaw()) {
     case RINT: {
       DCHECK(kArchVariant == kMips64r6);
       double result, temp, temp_result;
@@ -3098,7 +2621,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
           result = lower;
           break;
       }
-      set_fpu_register_double(fd_reg, result);
+      set_fpu_register_double(fd_reg(), result);
       if (result != fs) {
         set_fcsr_bit(kFCSRInexactFlagBit, true);
       }
@@ -3106,56 +2629,52 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
     }
     case SEL:
       DCHECK(kArchVariant == kMips64r6);
-      set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
+      set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
       break;
     case SELEQZ_C:
       DCHECK(kArchVariant == kMips64r6);
-      set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0);
+      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);
+      set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
       break;
     case MOVZ_C: {
       DCHECK(kArchVariant == kMips64r2);
-      int32_t rt_reg = instr->RtValue();
-      int64_t rt = get_register(rt_reg);
-      if (rt == 0) {
-        set_fpu_register_double(fd_reg, fs);
+      if (rt() == 0) {
+        set_fpu_register_double(fd_reg(), fs);
       }
       break;
     }
     case MOVN_C: {
       DCHECK(kArchVariant == kMips64r2);
-      int32_t rt_reg = instr->RtValue();
-      int64_t rt = get_register(rt_reg);
-      if (rt != 0) {
-        set_fpu_register_double(fd_reg, fs);
+      if (rt() != 0) {
+        set_fpu_register_double(fd_reg(), fs);
       }
       break;
     }
     case MOVF: {
       // Same function field for MOVT.D and MOVF.D
-      uint32_t ft_cc = (ft_reg >> 2) & 0x7;
+      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
       ft_cc = get_fcsr_condition_bit(ft_cc);
-      if (instr->Bit(16)) {  // Read Tf bit.
+      if (get_instr()->Bit(16)) {  // Read Tf bit.
         // MOVT.D
-        if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs);
+        if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
       } else {
         // MOVF.D
-        if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs);
+        if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
       }
       break;
     }
     case MINA:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_double(fs_reg);
+      fs = get_fpu_register_double(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, ft);
+        set_fpu_register_double(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else {
         double result;
         if (fabs(fs) > fabs(ft)) {
@@ -3165,18 +2684,18 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
         } else {
           result = (fs > ft ? fs : ft);
         }
-        set_fpu_register_double(fd_reg, result);
+        set_fpu_register_double(fd_reg(), result);
       }
       break;
     case MAXA:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_double(fs_reg);
+      fs = get_fpu_register_double(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, ft);
+        set_fpu_register_double(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else {
         double result;
         if (fabs(fs) < fabs(ft)) {
@@ -3186,67 +2705,67 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
         } else {
           result = (fs > ft ? fs : ft);
         }
-        set_fpu_register_double(fd_reg, result);
+        set_fpu_register_double(fd_reg(), result);
       }
       break;
     case MIN:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_double(fs_reg);
+      fs = get_fpu_register_double(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, ft);
+        set_fpu_register_double(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else {
-        set_fpu_register_double(fd_reg, (fs >= ft) ? ft : fs);
+        set_fpu_register_double(fd_reg(), (fs >= ft) ? ft : fs);
       }
       break;
     case MAX:
       DCHECK(kArchVariant == kMips64r6);
-      fs = get_fpu_register_double(fs_reg);
+      fs = get_fpu_register_double(fs_reg());
       if (std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else if (std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, ft);
+        set_fpu_register_double(fd_reg(), ft);
       } else if (!std::isnan(fs) && std::isnan(ft)) {
-        set_fpu_register_double(fd_reg, fs);
+        set_fpu_register_double(fd_reg(), fs);
       } else {
-        set_fpu_register_double(fd_reg, (fs <= ft) ? ft : fs);
+        set_fpu_register_double(fd_reg(), (fs <= ft) ? ft : fs);
       }
       break;
     case ADD_D:
-      set_fpu_register_double(fd_reg, fs + ft);
+      set_fpu_register_double(fd_reg(), fs + ft);
       break;
     case SUB_D:
-      set_fpu_register_double(fd_reg, fs - ft);
+      set_fpu_register_double(fd_reg(), fs - ft);
       break;
     case MUL_D:
-      set_fpu_register_double(fd_reg, fs * ft);
+      set_fpu_register_double(fd_reg(), fs * ft);
       break;
     case DIV_D:
-      set_fpu_register_double(fd_reg, fs / ft);
+      set_fpu_register_double(fd_reg(), fs / ft);
       break;
     case ABS_D:
-      set_fpu_register_double(fd_reg, fabs(fs));
+      set_fpu_register_double(fd_reg(), fabs(fs));
       break;
     case MOV_D:
-      set_fpu_register_double(fd_reg, fs);
+      set_fpu_register_double(fd_reg(), fs);
       break;
     case NEG_D:
-      set_fpu_register_double(fd_reg, -fs);
+      set_fpu_register_double(fd_reg(), -fs);
       break;
     case SQRT_D:
-      set_fpu_register_double(fd_reg, fast_sqrt(fs));
+      set_fpu_register_double(fd_reg(), fast_sqrt(fs));
       break;
     case RSQRT_D: {
       double result = 1.0 / fast_sqrt(fs);
-      set_fpu_register_double(fd_reg, result);
+      set_fpu_register_double(fd_reg(), result);
       break;
     }
     case RECIP_D: {
       double result = 1.0 / fs;
-      set_fpu_register_double(fd_reg, result);
+      set_fpu_register_double(fd_reg(), result);
       break;
     }
     case C_UN_D:
@@ -3274,9 +2793,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       double rounded;
       int32_t result;
       round_according_to_fcsr(fs, rounded, result, fs);
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+        set_fpu_register_word(fd_reg(), kFPUInvalidResult);
       }
       break;
     }
@@ -3289,48 +2808,48 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
         // round to the even one.
         result--;
       }
-      set_fpu_register_word(fd_reg, result);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        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);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        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);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        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);
+      set_fpu_register_word(fd_reg(), result);
       if (set_fcsr_round_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        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));
+      set_fpu_register_float(fd_reg(), static_cast<float>(fs));
       break;
     case CVT_L_D: {  // Mips64r2: Truncate double to 64-bit long-word.
       double rounded;
       int64_t result;
       round64_according_to_fcsr(fs, rounded, result, fs);
-      set_fpu_register(fd_reg, result);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
@@ -3343,36 +2862,36 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
         result--;
       }
       int64_t i64 = static_cast<int64_t>(result);
-      set_fpu_register(fd_reg, i64);
+      set_fpu_register(fd_reg(), i64);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        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);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        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);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        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);
+      set_fpu_register(fd_reg(), result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPU64InvalidResult);
+        set_fpu_register(fd_reg(), kFPU64InvalidResult);
       }
       break;
     }
@@ -3437,7 +2956,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       DCHECK(result != 0);
 
       dResult = bit_cast<double>(result);
-      set_fpu_register_double(fd_reg, dResult);
+      set_fpu_register_double(fd_reg(), dResult);
 
       break;
     }
@@ -3451,93 +2970,90 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
 }
 
 
-void Simulator::DecodeTypeRegisterWRsType(Instruction* instr,
-                                          const int32_t fs_reg,
-                                          const int32_t fd_reg,
-                                          const int32_t ft_reg,
-                                          int64_t& alu_out) {
-  float fs = get_fpu_register_float(fs_reg);
-  float ft = get_fpu_register_float(ft_reg);
-  switch (instr->FunctionFieldRaw()) {
+void Simulator::DecodeTypeRegisterWRsType() {
+  float fs = get_fpu_register_float(fs_reg());
+  float ft = get_fpu_register_float(ft_reg());
+  int64_t alu_out = 0x12345678;
+  switch (get_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));
+      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));
+      alu_out = get_fpu_register_signed_word(fs_reg());
+      set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
       break;
     case CMP_AF:
-      set_fpu_register_word(fd_reg, 0);
+      set_fpu_register_word(fd_reg(), 0);
       break;
     case CMP_UN:
       if (std::isnan(fs) || std::isnan(ft)) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_EQ:
       if (fs == ft) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_UEQ:
       if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_LT:
       if (fs < ft) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_ULT:
       if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_LE:
       if (fs <= ft) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_ULE:
       if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_OR:
       if (!std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_UNE:
       if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     case CMP_NE:
       if (fs != ft) {
-        set_fpu_register_word(fd_reg, -1);
+        set_fpu_register_word(fd_reg(), -1);
       } else {
-        set_fpu_register_word(fd_reg, 0);
+        set_fpu_register_word(fd_reg(), 0);
       }
       break;
     default:
@@ -3546,93 +3062,90 @@ void Simulator::DecodeTypeRegisterWRsType(Instruction* instr,
 }
 
 
-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);
+void Simulator::DecodeTypeRegisterLRsType() {
+  double fs = get_fpu_register_double(fs_reg());
+  double ft = get_fpu_register_double(ft_reg());
   int64_t i64;
-  switch (instr->FunctionFieldRaw()) {
+  switch (get_instr()->FunctionFieldRaw()) {
     case CVT_D_L:  // Mips32r2 instruction.
-      i64 = get_fpu_register(fs_reg);
-      set_fpu_register_double(fd_reg, static_cast<double>(i64));
+      i64 = get_fpu_register(fs_reg());
+      set_fpu_register_double(fd_reg(), static_cast<double>(i64));
       break;
     case CVT_S_L:
-      i64 = get_fpu_register(fs_reg);
-      set_fpu_register_float(fd_reg, static_cast<float>(i64));
+      i64 = get_fpu_register(fs_reg());
+      set_fpu_register_float(fd_reg(), static_cast<float>(i64));
       break;
     case CMP_AF:
-      set_fpu_register(fd_reg, 0);
+      set_fpu_register(fd_reg(), 0);
       break;
     case CMP_UN:
       if (std::isnan(fs) || std::isnan(ft)) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_EQ:
       if (fs == ft) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        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);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_LT:
       if (fs < ft) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        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);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_LE:
       if (fs <= ft) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        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);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_OR:
       if (!std::isnan(fs) && !std::isnan(ft)) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_UNE:
       if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     case CMP_NE:
       if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
-        set_fpu_register(fd_reg, -1);
+        set_fpu_register(fd_reg(), -1);
       } else {
-        set_fpu_register(fd_reg, 0);
+        set_fpu_register(fd_reg(), 0);
       }
       break;
     default:
@@ -3640,54 +3153,56 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
   }
 }
 
-void Simulator::DecodeTypeRegisterCOP1(
-    Instruction* instr, const int32_t rs_reg, const int64_t rs,
-    const uint64_t rs_u, const int32_t rt_reg, const int64_t rt,
-    const uint64_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& alu_out) {
-  switch (instr->RsFieldRaw()) {
+
+void Simulator::DecodeTypeRegisterCOP1() {
+  switch (get_instr()->RsFieldRaw()) {
     case BC1:  // Branch on coprocessor condition.
     case BC1EQZ:
     case BC1NEZ:
       UNREACHABLE();
       break;
     case CFC1:
-      set_register(rt_reg, alu_out);
+      // At the moment only FCSR is supported.
+      DCHECK(fs_reg() == kFCSRRegister);
+      set_register(rt_reg(), FCSR_);
       break;
     case MFC1:
+      set_register(rt_reg(),
+                   static_cast<int64_t>(get_fpu_register_word(fs_reg())));
+      break;
     case DMFC1:
+      set_register(rt_reg(), get_fpu_register(fs_reg()));
+      break;
     case MFHC1:
-      set_register(rt_reg, alu_out);
+      set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
       break;
     case CTC1:
       // At the moment only FCSR is supported.
-      DCHECK(fs_reg == kFCSRRegister);
-      FCSR_ = static_cast<uint32_t>(registers_[rt_reg]);
+      DCHECK(fs_reg() == kFCSRRegister);
+      FCSR_ = static_cast<uint32_t>(rt());
       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, static_cast<int32_t>(registers_[rt_reg]));
+      set_fpu_register_hi_word(fs_reg(), 0);
+      set_fpu_register_word(fs_reg(), static_cast<int32_t>(rt()));
       break;
     case DMTC1:
-      set_fpu_register(fs_reg, registers_[rt_reg]);
+      set_fpu_register(fs_reg(), rt());
       break;
     case MTHC1:
-      set_fpu_register_hi_word(fs_reg,
-                               static_cast<int32_t>(registers_[rt_reg]));
+      set_fpu_register_hi_word(fs_reg(), static_cast<int32_t>(rt()));
       break;
     case S:
-      DecodeTypeRegisterSRsType(instr, fs_reg, ft_reg, fd_reg);
+      DecodeTypeRegisterSRsType();
       break;
     case D:
-      DecodeTypeRegisterDRsType(instr, fs_reg, ft_reg, fd_reg);
+      DecodeTypeRegisterDRsType();
       break;
     case W:
-      DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, ft_reg, alu_out);
+      DecodeTypeRegisterWRsType();
       break;
     case L:
-      DecodeTypeRegisterLRsType(instr, fs_reg, fd_reg, ft_reg);
+      DecodeTypeRegisterLRsType();
       break;
     default:
       UNREACHABLE();
@@ -3695,18 +3210,14 @@ void Simulator::DecodeTypeRegisterCOP1(
 }
 
 
-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()) {
+void Simulator::DecodeTypeRegisterCOP1X() {
+  switch (get_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);
+      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();
@@ -3714,25 +3225,24 @@ void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr,
 }
 
 
-void Simulator::DecodeTypeRegisterSPECIAL(
-    Instruction* instr, const int32_t rs_reg, const int64_t rs,
-    const uint64_t rs_u, const int32_t rt_reg, const int64_t rt,
-    const uint64_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,
-    const int64_t i64hilo, const uint64_t u64hilo, const int64_t alu_out,
-    const bool do_interrupt, const int64_t current_pc, const int64_t next_pc,
-    const int32_t return_addr_reg, const int64_t i128resultH,
-    const int64_t i128resultL) {
-  switch (instr->FunctionFieldRaw()) {
+void Simulator::DecodeTypeRegisterSPECIAL() {
+  int64_t i64hilo;
+  uint64_t u64hilo;
+  int64_t alu_out;
+  bool do_interrupt = false;
+
+  switch (get_instr()->FunctionFieldRaw()) {
     case SELEQZ_S:
       DCHECK(kArchVariant == kMips64r6);
-      set_register(rd_reg, rt == 0 ? rs : 0);
+      set_register(rd_reg(), rt() == 0 ? rs() : 0);
       break;
     case SELNEZ_S:
       DCHECK(kArchVariant == kMips64r6);
-      set_register(rd_reg, rt != 0 ? rs : 0);
+      set_register(rd_reg(), rt() != 0 ? rs() : 0);
       break;
     case JR: {
+      int64_t next_pc = rs();
+      int64_t current_pc = get_pc();
       Instruction* branch_delay_instr =
           reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
       BranchDelayInstructionDecode(branch_delay_instr);
@@ -3741,6 +3251,9 @@ void Simulator::DecodeTypeRegisterSPECIAL(
       break;
     }
     case JALR: {
+      int64_t next_pc = rs();
+      int64_t current_pc = get_pc();
+      int32_t return_addr_reg = rd_reg();
       Instruction* branch_delay_instr =
           reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
       BranchDelayInstructionDecode(branch_delay_instr);
@@ -3749,18 +3262,118 @@ void Simulator::DecodeTypeRegisterSPECIAL(
       pc_modified_ = true;
       break;
     }
+    case SLL:
+      SetResult(rd_reg(), static_cast<int32_t>(rt()) << sa());
+      break;
+    case DSLL:
+      SetResult(rd_reg(), rt() << sa());
+      break;
+    case DSLL32:
+      SetResult(rd_reg(), rt() << sa() << 32);
+      break;
+    case SRL:
+      if (rs_reg() == 0) {
+        // Regular logical right shift of a word by a fixed number of
+        // bits instruction. RS field is always equal to 0.
+        // Sign-extend the 32-bit result.
+        alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u()) >> sa());
+      } else {
+        // Logical right-rotate of a word by a fixed number of bits. This
+        // is special case of SRL instruction, added in MIPS32 Release 2.
+        // RS field is equal to 00001.
+        alu_out = static_cast<int32_t>(
+            base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
+                                      static_cast<const uint32_t>(sa())));
+      }
+      SetResult(rd_reg(), alu_out);
+      break;
+    case DSRL:
+      SetResult(rd_reg(), rt_u() >> sa());
+      break;
+    case DSRL32:
+      SetResult(rd_reg(), rt_u() >> sa() >> 32);
+      break;
+    case SRA:
+      SetResult(rd_reg(), (int32_t)rt() >> sa());
+      break;
+    case DSRA:
+      SetResult(rd_reg(), rt() >> sa());
+      break;
+    case DSRA32:
+      SetResult(rd_reg(), rt() >> sa() >> 32);
+      break;
+    case SLLV:
+      SetResult(rd_reg(), (int32_t)rt() << rs());
+      break;
+    case DSLLV:
+      SetResult(rd_reg(), rt() << rs());
+      break;
+    case SRLV:
+      if (sa() == 0) {
+        // Regular logical right-shift of a word by a variable number of
+        // bits instruction. SA field is always equal to 0.
+        alu_out = static_cast<int32_t>((uint32_t)rt_u() >> rs());
+      } else {
+        // Logical right-rotate of a word by a variable number of bits.
+        // This is special case od SRLV instruction, added in MIPS32
+        // Release 2. SA field is equal to 00001.
+        alu_out = static_cast<int32_t>(
+            base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
+                                      static_cast<const uint32_t>(rs_u())));
+      }
+      SetResult(rd_reg(), alu_out);
+      break;
+    case DSRLV:
+      if (sa() == 0) {
+        // Regular logical right-shift of a word by a variable number of
+        // bits instruction. SA field is always equal to 0.
+        alu_out = rt_u() >> rs();
+      } else {
+        // Logical right-rotate of a word by a variable number of bits.
+        // This is special case od SRLV instruction, added in MIPS32
+        // Release 2. SA field is equal to 00001.
+        alu_out =
+            base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
+                                      static_cast<const uint32_t>(rs_u()));
+      }
+      SetResult(rd_reg(), alu_out);
+      break;
+    case SRAV:
+      SetResult(rd_reg(), (int32_t)rt() >> rs());
+      break;
+    case DSRAV:
+      SetResult(rd_reg(), rt() >> rs());
+      break;
+    case MFHI:  // MFHI == CLZ on R6.
+      if (kArchVariant != kMips64r6) {
+        DCHECK(sa() == 0);
+        alu_out = get_register(HI);
+      } else {
+        // MIPS spec: If no bits were set in GPR rs(), the result written to
+        // GPR rd() is 32.
+        DCHECK(sa() == 1);
+        alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u()));
+      }
+      SetResult(rd_reg(), alu_out);
+      break;
+    case MFLO:
+      SetResult(rd_reg(), get_register(LO));
+      break;
     // Instructions using HI and LO registers.
-    case MULT:
+    case MULT: {  // MULT == D_MUL_MUH.
+      int32_t rs_lo = static_cast<int32_t>(rs());
+      int32_t rt_lo = static_cast<int32_t>(rt());
+      i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
       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()) {
+        switch (sa()) {
           case MUL_OP:
-            set_register(rd_reg, static_cast<int32_t>(i64hilo & 0xffffffff));
+            set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
             break;
           case MUH_OP:
-            set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32));
+            set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
             break;
           default:
             UNIMPLEMENTED_MIPS();
@@ -3768,21 +3381,24 @@ void Simulator::DecodeTypeRegisterSPECIAL(
         }
       }
       break;
+    }
     case MULTU:
+      u64hilo = static_cast<uint64_t>(rs_u() & 0xffffffff) *
+                static_cast<uint64_t>(rt_u() & 0xffffffff);
       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));
+        set_register(LO, rs() * rt());
+        set_register(HI, MultiplyHighSigned(rs(), rt()));
       } else {
-        switch (instr->SaValue()) {
+        switch (sa()) {
           case MUL_OP:
-            set_register(rd_reg, static_cast<int64_t>(i128resultL));
+            set_register(rd_reg(), rs() * rt());
             break;
           case MUH_OP:
-            set_register(rd_reg, static_cast<int64_t>(i128resultH));
+            set_register(rd_reg(), MultiplyHighSigned(rs(), rt()));
             break;
           default:
             UNIMPLEMENTED_MIPS();
@@ -3793,42 +3409,38 @@ void Simulator::DecodeTypeRegisterSPECIAL(
     case DMULTU:
       UNIMPLEMENTED_MIPS();
       break;
-    case DSLL:
-      set_register(rd_reg, alu_out);
-      TraceRegWr(alu_out);
-      break;
     case DIV:
     case DDIV: {
       const int64_t int_min_value =
-          instr->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
+          get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
       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_value && rt == -1) {
+          if (rs() == int_min_value && rt() == -1) {
             set_register(LO, int_min_value);
             set_register(HI, 0);
-          } else if (rt != 0) {
-            set_register(LO, rs / rt);
-            set_register(HI, rs % rt);
+          } else if (rt() != 0) {
+            set_register(LO, rs() / rt());
+            set_register(HI, rs() % rt());
           }
           break;
         case kMips64r6:
-          switch (instr->SaValue()) {
+          switch (sa()) {
             case DIV_OP:
-              if (rs == int_min_value && rt == -1) {
-                set_register(rd_reg, int_min_value);
-              } else if (rt != 0) {
-                set_register(rd_reg, rs / rt);
+              if (rs() == int_min_value && rt() == -1) {
+                set_register(rd_reg(), int_min_value);
+              } else if (rt() != 0) {
+                set_register(rd_reg(), rs() / rt());
               }
               break;
             case MOD_OP:
-              if (rs == int_min_value && rt == -1) {
-                set_register(rd_reg, 0);
-              } else if (rt != 0) {
-                set_register(rd_reg, rs % rt);
+              if (rs() == int_min_value && rt() == -1) {
+                set_register(rd_reg(), 0);
+              } else if (rt() != 0) {
+                set_register(rd_reg(), rs() % rt());
               }
               break;
             default:
@@ -3842,91 +3454,317 @@ void Simulator::DecodeTypeRegisterSPECIAL(
       break;
     }
     case DIVU:
-      if (rt_u != 0) {
-        set_register(LO, rs_u / rt_u);
-        set_register(HI, rs_u % rt_u);
+      if (rt_u() != 0) {
+        uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
+        uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
+        set_register(LO, rs_u_32 / rt_u_32);
+        set_register(HI, rs_u_32 % rt_u_32);
       }
       break;
+    case DDIVU:
+      if (rt_u() != 0) {
+        set_register(LO, rs_u() / rt_u());
+        set_register(HI, rs_u() % rt_u());
+      }
+      break;
+    case ADD:
+    case DADD:
+      if (HaveSameSign(rs(), rt())) {
+        if (rs() > 0) {
+          if (rs() > (Registers::kMaxValue - rt())) {
+            SignalException(kIntegerOverflow);
+          }
+        } else if (rs() < 0) {
+          if (rs() < (Registers::kMinValue - rt())) {
+            SignalException(kIntegerUnderflow);
+          }
+        }
+      }
+      SetResult(rd_reg(), rs() + rt());
+      break;
+    case ADDU: {
+      int32_t alu32_out = static_cast<int32_t>(rs() + rt());
+      // Sign-extend result of 32bit operation into 64bit register.
+      SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
+      break;
+    }
+    case DADDU:
+      SetResult(rd_reg(), rs() + rt());
+      break;
+    case SUB:
+    case DSUB:
+      if (!HaveSameSign(rs(), rt())) {
+        if (rs() > 0) {
+          if (rs() > (Registers::kMaxValue + rt())) {
+            SignalException(kIntegerOverflow);
+          }
+        } else if (rs() < 0) {
+          if (rs() < (Registers::kMinValue + rt())) {
+            SignalException(kIntegerUnderflow);
+          }
+        }
+      }
+      SetResult(rd_reg(), rs() - rt());
+      break;
+    case SUBU: {
+      int32_t alu32_out = static_cast<int32_t>(rs() - rt());
+      // Sign-extend result of 32bit operation into 64bit register.
+      SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
+      break;
+    }
+    case DSUBU:
+      SetResult(rd_reg(), rs() - rt());
+      break;
+    case AND:
+      SetResult(rd_reg(), rs() & rt());
+      break;
+    case OR:
+      SetResult(rd_reg(), rs() | rt());
+      break;
+    case XOR:
+      SetResult(rd_reg(), rs() ^ rt());
+      break;
+    case NOR:
+      SetResult(rd_reg(), ~(rs() | rt()));
+      break;
+    case SLT:
+      SetResult(rd_reg(), rs() < rt() ? 1 : 0);
+      break;
+    case SLTU:
+      SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
+      break;
     // Break and trap instructions.
     case BREAK:
+      do_interrupt = true;
+      break;
     case TGE:
+      do_interrupt = rs() >= rt();
+      break;
     case TGEU:
+      do_interrupt = rs_u() >= rt_u();
+      break;
     case TLT:
+      do_interrupt = rs() < rt();
+      break;
     case TLTU:
+      do_interrupt = rs_u() < rt_u();
+      break;
     case TEQ:
+      do_interrupt = rs() == rt();
+      break;
     case TNE:
-      if (do_interrupt) {
-        SoftwareInterrupt(instr);
-      }
+      do_interrupt = rs() != rt();
       break;
     // Conditional moves.
     case MOVN:
-      if (rt) {
-        set_register(rd_reg, rs);
-        TraceRegWr(rs);
+      if (rt()) {
+        SetResult(rd_reg(), rs());
       }
       break;
     case MOVCI: {
-      uint32_t cc = instr->FBccValue();
+      uint32_t cc = get_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);
+      if (get_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);
+        if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
       }
       break;
     }
     case MOVZ:
-      if (!rt) {
-        set_register(rd_reg, rs);
-        TraceRegWr(rs);
+      if (!rt()) {
+        SetResult(rd_reg(), rs());
       }
       break;
-    default:  // For other special opcodes we do the default operation.
-      set_register(rd_reg, alu_out);
-      TraceRegWr(alu_out);
+    default:
+      UNREACHABLE();
+  }
+  if (do_interrupt) {
+    SoftwareInterrupt(get_instr());
   }
 }
 
 
-void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
-                                           const int32_t rd_reg,
-                                           int64_t alu_out) {
-  switch (instr->FunctionFieldRaw()) {
+void Simulator::DecodeTypeRegisterSPECIAL2() {
+  int64_t alu_out;
+  switch (get_instr()->FunctionFieldRaw()) {
     case MUL:
-      set_register(rd_reg, alu_out);
-      TraceRegWr(alu_out);
+      alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u());
+      SetResult(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);
+    case CLZ:
+      // MIPS32 spec: If no bits were set in GPR rs(), the result written to
+      // GPR rd is 32.
+      alu_out = base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u()));
+      set_register(rd_reg(), alu_out);
+      break;
+    default:
+      alu_out = 0x12345678;
+      UNREACHABLE();
   }
 }
 
 
-void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
-                                           const int32_t rt_reg,
-                                           const int32_t rd_reg,
-                                           const 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);
+void Simulator::DecodeTypeRegisterSPECIAL3() {
+  int64_t alu_out;
+  switch (get_instr()->FunctionFieldRaw()) {
+    case INS: {  // Mips32r2 instruction.
+      // Interpret rd field as 5-bit msb of insert.
+      uint16_t msb = rd_reg();
+      // Interpret sa field as 5-bit lsb of insert.
+      uint16_t lsb = sa();
+      uint16_t size = msb - lsb + 1;
+      uint64_t mask = (1ULL << size) - 1;
+      alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
+      SetResult(rt_reg(), 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);
+    }
+    case EXT: {  // Mips32r2 instruction.
+      // Interpret rd field as 5-bit msb of extract.
+      uint16_t msb = rd_reg();
+      // Interpret sa field as 5-bit lsb of extract.
+      uint16_t lsb = sa();
+      uint16_t size = msb + 1;
+      uint64_t mask = (1ULL << size) - 1;
+      alu_out = static_cast<int32_t>((rs_u() & (mask << lsb)) >> lsb);
+      SetResult(rt_reg(), alu_out);
+      break;
+    }
+    case DEXT: {  // Mips32r2 instruction.
+      // Interpret rd field as 5-bit msb of extract.
+      uint16_t msb = rd_reg();
+      // Interpret sa field as 5-bit lsb of extract.
+      uint16_t lsb = sa();
+      uint16_t size = msb + 1;
+      uint64_t mask = (1ULL << size) - 1;
+      alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
+      SetResult(rt_reg(), alu_out);
+      break;
+    }
+    case BSHFL: {
+      int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
+      switch (sa) {
+        case BITSWAP: {
+          uint32_t input = static_cast<uint32_t>(rt());
+          uint32_t output = 0;
+          uint8_t i_byte, o_byte;
+
+          // Reverse the bit in byte for each individual byte
+          for (int i = 0; i < 4; i++) {
+            output = output >> 8;
+            i_byte = input & 0xff;
+
+            // Fast way to reverse bits in byte
+            // Devised by Sean Anderson, July 13, 2001
+            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+                                           (i_byte * 0x8020LU & 0x88440LU)) *
+                                              0x10101LU >>
+                                          16);
+
+            output = output | (static_cast<uint32_t>(o_byte << 24));
+            input = input >> 8;
+          }
+
+          alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
+          break;
+        }
+        case SEB:
+        case SEH:
+        case WSBH:
+          alu_out = 0x12345678;
+          UNREACHABLE();
+          break;
+        default: {
+          const uint8_t bp2 = get_instr()->Bp2Value();
+          sa >>= kBp2Bits;
+          switch (sa) {
+            case ALIGN: {
+              if (bp2 == 0) {
+                alu_out = static_cast<int32_t>(rt());
+              } else {
+                uint64_t rt_hi = rt() << (8 * bp2);
+                uint64_t rs_lo = rs() >> (8 * (4 - bp2));
+                alu_out = static_cast<int32_t>(rt_hi | rs_lo);
+              }
+              break;
+            }
+            default:
+              alu_out = 0x12345678;
+              UNREACHABLE();
+              break;
+          }
+          break;
+        }
+      }
+      SetResult(rd_reg(), alu_out);
       break;
-    case BSHFL:
-    case DBSHFL:
-      set_register(rd_reg, alu_out);
-      TraceRegWr(alu_out);
+    }
+    case DBSHFL: {
+      int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
+      switch (sa) {
+        case DBITSWAP: {
+          switch (sa) {
+            case DBITSWAP_SA: {  // Mips64r6
+              uint64_t input = static_cast<uint64_t>(rt());
+              uint64_t output = 0;
+              uint8_t i_byte, o_byte;
+
+              // Reverse the bit in byte for each individual byte
+              for (int i = 0; i < 8; i++) {
+                output = output >> 8;
+                i_byte = input & 0xff;
+
+                // Fast way to reverse bits in byte
+                // Devised by Sean Anderson, July 13, 2001
+                o_byte =
+                    static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+                                          (i_byte * 0x8020LU & 0x88440LU)) *
+                                             0x10101LU >>
+                                         16);
+
+                output = output | ((static_cast<uint64_t>(o_byte) << 56));
+                input = input >> 8;
+              }
+
+              alu_out = static_cast<int64_t>(output);
+              break;
+            }
+          }
+          break;
+        }
+        case DSBH:
+        case DSHD:
+          alu_out = 0x12345678;
+          UNREACHABLE();
+          break;
+        default: {
+          const uint8_t bp3 = get_instr()->Bp3Value();
+          sa >>= kBp3Bits;
+          switch (sa) {
+            case DALIGN: {
+              if (bp3 == 0) {
+                alu_out = static_cast<int64_t>(rt());
+              } else {
+                uint64_t rt_hi = rt() << (8 * bp3);
+                uint64_t rs_lo = rs() >> (8 * (8 - bp3));
+                alu_out = static_cast<int64_t>(rt_hi | rs_lo);
+              }
+              break;
+            }
+            default:
+              alu_out = 0x12345678;
+              UNREACHABLE();
+              break;
+          }
+          break;
+        }
+      }
+      SetResult(rd_reg(), alu_out);
       break;
+    }
     default:
       UNREACHABLE();
   }
@@ -3934,97 +3772,46 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
 
 
 void Simulator::DecodeTypeRegister(Instruction* instr) {
-  // Instruction fields.
-  const Opcode   op     = instr->OpcodeFieldRaw();
-  const int32_t  rs_reg = instr->RsValue();
-  const int64_t  rs     = get_register(rs_reg);
-  const uint64_t rs_u   = static_cast<uint32_t>(rs);
-  const int32_t  rt_reg = instr->RtValue();
-  const int64_t  rt     = get_register(rt_reg);
-  const uint64_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.
-  int64_t alu_out = 0x12345678;
-
-  // For break and trap instructions.
-  bool do_interrupt = false;
-
-  // For jr and jalr.
-  // Get current pc.
-  int64_t current_pc = get_pc();
-  // Next pc
-  int64_t next_pc = 0;
-  int32_t return_addr_reg = 31;
-
-  int64_t i128resultH;
-  int64_t i128resultL;
-
-  // Set up the variables if needed before executing the instruction.
-  ConfigureTypeRegister(instr,
-                        &alu_out,
-                        &i64hilo,
-                        &u64hilo,
-                        &next_pc,
-                        &return_addr_reg,
-                        &do_interrupt,
-                        &i128resultH,
-                        &i128resultL);
-
-  // ---------- Raise exceptions triggered.
-  SignalExceptions();
+  set_instr(instr);
 
   // ---------- Execution.
-  switch (op) {
+  switch (instr->OpcodeFieldRaw()) {
     case COP1:
-      DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg,
-                             fr_reg, fs_reg, ft_reg, fd_reg, alu_out);
+      DecodeTypeRegisterCOP1();
       break;
     case COP1X:
-      DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg);
+      DecodeTypeRegisterCOP1X();
       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, i128resultH, i128resultL);
+      DecodeTypeRegisterSPECIAL();
       break;
     case SPECIAL2:
-      DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
+      DecodeTypeRegisterSPECIAL2();
       break;
     case SPECIAL3:
       switch (instr->FunctionFieldRaw()) {
         case BSHFL: {
-          int sa = instr->SaValue();
-          sa >>= kBp2Bits;
-          switch (sa) {
+          int32_t saVal = sa();
+          saVal >>= kBp2Bits;
+          switch (saVal) {
             case ALIGN: {
-              DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+              DecodeTypeRegisterSPECIAL3();
               break;
             }
           }
         }
         case DBSHFL: {
-          int sa = instr->SaValue();
-          sa >>= kBp3Bits;
-          switch (sa) {
+          int32_t saVal = sa();
+          saVal >>= kBp2Bits;
+          switch (saVal) {
             case DALIGN: {
-              DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+              DecodeTypeRegisterSPECIAL3();
               break;
             }
           }
         }
         default:
-          DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+          DecodeTypeRegisterSPECIAL3();
           break;
       }
       break;
@@ -4032,60 +3819,68 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
     // so we can use the default here to set the destination register in common
     // cases.
     default:
-      set_register(rd_reg, alu_out);
-      TraceRegWr(alu_out);
+      UNREACHABLE();
   }
 }
 
 
+// Branch instructions common part.
+#define BranchAndLinkHelper(do_branch)                             \
+  execute_branch_delay_instruction = true;                         \
+  if (do_branch) {                                                 \
+    next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \
+    set_register(31, current_pc + kBranchReturnOffset);            \
+  } else {                                                         \
+    next_pc = current_pc + kBranchReturnOffset;                    \
+  }
+
+
+#define BranchHelper(do_branch)                                    \
+  execute_branch_delay_instruction = true;                         \
+  if (do_branch) {                                                 \
+    next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \
+  } else {                                                         \
+    next_pc = current_pc + kBranchReturnOffset;                    \
+  }
+
+
 // Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
 void Simulator::DecodeTypeImmediate(Instruction* instr) {
   // Instruction fields.
-  Opcode   op     = instr->OpcodeFieldRaw();
+  Opcode op = instr->OpcodeFieldRaw();
   int32_t rs_reg = instr->RsValue();
-  int64_t  rs     = get_register(instr->RsValue());
-  uint64_t rs_u   = static_cast<uint64_t>(rs);
-  int32_t  rt_reg = instr->RtValue();  // Destination register.
-  int64_t  rt     = get_register(rt_reg);
-  int16_t  imm16  = instr->Imm16Value();
+  int64_t rs = get_register(instr->RsValue());
+  uint64_t rs_u = static_cast<uint64_t>(rs);
+  int32_t rt_reg = instr->RtValue();  // Destination register.
+  int64_t rt = get_register(rt_reg);
+  int16_t imm16 = instr->Imm16Value();
   int32_t imm18 = instr->Imm18Value();
-  int32_t imm19 = instr->Imm19Value();
   int32_t imm21 = instr->Imm21Value();
   int32_t imm26 = instr->Imm26Value();
 
-  int32_t  ft_reg = instr->FtValue();  // Destination register.
-  int64_t  ft     = get_fpu_register(ft_reg);
+  int32_t ft_reg = instr->FtValue();  // Destination register.
+  int64_t ft = get_fpu_register(ft_reg);
 
   // Zero extended immediate.
   uint64_t oe_imm16 = 0xffff & imm16;
   // Sign extended immediate.
   int64_t se_imm16 = imm16;
   int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
-  int64_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
   int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0);
 
-
   // Get current pc.
   int64_t current_pc = get_pc();
   // Next pc.
   int64_t next_pc = bad_ra;
-  // pc increment
-  int16_t pc_increment;
 
   // Used for conditional branch instructions.
-  bool do_branch = false;
   bool execute_branch_delay_instruction = false;
 
   // Used for arithmetic instructions.
   int64_t alu_out = 0;
-  // Floating point.
-  double fp_out = 0.0;
-  uint32_t cc, cc_value, fcsr_cc;
 
   // Used for memory instructions.
   int64_t addr = 0x0;
-  // Value to be written in memory.
-  uint64_t mem_value = 0x0;
   // Alignment for 32-bit integers used in LWL, LWR, etc.
   const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
 
@@ -4094,11 +3889,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
     // ------------- COP1. Coprocessor instructions.
     case COP1:
       switch (instr->RsFieldRaw()) {
-        case BC1:   // Branch on coprocessor condition.
-          cc = instr->FBccValue();
-          fcsr_cc = get_fcsr_condition_bit(cc);
-          cc_value = test_fcsr_bit(fcsr_cc);
-          do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
+        case BC1: {  // Branch on coprocessor condition.
+          uint32_t cc = instr->FBccValue();
+          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
+          uint32_t cc_value = test_fcsr_bit(fcsr_cc);
+          bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
           execute_branch_delay_instruction = true;
           // Set next_pc.
           if (do_branch) {
@@ -4107,21 +3902,20 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
             next_pc = current_pc + kBranchReturnOffset;
           }
           break;
+        }
         case BC1EQZ:
-          do_branch = (ft & 0x1) ? false : true;
           execute_branch_delay_instruction = true;
           // Set next_pc.
-          if (do_branch) {
+          if (!(ft & 0x1)) {
             next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
           } else {
             next_pc = current_pc + kBranchReturnOffset;
           }
           break;
         case BC1NEZ:
-          do_branch = (ft & 0x1) ? true : false;
           execute_branch_delay_instruction = true;
           // Set next_pc.
-          if (do_branch) {
+          if (ft & 0x1) {
             next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
           } else {
             next_pc = current_pc + kBranchReturnOffset;
@@ -4135,54 +3929,35 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
     case REGIMM:
       switch (instr->RtFieldRaw()) {
         case BLTZ:
-          do_branch = (rs  < 0);
-          break;
-        case BLTZAL:
-          do_branch = rs  < 0;
+          BranchHelper(rs < 0);
           break;
         case BGEZ:
-          do_branch = rs >= 0;
+          BranchHelper(rs >= 0);
+          break;
+        case BLTZAL:
+          BranchAndLinkHelper(rs < 0);
           break;
         case BGEZAL:
-          do_branch = rs >= 0;
+          BranchAndLinkHelper(rs >= 0);
           break;
         default:
           UNREACHABLE();
       }
-      switch (instr->RtFieldRaw()) {
-        case BLTZ:
-        case BLTZAL:
-        case BGEZ:
-        case BGEZAL:
-          // Branch instructions common part.
-          execute_branch_delay_instruction = true;
-          // Set next_pc.
-          if (do_branch) {
-            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
-            if (instr->IsLinkingInstruction()) {
-              set_register(31, current_pc + kBranchReturnOffset);
-            }
-          } else {
-            next_pc = current_pc + kBranchReturnOffset;
-          }
-        default:
-          break;
-        }
-    break;  // case REGIMM.
+      break;  // case REGIMM.
     // ------------- Branch instructions.
     // When comparing to zero, the encoding of rt field is always 0, so we don't
     // need to replace rt with zero.
     case BEQ:
-      do_branch = (rs == rt);
+      BranchHelper(rs == rt);
       break;
     case BNE:
-      do_branch = rs != rt;
+      BranchHelper(rs != rt);
       break;
     case BLEZ:
-      do_branch = rs <= 0;
+      BranchHelper(rs <= 0);
       break;
     case BGTZ:
-      do_branch = rs  > 0;
+      BranchHelper(rs > 0);
       break;
     case POP66: {
       if (rs_reg) {  // BEQZC
@@ -4216,52 +3991,53 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
     case DADDI:
       if (HaveSameSign(rs, se_imm16)) {
         if (rs > 0) {
-          exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
+          if (rs > Registers::kMaxValue - se_imm16) {
+            SignalException(kIntegerOverflow);
+          }
         } else if (rs < 0) {
-          exceptions[kIntegerUnderflow] =
-              rs < (Registers::kMinValue - se_imm16);
+          if (rs < Registers::kMinValue - se_imm16) {
+            SignalException(kIntegerUnderflow);
+          }
         }
       }
-      alu_out = rs + se_imm16;
+      SetResult(rt_reg, rs + se_imm16);
       break;
     case ADDIU: {
       int32_t alu32_out = static_cast<int32_t>(rs + se_imm16);
       // Sign-extend result of 32bit operation into 64bit register.
-      alu_out = static_cast<int64_t>(alu32_out);
+      SetResult(rt_reg, static_cast<int64_t>(alu32_out));
       break;
     }
     case DADDIU:
-      alu_out = rs + se_imm16;
+      SetResult(rt_reg, rs + se_imm16);
       break;
     case SLTI:
-      alu_out = (rs < se_imm16) ? 1 : 0;
+      SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
       break;
     case SLTIU:
-      alu_out = (rs_u < static_cast<uint64_t>(se_imm16)) ? 1 : 0;
+      SetResult(rt_reg, rs_u < static_cast<uint64_t>(se_imm16) ? 1 : 0);
       break;
     case ANDI:
-      alu_out = rs & oe_imm16;
+      SetResult(rt_reg, rs & oe_imm16);
       break;
     case ORI:
-      alu_out = rs | oe_imm16;
+      SetResult(rt_reg, rs | oe_imm16);
       break;
     case XORI:
-      alu_out = rs ^ oe_imm16;
+      SetResult(rt_reg, rs ^ oe_imm16);
       break;
     case LUI: {
       int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
       // Sign-extend result of 32bit operation into 64bit register.
-      alu_out = static_cast<int64_t>(alu32_out);
+      SetResult(rt_reg, static_cast<int64_t>(alu32_out));
       break;
     }
     // ------------- Memory instructions.
     case LB:
-      addr = rs + se_imm16;
-      alu_out = ReadB(addr);
+      set_register(rt_reg, ReadB(rs + se_imm16));
       break;
     case LH:
-      addr = rs + se_imm16;
-      alu_out = ReadH(addr, instr);
+      set_register(rt_reg, ReadH(rs + se_imm16, instr));
       break;
     case LWL: {
       // al_offset is offset of the effective address within an aligned word.
@@ -4272,27 +4048,23 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
       alu_out = ReadW(addr, instr);
       alu_out <<= byte_shift * 8;
       alu_out |= rt & mask;
+      set_register(rt_reg, alu_out);
       break;
     }
     case LW:
-      addr = rs + se_imm16;
-      alu_out = ReadW(addr, instr);
+      set_register(rt_reg, ReadW(rs + se_imm16, instr));
       break;
     case LWU:
-      addr = rs + se_imm16;
-      alu_out = ReadWU(addr, instr);
+      set_register(rt_reg, ReadWU(rs + se_imm16, instr));
       break;
     case LD:
-      addr = rs + se_imm16;
-      alu_out = Read2W(addr, instr);
+      set_register(rt_reg, Read2W(rs + se_imm16, instr));
       break;
     case LBU:
-      addr = rs + se_imm16;
-      alu_out = ReadBU(addr);
+      set_register(rt_reg, ReadBU(rs + se_imm16));
       break;
     case LHU:
-      addr = rs + se_imm16;
-      alu_out = ReadHU(addr, instr);
+      set_register(rt_reg, ReadHU(rs + se_imm16, instr));
       break;
     case LWR: {
       // al_offset is offset of the effective address within an aligned word.
@@ -4303,59 +4075,68 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
       alu_out = ReadW(addr, instr);
       alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
       alu_out |= rt & mask;
+      set_register(rt_reg, alu_out);
       break;
     }
     case SB:
-      addr = rs + se_imm16;
+      WriteB(rs + se_imm16, static_cast<int8_t>(rt));
       break;
     case SH:
-      addr = rs + se_imm16;
+      WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
       break;
     case SWL: {
       uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
       uint8_t byte_shift = kInt32AlignmentMask - al_offset;
       uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
       addr = rs + se_imm16 - al_offset;
-      mem_value = ReadW(addr, instr) & mask;
+      uint64_t mem_value = ReadW(addr, instr) & mask;
       mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
+      WriteW(addr, static_cast<int32_t>(mem_value), instr);
       break;
     }
     case SW:
+      WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr);
+      break;
     case SD:
-      addr = rs + se_imm16;
+      Write2W(rs + se_imm16, rt, instr);
       break;
     case SWR: {
       uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
       uint32_t mask = (1 << al_offset * 8) - 1;
       addr = rs + se_imm16 - al_offset;
-      mem_value = ReadW(addr, instr);
+      uint64_t mem_value = ReadW(addr, instr);
       mem_value = (rt << al_offset * 8) | (mem_value & mask);
+      WriteW(addr, static_cast<int32_t>(mem_value), instr);
       break;
     }
     case LWC1:
-      addr = rs + se_imm16;
-      alu_out = ReadW(addr, instr);
+      set_fpu_register(ft_reg, kFPUInvalidResult);  // Trash upper 32 bits.
+      set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
       break;
     case LDC1:
-      addr = rs + se_imm16;
-      fp_out = ReadD(addr, instr);
+      set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
       break;
-    case SWC1:
+    case SWC1: {
+      int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg));
+      WriteW(rs + se_imm16, alu_out_32, instr);
+      break;
+    }
     case SDC1:
-      addr = rs + se_imm16;
+      WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
       break;
     // ------------- JIALC and BNEZC instructions.
-    case POP76:
+    case POP76: {
       // Next pc.
       next_pc = rt + se_imm16;
       // The instruction after the jump is NOT executed.
-      pc_increment = Instruction::kInstrSize;
+      uint16_t pc_increment = Instruction::kInstrSize;
       if (instr->IsLinkingInstruction()) {
         set_register(31, current_pc + pc_increment);
       }
       set_pc(next_pc);
       pc_modified_ = true;
       break;
+    }
     // ------------- PC-Relative instructions.
     case PCREL: {
       // rt field: checking 5-bits.
@@ -4369,6 +4150,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
           alu_out = current_pc + (se_imm16 << 16);
           break;
         default: {
+          int32_t imm19 = instr->Imm19Value();
           // rt field: checking the most significant 3-bits.
           rt = (imm21 >> kImm18Bits);
           switch (rt) {
@@ -4382,28 +4164,29 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
               rt = (imm21 >> kImm19Bits);
               switch (rt) {
                 case LWUPC: {
-                  int32_t offset = imm19;
                   // Set sign.
-                  offset <<= (kOpcodeBits + kRsBits + 2);
-                  offset >>= (kOpcodeBits + kRsBits + 2);
-                  addr = current_pc + (offset << 2);
+                  imm19 <<= (kOpcodeBits + kRsBits + 2);
+                  imm19 >>= (kOpcodeBits + kRsBits + 2);
+                  addr = current_pc + (imm19 << 2);
                   uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
                   alu_out = *ptr;
                   break;
                 }
                 case LWPC: {
-                  int32_t offset = imm19;
                   // Set sign.
-                  offset <<= (kOpcodeBits + kRsBits + 2);
-                  offset >>= (kOpcodeBits + kRsBits + 2);
-                  addr = current_pc + (offset << 2);
+                  imm19 <<= (kOpcodeBits + kRsBits + 2);
+                  imm19 >>= (kOpcodeBits + kRsBits + 2);
+                  addr = current_pc + (imm19 << 2);
                   int32_t* ptr = reinterpret_cast<int32_t*>(addr);
                   alu_out = *ptr;
                   break;
                 }
-                case ADDIUPC:
+                case ADDIUPC: {
+                  int64_t se_imm19 =
+                      imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
                   alu_out = current_pc + (se_imm19 << 2);
                   break;
+                }
                 default:
                   UNREACHABLE();
                   break;
@@ -4414,100 +4197,13 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
           break;
         }
       }
+      set_register(rs_reg, alu_out);
       break;
     }
     default:
       UNREACHABLE();
   }
 
-  // ---------- Raise exceptions triggered.
-  SignalExceptions();
-
-  // ---------- Execution.
-  switch (op) {
-    // ------------- Branch instructions.
-    case BEQ:
-    case BNE:
-    case BLEZ:
-    case BGTZ:
-      // Branch instructions common part.
-      execute_branch_delay_instruction = true;
-      // Set next_pc.
-      if (do_branch) {
-        next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
-        if (instr->IsLinkingInstruction()) {
-          set_register(31, current_pc + 2* Instruction::kInstrSize);
-        }
-      } else {
-        next_pc = current_pc + 2 * Instruction::kInstrSize;
-      }
-      break;
-    // ------------- Arithmetic instructions.
-    case ADDI:
-    case DADDI:
-    case ADDIU:
-    case DADDIU:
-    case SLTI:
-    case SLTIU:
-    case ANDI:
-    case ORI:
-    case XORI:
-    case LUI:
-      set_register(rt_reg, alu_out);
-      TraceRegWr(alu_out);
-      break;
-    // ------------- Memory instructions.
-    case LB:
-    case LH:
-    case LWL:
-    case LW:
-    case LWU:
-    case LD:
-    case LBU:
-    case LHU:
-    case LWR:
-      set_register(rt_reg, alu_out);
-      break;
-    case SB:
-      WriteB(addr, static_cast<int8_t>(rt));
-      break;
-    case SH:
-      WriteH(addr, static_cast<uint16_t>(rt), instr);
-      break;
-    case SWL:
-      WriteW(addr, static_cast<int32_t>(mem_value), instr);
-      break;
-    case SW:
-      WriteW(addr, static_cast<int32_t>(rt), instr);
-      break;
-    case SD:
-      Write2W(addr, rt, instr);
-      break;
-    case SWR:
-      WriteW(addr, static_cast<int32_t>(mem_value), instr);
-      break;
-    case LWC1:
-      set_fpu_register(ft_reg, kFPUInvalidResult);  // Trash upper 32 bits.
-      set_fpu_register_word(ft_reg, static_cast<int32_t>(alu_out));
-      break;
-    case LDC1:
-      set_fpu_register_double(ft_reg, fp_out);
-      break;
-    case SWC1:
-      addr = rs + se_imm16;
-      WriteW(addr, static_cast<int32_t>(get_fpu_register(ft_reg)), instr);
-      break;
-    case SDC1:
-      addr = rs + se_imm16;
-      WriteD(addr, get_fpu_register_double(ft_reg), instr);
-      break;
-    case PCREL:
-      set_register(rs_reg, alu_out);
-    default:
-      break;
-  }
-
-
   if (execute_branch_delay_instruction) {
     // Execute branch delay slot
     // We don't check for end_sim_pc. First it should not be met as the current
@@ -4523,6 +4219,9 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
   }
 }
 
+#undef BranchHelper
+#undef BranchAndLinkHelper
+
 
 // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
 void Simulator::DecodeTypeJump(Instruction* instr) {
@@ -4567,7 +4266,7 @@ void Simulator::InstructionDecode(Instruction* instr) {
     dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
   }
 
-  switch (instr->InstructionType()) {
+  switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
     case Instruction::kRegisterType:
       DecodeTypeRegister(instr);
       break;
index dea9e30adfca7d41c0679858038b8ad394274705..75d4935b74d538f73c8b4661cc2a7a20ab636b91 100644 (file)
@@ -325,57 +325,54 @@ class Simulator {
   inline int32_t SetDoubleHIW(double* addr);
   inline int32_t SetDoubleLOW(double* addr);
 
-  // functions called from DecodeTypeRegister
-  void DecodeTypeRegisterCOP1(Instruction* instr, const int32_t rs_reg,
-                              const int64_t rs, const uint64_t rs_u,
-                              const int32_t rt_reg, const int64_t rt,
-                              const uint64_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& alu_out);
-
-  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 int64_t rs,
-      const uint64_t rs_u, const int32_t rt_reg, const int64_t rt,
-      const uint64_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,
-      const int64_t i64hilo, const uint64_t u64hilo, const int64_t alu_out,
-      const bool do_interrupt, const int64_t current_pc, const int64_t next_pc,
-      const int32_t return_addr_reg, const int64_t i128resultH,
-      const int64_t i128resultL);
-
-
-  void DecodeTypeRegisterSPECIAL2(Instruction* instr, const int32_t rd_reg,
-                                  const int64_t alu_out);
-
-  void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int32_t rt_reg,
-                                  const int32_t rd_reg, const int64_t alu_out);
-
-  void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t fs_reg,
-                                 const int32_t ft_reg, const int32_t fd_reg);
-
-  void DecodeTypeRegisterDRsType(Instruction* instr, const int32_t fs_reg,
-                                 const int32_t ft_reg, const int32_t fd_reg);
-
-  void DecodeTypeRegisterWRsType(Instruction* instr, const int32_t fs_reg,
-                                 const int32_t ft_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);
+  // functions called from DecodeTypeRegister.
+  void DecodeTypeRegisterCOP1();
+
+  void DecodeTypeRegisterCOP1X();
+
+  void DecodeTypeRegisterSPECIAL();
+
+
+  void DecodeTypeRegisterSPECIAL2();
+
+  void DecodeTypeRegisterSPECIAL3();
+
+  void DecodeTypeRegisterSRsType();
+
+  void DecodeTypeRegisterDRsType();
+
+  void DecodeTypeRegisterWRsType();
+
+  void DecodeTypeRegisterLRsType();
+
   // Executing is handled based on the instruction type.
   void DecodeTypeRegister(Instruction* instr);
 
-  // Helper function for DecodeTypeRegister.
-  void ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
-                             int64_t* i64hilo, uint64_t* u64hilo,
-                             int64_t* next_pc, int* return_addr_reg,
-                             bool* do_interrupt, int64_t* result128H,
-                             int64_t* result128L);
+  Instruction* currentInstr_;
+  inline Instruction* get_instr() const { return currentInstr_; }
+  inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
+
+  inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
+  inline int64_t rs() const { return get_register(rs_reg()); }
+  inline uint64_t rs_u() const {
+    return static_cast<uint64_t>(get_register(rs_reg()));
+  }
+  inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
+  inline int64_t rt() const { return get_register(rt_reg()); }
+  inline uint64_t rt_u() const {
+    return static_cast<uint64_t>(get_register(rt_reg()));
+  }
+  inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
+  inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
+  inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
+  inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
+  inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
+  inline int32_t sa() const { return currentInstr_->SaValue(); }
+
+  inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
+    set_register(rd_reg, alu_out);
+    TraceRegWr(alu_out);
+  }
 
   void DecodeTypeImmediate(Instruction* instr);
   void DecodeTypeJump(Instruction* instr);
@@ -427,10 +424,9 @@ class Simulator {
     kDivideByZero,
     kNumExceptions
   };
-  int16_t exceptions[kNumExceptions];
 
   // Exceptions.
-  void SignalExceptions();
+  void SignalException(Exception e);
 
   // Runtime call support.
   static void* RedirectExternalReference(void* external_function,