Commit 639e8fa4 authored by balazs.kilvady's avatar balazs.kilvady Committed by Commit bot

MIPS: Improve performance of simulator in debug mode.

The running time of optdebug.quickcheck is improved by 8% while a more strict DCHECKing is kept in simulator.

Review-Url: https://codereview.chromium.org/1349403003
Cr-Commit-Position: refs/heads/master@{#39667}
parent 648ac440
...@@ -123,116 +123,6 @@ int FPURegisters::Number(const char* name) { ...@@ -123,116 +123,6 @@ int FPURegisters::Number(const char* name) {
} }
// -----------------------------------------------------------------------------
// Instructions.
bool Instruction::IsForbiddenAfterBranchInstr(Instr instr) {
Opcode opcode = static_cast<Opcode>(instr & kOpcodeMask);
switch (opcode) {
case J:
case JAL:
case BEQ:
case BNE:
case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc
case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc
case BEQL:
case BNEL:
case BLEZL: // POP26 bgezc, blezc, bgec/blec
case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc
case BC:
case BALC:
case POP10: // beqzalc, bovc, beqc
case POP30: // bnezalc, bnvc, bnec
case POP66: // beqzc, jic
case POP76: // bnezc, jialc
return true;
case REGIMM:
switch (instr & kRtFieldMask) {
case BLTZ:
case BGEZ:
case BLTZAL:
case BGEZAL:
return true;
default:
return false;
}
break;
case SPECIAL:
switch (instr & kFunctionFieldMask) {
case JR:
case JALR:
return true;
default:
return false;
}
break;
case COP1:
switch (instr & kRsFieldMask) {
case BC1:
case BC1EQZ:
case BC1NEZ:
return true;
break;
default:
return false;
}
break;
default:
return false;
}
}
bool Instruction::IsLinkingInstruction() const {
switch (OpcodeFieldRaw()) {
case JAL:
return true;
case POP76:
if (RsFieldRawNoAssert() == JIALC)
return true; // JIALC
else
return false; // BNEZC
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
case BLTZAL:
return true;
default:
return false;
}
case SPECIAL:
switch (FunctionFieldRaw()) {
case JALR:
return true;
default:
return false;
}
default:
return false;
}
}
bool Instruction::IsTrap() const {
if (OpcodeFieldRaw() != SPECIAL) {
return false;
} else {
switch (FunctionFieldRaw()) {
case BREAK:
case TGE:
case TGEU:
case TLT:
case TLTU:
case TEQ:
case TNE:
return true;
default:
return false;
}
}
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -866,8 +866,7 @@ static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) { ...@@ -866,8 +866,7 @@ static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) {
return 1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift); return 1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift);
} }
class InstructionBase {
class Instruction {
public: public:
enum { enum {
kInstrSize = 4, kInstrSize = 4,
...@@ -877,6 +876,9 @@ class Instruction { ...@@ -877,6 +876,9 @@ class Instruction {
kPCReadOffset = 0 kPCReadOffset = 0
}; };
// Instruction type.
enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 };
// Get the raw instruction bits. // Get the raw instruction bits.
inline Instr InstructionBits() const { inline Instr InstructionBits() const {
return *reinterpret_cast<const Instr*>(this); return *reinterpret_cast<const Instr*>(this);
...@@ -896,15 +898,6 @@ class Instruction { ...@@ -896,15 +898,6 @@ class Instruction {
inline int Bits(int hi, int lo) const { inline int Bits(int hi, int lo) const {
return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1); return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1);
} }
// Instruction type.
enum Type {
kRegisterType,
kImmediateType,
kJumpType,
kUnsupported = -1
};
enum TypeChecks { NORMAL, EXTRA }; enum TypeChecks { NORMAL, EXTRA };
...@@ -951,122 +944,140 @@ class Instruction { ...@@ -951,122 +944,140 @@ class Instruction {
FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) | FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC); FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC);
// Get the encoding type of the instruction.
inline Type InstructionType(TypeChecks checks = NORMAL) const;
// Accessors for the different named fields used in the MIPS encoding. // Accessors for the different named fields used in the MIPS encoding.
inline Opcode OpcodeValue() const { inline Opcode OpcodeValue() const {
return static_cast<Opcode>( return static_cast<Opcode>(
Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift)); Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift));
} }
inline int FunctionFieldRaw() const {
return InstructionBits() & kFunctionFieldMask;
}
// Return the fields at their original place in the instruction encoding.
inline Opcode OpcodeFieldRaw() const {
return static_cast<Opcode>(InstructionBits() & kOpcodeMask);
}
// Safe to call within InstructionType().
inline int RsFieldRawNoAssert() const {
return InstructionBits() & kRsFieldMask;
}
inline int SaFieldRaw() const { return InstructionBits() & kSaFieldMask; }
// Get the encoding type of the instruction.
inline Type InstructionType(TypeChecks checks = NORMAL) const;
protected:
InstructionBase() {}
};
template <class T>
class InstructionGetters : public T {
public:
inline int RsValue() const { inline int RsValue() const {
DCHECK(InstructionType() == kRegisterType || DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
InstructionType() == kImmediateType); this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kRsShift + kRsBits - 1, kRsShift); return InstructionBase::Bits(kRsShift + kRsBits - 1, kRsShift);
} }
inline int RtValue() const { inline int RtValue() const {
DCHECK(InstructionType() == kRegisterType || DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
InstructionType() == kImmediateType); this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kRtShift + kRtBits - 1, kRtShift); return this->Bits(kRtShift + kRtBits - 1, kRtShift);
} }
inline int RdValue() const { inline int RdValue() const {
DCHECK(InstructionType() == kRegisterType); DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
return Bits(kRdShift + kRdBits - 1, kRdShift); return this->Bits(kRdShift + kRdBits - 1, kRdShift);
} }
inline int SaValue() const { inline int SaValue() const {
DCHECK(InstructionType() == kRegisterType); DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
return Bits(kSaShift + kSaBits - 1, kSaShift); return this->Bits(kSaShift + kSaBits - 1, kSaShift);
} }
inline int LsaSaValue() const { inline int LsaSaValue() const {
DCHECK(InstructionType() == kRegisterType); DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
return Bits(kSaShift + kLsaSaBits - 1, kSaShift); return this->Bits(kSaShift + kLsaSaBits - 1, kSaShift);
} }
inline int FunctionValue() const { inline int FunctionValue() const {
DCHECK(InstructionType() == kRegisterType || DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
InstructionType() == kImmediateType); this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift); return this->Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
} }
inline int FdValue() const { inline int FdValue() const {
return Bits(kFdShift + kFdBits - 1, kFdShift); return this->Bits(kFdShift + kFdBits - 1, kFdShift);
} }
inline int FsValue() const { inline int FsValue() const {
return Bits(kFsShift + kFsBits - 1, kFsShift); return this->Bits(kFsShift + kFsBits - 1, kFsShift);
} }
inline int FtValue() const { inline int FtValue() const {
return Bits(kFtShift + kFtBits - 1, kFtShift); return this->Bits(kFtShift + kFtBits - 1, kFtShift);
} }
inline int FrValue() const { inline int FrValue() const {
return Bits(kFrShift + kFrBits -1, kFrShift); return this->Bits(kFrShift + kFrBits - 1, kFrShift);
} }
inline int Bp2Value() const { inline int Bp2Value() const {
DCHECK(InstructionType() == kRegisterType); DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift); return this->Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
} }
// Float Compare condition code instruction bits. // Float Compare condition code instruction bits.
inline int FCccValue() const { inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift); return this->Bits(kFCccShift + kFCccBits - 1, kFCccShift);
} }
// Float Branch condition code instruction bits. // Float Branch condition code instruction bits.
inline int FBccValue() const { inline int FBccValue() const {
return Bits(kFBccShift + kFBccBits - 1, kFBccShift); return this->Bits(kFBccShift + kFBccBits - 1, kFBccShift);
} }
// Float Branch true/false instruction bit. // Float Branch true/false instruction bit.
inline int FBtrueValue() const { inline int FBtrueValue() const {
return Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift); return this->Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
} }
// Return the fields at their original place in the instruction encoding. // Return the fields at their original place in the instruction encoding.
inline Opcode OpcodeFieldRaw() const { inline Opcode OpcodeFieldRaw() const {
return static_cast<Opcode>(InstructionBits() & kOpcodeMask); return static_cast<Opcode>(this->InstructionBits() & kOpcodeMask);
} }
inline int RsFieldRaw() const { inline int RsFieldRaw() const {
DCHECK(InstructionType() == kRegisterType || DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
InstructionType() == kImmediateType); this->InstructionType() == InstructionBase::kImmediateType);
return InstructionBits() & kRsFieldMask; return this->InstructionBits() & kRsFieldMask;
}
// Same as above function, but safe to call within InstructionType().
inline int RsFieldRawNoAssert() const {
return InstructionBits() & kRsFieldMask;
} }
inline int RtFieldRaw() const { inline int RtFieldRaw() const {
DCHECK(InstructionType() == kRegisterType || DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
InstructionType() == kImmediateType); this->InstructionType() == InstructionBase::kImmediateType);
return InstructionBits() & kRtFieldMask; return this->InstructionBits() & kRtFieldMask;
} }
inline int RdFieldRaw() const { inline int RdFieldRaw() const {
DCHECK(InstructionType() == kRegisterType); DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
return InstructionBits() & kRdFieldMask; return this->InstructionBits() & kRdFieldMask;
} }
inline int SaFieldRaw() const { inline int SaFieldRaw() const {
return InstructionBits() & kSaFieldMask; return this->InstructionBits() & kSaFieldMask;
} }
inline int FunctionFieldRaw() const { inline int FunctionFieldRaw() const {
return InstructionBits() & kFunctionFieldMask; return this->InstructionBits() & kFunctionFieldMask;
} }
// Get the secondary field according to the opcode. // Get the secondary field according to the opcode.
inline int SecondaryValue() const { inline int SecondaryValue() const {
Opcode op = OpcodeFieldRaw(); Opcode op = this->OpcodeFieldRaw();
switch (op) { switch (op) {
case SPECIAL: case SPECIAL:
case SPECIAL2: case SPECIAL2:
...@@ -1081,34 +1092,34 @@ class Instruction { ...@@ -1081,34 +1092,34 @@ class Instruction {
} }
inline int32_t ImmValue(int bits) const { inline int32_t ImmValue(int bits) const {
DCHECK(InstructionType() == kImmediateType); DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
return Bits(bits - 1, 0); return this->Bits(bits - 1, 0);
} }
inline int32_t Imm16Value() const { inline int32_t Imm16Value() const {
DCHECK(InstructionType() == kImmediateType); DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift); return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
} }
inline int32_t Imm18Value() const { inline int32_t Imm18Value() const {
DCHECK(InstructionType() == kImmediateType); DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift); return this->Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
} }
inline int32_t Imm19Value() const { inline int32_t Imm19Value() const {
DCHECK(InstructionType() == kImmediateType); DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift); return this->Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
} }
inline int32_t Imm21Value() const { inline int32_t Imm21Value() const {
DCHECK(InstructionType() == kImmediateType); DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift); return this->Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
} }
inline int32_t Imm26Value() const { inline int32_t Imm26Value() const {
DCHECK((InstructionType() == kJumpType) || DCHECK((this->InstructionType() == InstructionBase::kJumpType) ||
(InstructionType() == kImmediateType)); (this->InstructionType() == InstructionBase::kImmediateType));
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift); return this->Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
} }
static bool IsForbiddenAfterBranchInstr(Instr instr); static bool IsForbiddenAfterBranchInstr(Instr instr);
...@@ -1116,7 +1127,7 @@ class Instruction { ...@@ -1116,7 +1127,7 @@ class Instruction {
// Say if the instruction should not be used in a branch delay slot or // Say if the instruction should not be used in a branch delay slot or
// immediately after a compact branch. // immediately after a compact branch.
inline bool IsForbiddenAfterBranch() const { inline bool IsForbiddenAfterBranch() const {
return IsForbiddenAfterBranchInstr(InstructionBits()); return IsForbiddenAfterBranchInstr(this->InstructionBits());
} }
inline bool IsForbiddenInBranchDelay() const { inline bool IsForbiddenInBranchDelay() const {
...@@ -1127,17 +1138,15 @@ class Instruction { ...@@ -1127,17 +1138,15 @@ class Instruction {
bool IsLinkingInstruction() const; bool IsLinkingInstruction() const;
// Say if the instruction is a break or a trap. // Say if the instruction is a break or a trap.
bool IsTrap() const; bool IsTrap() const;
};
// Instructions are read of out a code stream. The only way to get a class Instruction : public InstructionGetters<InstructionBase> {
// reference to an instruction is to convert a pointer. There is no way public:
// to allocate or create instances of class Instruction.
// Use the At(pc) function to create references to Instruction.
static Instruction* At(byte* pc) { static Instruction* At(byte* pc) {
return reinterpret_cast<Instruction*>(pc); return reinterpret_cast<Instruction*>(pc);
} }
private: private:
// We need to prevent the creation of instances of class Instruction.
DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
}; };
...@@ -1156,8 +1165,8 @@ const int kBArgsSlotsSize = 0 * Instruction::kInstrSize; ...@@ -1156,8 +1165,8 @@ const int kBArgsSlotsSize = 0 * Instruction::kInstrSize;
const int kBranchReturnOffset = 2 * Instruction::kInstrSize; const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
InstructionBase::Type InstructionBase::InstructionType(
Instruction::Type Instruction::InstructionType(TypeChecks checks) const { TypeChecks checks) const {
if (checks == EXTRA) { if (checks == EXTRA) {
if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) { if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) {
return kImmediateType; return kImmediateType;
...@@ -1240,6 +1249,118 @@ Instruction::Type Instruction::InstructionType(TypeChecks checks) const { ...@@ -1240,6 +1249,118 @@ Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
#undef OpcodeToBitNumber #undef OpcodeToBitNumber
#undef FunctionFieldToBitNumber #undef FunctionFieldToBitNumber
// -----------------------------------------------------------------------------
// Instructions.
template <class P>
bool InstructionGetters<P>::IsLinkingInstruction() const {
uint32_t op = this->OpcodeFieldRaw();
switch (op) {
case JAL:
return true;
case POP76:
if (this->RsFieldRawNoAssert() == JIALC)
return true; // JIALC
else
return false; // BNEZC
case REGIMM:
switch (this->RtFieldRaw()) {
case BGEZAL:
case BLTZAL:
return true;
default:
return false;
}
case SPECIAL:
switch (this->FunctionFieldRaw()) {
case JALR:
return true;
default:
return false;
}
default:
return false;
}
}
template <class P>
bool InstructionGetters<P>::IsTrap() const {
if (this->OpcodeFieldRaw() != SPECIAL) {
return false;
} else {
switch (this->FunctionFieldRaw()) {
case BREAK:
case TGE:
case TGEU:
case TLT:
case TLTU:
case TEQ:
case TNE:
return true;
default:
return false;
}
}
}
// static
template <class T>
bool InstructionGetters<T>::IsForbiddenAfterBranchInstr(Instr instr) {
Opcode opcode = static_cast<Opcode>(instr & kOpcodeMask);
switch (opcode) {
case J:
case JAL:
case BEQ:
case BNE:
case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc
case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc
case BEQL:
case BNEL:
case BLEZL: // POP26 bgezc, blezc, bgec/blec
case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc
case BC:
case BALC:
case POP10: // beqzalc, bovc, beqc
case POP30: // bnezalc, bnvc, bnec
case POP66: // beqzc, jic
case POP76: // bnezc, jialc
return true;
case REGIMM:
switch (instr & kRtFieldMask) {
case BLTZ:
case BGEZ:
case BLTZAL:
case BGEZAL:
return true;
default:
return false;
}
break;
case SPECIAL:
switch (instr & kFunctionFieldMask) {
case JR:
case JALR:
return true;
default:
return false;
}
break;
case COP1:
switch (instr & kRsFieldMask) {
case BC1:
case BC1EQZ:
case BC1NEZ:
return true;
break;
default:
return false;
}
break;
default:
return false;
}
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -1929,16 +1929,16 @@ typedef void (*SimulatorRuntimeProfilingGetterCall)( ...@@ -1929,16 +1929,16 @@ typedef void (*SimulatorRuntimeProfilingGetterCall)(
// Software interrupt instructions are used by the simulator to call into the // Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime. They are also used for debugging with simulator. // C-based V8 runtime. They are also used for debugging with simulator.
void Simulator::SoftwareInterrupt(Instruction* instr) { void Simulator::SoftwareInterrupt() {
// There are several instructions that could get us here, // There are several instructions that could get us here,
// the break_ instruction, or several variants of traps. All // the break_ instruction, or several variants of traps. All
// Are "SPECIAL" class opcode, and are distinuished by function. // Are "SPECIAL" class opcode, and are distinuished by function.
int32_t func = instr->FunctionFieldRaw(); int32_t func = instr_.FunctionFieldRaw();
uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
// We first check if we met a call_rt_redirected. // We first check if we met a call_rt_redirected.
if (instr->InstructionBits() == rtCallRedirInstr) { if (instr_.InstructionBits() == rtCallRedirInstr) {
Redirection* redirection = Redirection::FromSwiInstruction(instr); Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr());
int32_t arg0 = get_register(a0); int32_t arg0 = get_register(a0);
int32_t arg1 = get_register(a1); int32_t arg1 = get_register(a1);
int32_t arg2 = get_register(a2); int32_t arg2 = get_register(a2);
...@@ -2173,7 +2173,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { ...@@ -2173,7 +2173,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
PrintWatchpoint(code); PrintWatchpoint(code);
} else { } else {
IncreaseStopCounter(code); IncreaseStopCounter(code);
HandleStop(code, instr); HandleStop(code, instr_.instr());
} }
} else { } else {
// All remaining break_ codes, and all traps are handled here. // All remaining break_ codes, and all traps are handled here.
...@@ -2416,15 +2416,14 @@ void Simulator::DecodeTypeRegisterDRsType() { ...@@ -2416,15 +2416,14 @@ void Simulator::DecodeTypeRegisterDRsType() {
uint32_t cc, fcsr_cc; uint32_t cc, fcsr_cc;
int64_t i64; int64_t i64;
fs = get_fpu_register_double(fs_reg()); fs = get_fpu_register_double(fs_reg());
ft = (get_instr()->FunctionFieldRaw() != MOVF) ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
? get_fpu_register_double(ft_reg()) : 0.0;
: 0.0;
fd = get_fpu_register_double(fd_reg()); fd = get_fpu_register_double(fd_reg());
int64_t ft_int = bit_cast<int64_t>(ft); int64_t ft_int = bit_cast<int64_t>(ft);
int64_t fd_int = bit_cast<int64_t>(fd); int64_t fd_int = bit_cast<int64_t>(fd);
cc = get_instr()->FCccValue(); cc = instr_.FCccValue();
fcsr_cc = get_fcsr_condition_bit(cc); fcsr_cc = get_fcsr_condition_bit(cc);
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case RINT: { case RINT: {
DCHECK(IsMipsArchVariant(kMips32r6)); DCHECK(IsMipsArchVariant(kMips32r6));
double result, temp, temp_result; double result, temp, temp_result;
...@@ -2483,7 +2482,7 @@ void Simulator::DecodeTypeRegisterDRsType() { ...@@ -2483,7 +2482,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
} }
case MOVN_C: { case MOVN_C: {
DCHECK(IsMipsArchVariant(kMips32r2)); DCHECK(IsMipsArchVariant(kMips32r2));
int32_t rt_reg = get_instr()->RtValue(); int32_t rt_reg = instr_.RtValue();
int32_t rt = get_register(rt_reg); int32_t rt = get_register(rt_reg);
if (rt != 0) { if (rt != 0) {
set_fpu_register_double(fd_reg(), fs); set_fpu_register_double(fd_reg(), fs);
...@@ -2494,7 +2493,7 @@ void Simulator::DecodeTypeRegisterDRsType() { ...@@ -2494,7 +2493,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
// Same function field for MOVT.D and MOVF.D // 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); ft_cc = get_fcsr_condition_bit(ft_cc);
if (get_instr()->Bit(16)) { // Read Tf bit. if (instr_.Bit(16)) { // Read Tf bit.
// MOVT.D // 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 { } else {
...@@ -2809,7 +2808,7 @@ void Simulator::DecodeTypeRegisterWRsType() { ...@@ -2809,7 +2808,7 @@ void Simulator::DecodeTypeRegisterWRsType() {
float fs = get_fpu_register_float(fs_reg()); float fs = get_fpu_register_float(fs_reg());
float ft = get_fpu_register_float(ft_reg()); float ft = get_fpu_register_float(ft_reg());
int32_t alu_out = 0x12345678; int32_t alu_out = 0x12345678;
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case CVT_S_W: // Convert word to float (single). case CVT_S_W: // Convert word to float (single).
alu_out = get_fpu_register_signed_word(fs_reg()); alu_out = get_fpu_register_signed_word(fs_reg());
set_fpu_register_float(fd_reg(), static_cast<float>(alu_out)); set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
...@@ -2905,9 +2904,9 @@ void Simulator::DecodeTypeRegisterSRsType() { ...@@ -2905,9 +2904,9 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t ft_int = bit_cast<int32_t>(ft); int32_t ft_int = bit_cast<int32_t>(ft);
int32_t fd_int = bit_cast<int32_t>(fd); int32_t fd_int = bit_cast<int32_t>(fd);
uint32_t cc, fcsr_cc; uint32_t cc, fcsr_cc;
cc = get_instr()->FCccValue(); cc = instr_.FCccValue();
fcsr_cc = get_fcsr_condition_bit(cc); fcsr_cc = get_fcsr_condition_bit(cc);
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case RINT: { case RINT: {
DCHECK(IsMipsArchVariant(kMips32r6)); DCHECK(IsMipsArchVariant(kMips32r6));
float result, temp_result; float result, temp_result;
...@@ -3134,7 +3133,7 @@ void Simulator::DecodeTypeRegisterSRsType() { ...@@ -3134,7 +3133,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
uint32_t ft_cc = (ft_reg() >> 2) & 0x7; uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
ft_cc = get_fcsr_condition_bit(ft_cc); ft_cc = get_fcsr_condition_bit(ft_cc);
if (get_instr()->Bit(16)) { // Read Tf bit. if (instr_.Bit(16)) { // Read Tf bit.
// MOVT.D // 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 { } else {
...@@ -3296,7 +3295,7 @@ void Simulator::DecodeTypeRegisterSRsType() { ...@@ -3296,7 +3295,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
void Simulator::DecodeTypeRegisterLRsType() { void Simulator::DecodeTypeRegisterLRsType() {
double fs = get_fpu_register_double(fs_reg()); double fs = get_fpu_register_double(fs_reg());
double ft = get_fpu_register_double(ft_reg()); double ft = get_fpu_register_double(ft_reg());
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case CVT_D_L: // Mips32r2 instruction. case CVT_D_L: // Mips32r2 instruction.
// Watch the signs here, we want 2 32-bit vals // Watch the signs here, we want 2 32-bit vals
// to make a sign-64. // to make a sign-64.
...@@ -3398,7 +3397,7 @@ void Simulator::DecodeTypeRegisterLRsType() { ...@@ -3398,7 +3397,7 @@ void Simulator::DecodeTypeRegisterLRsType() {
void Simulator::DecodeTypeRegisterCOP1() { void Simulator::DecodeTypeRegisterCOP1() {
switch (get_instr()->RsFieldRaw()) { switch (instr_.RsFieldRaw()) {
case CFC1: case CFC1:
// At the moment only FCSR is supported. // At the moment only FCSR is supported.
DCHECK(fs_reg() == kFCSRRegister); DCHECK(fs_reg() == kFCSRRegister);
...@@ -3461,7 +3460,7 @@ void Simulator::DecodeTypeRegisterCOP1() { ...@@ -3461,7 +3460,7 @@ void Simulator::DecodeTypeRegisterCOP1() {
void Simulator::DecodeTypeRegisterCOP1X() { void Simulator::DecodeTypeRegisterCOP1X() {
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case MADD_S: { case MADD_S: {
DCHECK(IsMipsArchVariant(kMips32r2)); DCHECK(IsMipsArchVariant(kMips32r2));
float fr, ft, fs; float fr, ft, fs;
...@@ -3510,7 +3509,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { ...@@ -3510,7 +3509,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
uint64_t u64hilo = 0; uint64_t u64hilo = 0;
bool do_interrupt = false; bool do_interrupt = false;
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case SELEQZ_S: case SELEQZ_S:
DCHECK(IsMipsArchVariant(kMips32r6)); DCHECK(IsMipsArchVariant(kMips32r6));
set_register(rd_reg(), rt() == 0 ? rs() : 0); set_register(rd_reg(), rt() == 0 ? rs() : 0);
...@@ -3650,7 +3649,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { ...@@ -3650,7 +3649,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
break; break;
case DIV: case DIV:
if (IsMipsArchVariant(kMips32r6)) { if (IsMipsArchVariant(kMips32r6)) {
switch (get_instr()->SaValue()) { switch (sa()) {
case DIV_OP: case DIV_OP:
if (rs() == INT_MIN && rt() == -1) { if (rs() == INT_MIN && rt() == -1) {
set_register(rd_reg(), INT_MIN); set_register(rd_reg(), INT_MIN);
...@@ -3685,7 +3684,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { ...@@ -3685,7 +3684,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
break; break;
case DIVU: case DIVU:
if (IsMipsArchVariant(kMips32r6)) { if (IsMipsArchVariant(kMips32r6)) {
switch (get_instr()->SaValue()) { switch (sa()) {
case DIV_OP: case DIV_OP:
if (rt_u() != 0) { if (rt_u() != 0) {
set_register(rd_reg(), rs_u() / rt_u()); set_register(rd_reg(), rs_u() / rt_u());
...@@ -3792,9 +3791,9 @@ void Simulator::DecodeTypeRegisterSPECIAL() { ...@@ -3792,9 +3791,9 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
} }
break; break;
case MOVCI: { case MOVCI: {
uint32_t cc = get_instr()->FBccValue(); uint32_t cc = instr_.FBccValue();
uint32_t fcsr_cc = get_fcsr_condition_bit(cc); uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
if (get_instr()->Bit(16)) { // Read Tf bit. if (instr_.Bit(16)) { // Read Tf bit.
if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
} else { } else {
if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
...@@ -3811,14 +3810,14 @@ void Simulator::DecodeTypeRegisterSPECIAL() { ...@@ -3811,14 +3810,14 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
UNREACHABLE(); UNREACHABLE();
} }
if (do_interrupt) { if (do_interrupt) {
SoftwareInterrupt(get_instr()); SoftwareInterrupt();
} }
} }
void Simulator::DecodeTypeRegisterSPECIAL2() { void Simulator::DecodeTypeRegisterSPECIAL2() {
int32_t alu_out; int32_t alu_out;
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case MUL: case MUL:
// Only the lower 32 bits are kept. // Only the lower 32 bits are kept.
alu_out = rs_u() * rt_u(); alu_out = rs_u() * rt_u();
...@@ -3841,7 +3840,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2() { ...@@ -3841,7 +3840,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2() {
void Simulator::DecodeTypeRegisterSPECIAL3() { void Simulator::DecodeTypeRegisterSPECIAL3() {
int32_t alu_out; int32_t alu_out;
switch (get_instr()->FunctionFieldRaw()) { switch (instr_.FunctionFieldRaw()) {
case INS: { // Mips32r2 instruction. case INS: { // Mips32r2 instruction.
// Interpret rd field as 5-bit msb of insert. // Interpret rd field as 5-bit msb of insert.
uint16_t msb = rd_reg(); uint16_t msb = rd_reg();
...@@ -3866,7 +3865,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { ...@@ -3866,7 +3865,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
break; break;
} }
case BSHFL: { case BSHFL: {
int sa = get_instr()->SaFieldRaw() >> kSaShift; int sa = instr_.SaFieldRaw() >> kSaShift;
switch (sa) { switch (sa) {
case BITSWAP: { case BITSWAP: {
uint32_t input = static_cast<uint32_t>(rt()); uint32_t input = static_cast<uint32_t>(rt());
...@@ -3938,7 +3937,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { ...@@ -3938,7 +3937,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
break; break;
} }
default: { default: {
const uint8_t bp = get_instr()->Bp2Value(); const uint8_t bp = instr_.Bp2Value();
sa >>= kBp2Bits; sa >>= kBp2Bits;
switch (sa) { switch (sa) {
case ALIGN: { case ALIGN: {
...@@ -3966,16 +3965,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { ...@@ -3966,16 +3965,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
} }
} }
void Simulator::DecodeTypeRegister() {
void Simulator::DecodeTypeRegister(Instruction* instr) {
const Opcode op = instr->OpcodeFieldRaw();
// Set up the variables if needed before executing the instruction.
// ConfigureTypeRegister(instr);
set_instr(instr);
// ---------- Execution. // ---------- Execution.
switch (op) { switch (instr_.OpcodeFieldRaw()) {
case COP1: case COP1:
DecodeTypeRegisterCOP1(); DecodeTypeRegisterCOP1();
break; break;
...@@ -3998,17 +3990,17 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { ...@@ -3998,17 +3990,17 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc). // Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
void Simulator::DecodeTypeImmediate(Instruction* instr) { void Simulator::DecodeTypeImmediate() {
// Instruction fields. // Instruction fields.
Opcode op = instr->OpcodeFieldRaw(); Opcode op = instr_.OpcodeFieldRaw();
int32_t rs_reg = instr->RsValue(); int32_t rs_reg = instr_.RsValue();
int32_t rs = get_register(instr->RsValue()); int32_t rs = get_register(instr_.RsValue());
uint32_t rs_u = static_cast<uint32_t>(rs); uint32_t rs_u = static_cast<uint32_t>(rs);
int32_t rt_reg = instr->RtValue(); // Destination register. int32_t rt_reg = instr_.RtValue(); // Destination register.
int32_t rt = get_register(rt_reg); int32_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value(); int16_t imm16 = instr_.Imm16Value();
int32_t ft_reg = instr->FtValue(); // Destination register. int32_t ft_reg = instr_.FtValue(); // Destination register.
// Zero extended immediate. // Zero extended immediate.
uint32_t oe_imm16 = 0xffff & imm16; uint32_t oe_imm16 = 0xffff & imm16;
...@@ -4028,38 +4020,36 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4028,38 +4020,36 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
int32_t addr = 0x0; int32_t addr = 0x0;
// Branch instructions common part. // Branch instructions common part.
auto BranchAndLinkHelper = [this, instr, &next_pc, auto BranchAndLinkHelper =
&execute_branch_delay_instruction]( [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
bool do_branch) { execute_branch_delay_instruction = true;
execute_branch_delay_instruction = true; int32_t current_pc = get_pc();
int32_t current_pc = get_pc(); if (do_branch) {
if (do_branch) { int16_t imm16 = this->instr_.Imm16Value();
int16_t imm16 = instr->Imm16Value(); next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; set_register(31, current_pc + 2 * Instruction::kInstrSize);
set_register(31, current_pc + 2 * Instruction::kInstrSize); } else {
} else { next_pc = current_pc + 2 * Instruction::kInstrSize;
next_pc = current_pc + 2 * Instruction::kInstrSize; }
} };
};
auto BranchHelper = [this, instr, &next_pc, auto BranchHelper = [this, &next_pc,
&execute_branch_delay_instruction](bool do_branch) { &execute_branch_delay_instruction](bool do_branch) {
execute_branch_delay_instruction = true; execute_branch_delay_instruction = true;
int32_t current_pc = get_pc(); int32_t current_pc = get_pc();
if (do_branch) { if (do_branch) {
int16_t imm16 = instr->Imm16Value(); int16_t imm16 = this->instr_.Imm16Value();
next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
} else { } else {
next_pc = current_pc + 2 * Instruction::kInstrSize; next_pc = current_pc + 2 * Instruction::kInstrSize;
} }
}; };
auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch, auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
int bits) {
int32_t current_pc = get_pc(); int32_t current_pc = get_pc();
CheckForbiddenSlot(current_pc); CheckForbiddenSlot(current_pc);
if (do_branch) { if (do_branch) {
int32_t imm = instr->ImmValue(bits); int32_t imm = this->instr_.ImmValue(bits);
imm <<= 32 - bits; imm <<= 32 - bits;
imm >>= 32 - bits; imm >>= 32 - bits;
next_pc = current_pc + (imm << 2) + Instruction::kInstrSize; next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
...@@ -4067,28 +4057,27 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4067,28 +4057,27 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
} }
}; };
auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) { auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
int32_t current_pc = get_pc(); int32_t current_pc = get_pc();
CheckForbiddenSlot(current_pc); CheckForbiddenSlot(current_pc);
if (do_branch) { if (do_branch) {
int32_t imm = instr->ImmValue(bits); int32_t imm = this->instr_.ImmValue(bits);
imm <<= 32 - bits; imm <<= 32 - bits;
imm >>= 32 - bits; imm >>= 32 - bits;
next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize; next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
} }
}; };
switch (op) { switch (op) {
// ------------- COP1. Coprocessor instructions. // ------------- COP1. Coprocessor instructions.
case COP1: case COP1:
switch (instr->RsFieldRaw()) { switch (instr_.RsFieldRaw()) {
case BC1: { // Branch on coprocessor condition. case BC1: { // Branch on coprocessor condition.
// Floating point. // Floating point.
uint32_t cc = instr->FBccValue(); uint32_t cc = instr_.FBccValue();
uint32_t fcsr_cc = get_fcsr_condition_bit(cc); uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
uint32_t cc_value = test_fcsr_bit(fcsr_cc); uint32_t cc_value = test_fcsr_bit(fcsr_cc);
bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
BranchHelper(do_branch); BranchHelper(do_branch);
break; break;
} }
...@@ -4104,7 +4093,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4104,7 +4093,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break; break;
// ------------- REGIMM class. // ------------- REGIMM class.
case REGIMM: case REGIMM:
switch (instr->RtFieldRaw()) { switch (instr_.RtFieldRaw()) {
case BLTZ: case BLTZ:
BranchHelper(rs < 0); BranchHelper(rs < 0);
break; break;
...@@ -4312,7 +4301,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4312,7 +4301,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
set_register(rt_reg, ReadB(rs + se_imm16)); set_register(rt_reg, ReadB(rs + se_imm16));
break; break;
case LH: case LH:
set_register(rt_reg, ReadH(rs + se_imm16, instr)); set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
break; break;
case LWL: { case LWL: {
// al_offset is offset of the effective address within an aligned word. // al_offset is offset of the effective address within an aligned word.
...@@ -4320,20 +4309,20 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4320,20 +4309,20 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
uint8_t byte_shift = kPointerAlignmentMask - al_offset; uint8_t byte_shift = kPointerAlignmentMask - al_offset;
uint32_t mask = (1 << byte_shift * 8) - 1; uint32_t mask = (1 << byte_shift * 8) - 1;
addr = rs + se_imm16 - al_offset; addr = rs + se_imm16 - al_offset;
alu_out = ReadW(addr, instr); alu_out = ReadW(addr, instr_.instr());
alu_out <<= byte_shift * 8; alu_out <<= byte_shift * 8;
alu_out |= rt & mask; alu_out |= rt & mask;
set_register(rt_reg, alu_out); set_register(rt_reg, alu_out);
break; break;
} }
case LW: case LW:
set_register(rt_reg, ReadW(rs + se_imm16, instr)); set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
break; break;
case LBU: case LBU:
set_register(rt_reg, ReadBU(rs + se_imm16)); set_register(rt_reg, ReadBU(rs + se_imm16));
break; break;
case LHU: case LHU:
set_register(rt_reg, ReadHU(rs + se_imm16, instr)); set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
break; break;
case LWR: { case LWR: {
// al_offset is offset of the effective address within an aligned word. // al_offset is offset of the effective address within an aligned word.
...@@ -4341,7 +4330,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4341,7 +4330,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
uint8_t byte_shift = kPointerAlignmentMask - al_offset; uint8_t byte_shift = kPointerAlignmentMask - al_offset;
uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
addr = rs + se_imm16 - al_offset; addr = rs + se_imm16 - al_offset;
alu_out = ReadW(addr, instr); alu_out = ReadW(addr, instr_.instr());
alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8; alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
alu_out |= rt & mask; alu_out |= rt & mask;
set_register(rt_reg, alu_out); set_register(rt_reg, alu_out);
...@@ -4351,7 +4340,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4351,7 +4340,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
WriteB(rs + se_imm16, static_cast<int8_t>(rt)); WriteB(rs + se_imm16, static_cast<int8_t>(rt));
break; break;
case SH: case SH:
WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr); WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
break; break;
case SWL: { case SWL: {
uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
...@@ -4359,40 +4348,40 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4359,40 +4348,40 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
addr = rs + se_imm16 - al_offset; addr = rs + se_imm16 - al_offset;
// Value to be written in memory. // Value to be written in memory.
uint32_t mem_value = ReadW(addr, instr) & mask; uint32_t mem_value = ReadW(addr, instr_.instr()) & mask;
mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
WriteW(addr, mem_value, instr); WriteW(addr, mem_value, instr_.instr());
break; break;
} }
case SW: case SW:
WriteW(rs + se_imm16, rt, instr); WriteW(rs + se_imm16, rt, instr_.instr());
break; break;
case SWR: { case SWR: {
uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
uint32_t mask = (1 << al_offset * 8) - 1; uint32_t mask = (1 << al_offset * 8) - 1;
addr = rs + se_imm16 - al_offset; addr = rs + se_imm16 - al_offset;
uint32_t mem_value = ReadW(addr, instr); uint32_t mem_value = ReadW(addr, instr_.instr());
mem_value = (rt << al_offset * 8) | (mem_value & mask); mem_value = (rt << al_offset * 8) | (mem_value & mask);
WriteW(addr, mem_value, instr); WriteW(addr, mem_value, instr_.instr());
break; break;
} }
case LWC1: case LWC1:
set_fpu_register_hi_word(ft_reg, 0); set_fpu_register_hi_word(ft_reg, 0);
set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr)); set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr_.instr()));
break; break;
case LDC1: case LDC1:
set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr)); set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
break; break;
case SWC1: case SWC1:
WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr); WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr_.instr());
break; break;
case SDC1: case SDC1:
WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
break; break;
// ------------- PC-Relative instructions. // ------------- PC-Relative instructions.
case PCREL: { case PCREL: {
// rt field: checking 5-bits. // rt field: checking 5-bits.
int32_t imm21 = instr->Imm21Value(); int32_t imm21 = instr_.Imm21Value();
int32_t current_pc = get_pc(); int32_t current_pc = get_pc();
uint8_t rt = (imm21 >> kImm16Bits); uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) { switch (rt) {
...@@ -4404,7 +4393,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4404,7 +4393,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
alu_out = current_pc + (se_imm16 << 16); alu_out = current_pc + (se_imm16 << 16);
break; break;
default: { default: {
int32_t imm19 = instr->Imm19Value(); int32_t imm19 = instr_.Imm19Value();
// rt field: checking the most significant 2-bits. // rt field: checking the most significant 2-bits.
rt = (imm21 >> kImm19Bits); rt = (imm21 >> kImm19Bits);
switch (rt) { switch (rt) {
...@@ -4452,13 +4441,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { ...@@ -4452,13 +4441,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
void Simulator::DecodeTypeJump(Instruction* instr) { void Simulator::DecodeTypeJump() {
SimInstruction simInstr = instr_;
// Get current pc. // Get current pc.
int32_t current_pc = get_pc(); int32_t current_pc = get_pc();
// Get unchanged bits of pc. // Get unchanged bits of pc.
int32_t pc_high_bits = current_pc & 0xf0000000; int32_t pc_high_bits = current_pc & 0xf0000000;
// Next pc. // Next pc.
int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
int32_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2);
// Execute branch delay slot. // Execute branch delay slot.
// We don't check for end_sim_pc. First it should not be met as the current pc // We don't check for end_sim_pc. First it should not be met as the current pc
...@@ -4469,7 +4460,7 @@ void Simulator::DecodeTypeJump(Instruction* instr) { ...@@ -4469,7 +4460,7 @@ void Simulator::DecodeTypeJump(Instruction* instr) {
// Update pc and ra if necessary. // Update pc and ra if necessary.
// Do this after the branch delay execution. // Do this after the branch delay execution.
if (instr->IsLinkingInstruction()) { if (simInstr.IsLinkingInstruction()) {
set_register(31, current_pc + 2 * Instruction::kInstrSize); set_register(31, current_pc + 2 * Instruction::kInstrSize);
} }
set_pc(next_pc); set_pc(next_pc);
...@@ -4491,15 +4482,16 @@ void Simulator::InstructionDecode(Instruction* instr) { ...@@ -4491,15 +4482,16 @@ void Simulator::InstructionDecode(Instruction* instr) {
dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
} }
switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) { instr_ = instr;
switch (instr_.InstructionType()) {
case Instruction::kRegisterType: case Instruction::kRegisterType:
DecodeTypeRegister(instr); DecodeTypeRegister();
break; break;
case Instruction::kImmediateType: case Instruction::kImmediateType:
DecodeTypeImmediate(instr); DecodeTypeImmediate();
break; break;
case Instruction::kJumpType: case Instruction::kJumpType:
DecodeTypeJump(instr); DecodeTypeJump();
break; break;
default: default:
UNSUPPORTED(); UNSUPPORTED();
......
...@@ -113,6 +113,39 @@ class CachePage { ...@@ -113,6 +113,39 @@ class CachePage {
char validity_map_[kValidityMapSize]; // One byte per line. char validity_map_[kValidityMapSize]; // One byte per line.
}; };
class SimInstructionBase : public InstructionBase {
public:
Type InstructionType() const { return type_; }
inline Instruction* instr() const { return instr_; }
inline int32_t operand() const { return operand_; }
protected:
SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
explicit SimInstructionBase(Instruction* instr) {}
int32_t operand_;
Instruction* instr_;
Type type_;
private:
DISALLOW_ASSIGN(SimInstructionBase);
};
class SimInstruction : public InstructionGetters<SimInstructionBase> {
public:
SimInstruction() {}
explicit SimInstruction(Instruction* instr) { *this = instr; }
SimInstruction& operator=(Instruction* instr) {
operand_ = *reinterpret_cast<const int32_t*>(instr);
instr_ = instr;
type_ = InstructionBase::InstructionType(EXTRA);
DCHECK(reinterpret_cast<void*>(&operand_) == this);
return *this;
}
};
class Simulator { class Simulator {
public: public:
friend class MipsDebugger; friend class MipsDebugger;
...@@ -299,8 +332,10 @@ class Simulator { ...@@ -299,8 +332,10 @@ class Simulator {
inline int32_t SetDoubleHIW(double* addr); inline int32_t SetDoubleHIW(double* addr);
inline int32_t SetDoubleLOW(double* addr); inline int32_t SetDoubleLOW(double* addr);
SimInstruction instr_;
// Executing is handled based on the instruction type. // Executing is handled based on the instruction type.
void DecodeTypeRegister(Instruction* instr); void DecodeTypeRegister();
// Functions called from DecodeTypeRegister. // Functions called from DecodeTypeRegister.
void DecodeTypeRegisterCOP1(); void DecodeTypeRegisterCOP1();
...@@ -322,39 +357,34 @@ class Simulator { ...@@ -322,39 +357,34 @@ class Simulator {
void DecodeTypeRegisterLRsType(); void DecodeTypeRegisterLRsType();
Instruction* currentInstr_; inline int32_t rs_reg() const { return instr_.RsValue(); }
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 int32_t rs() const { return get_register(rs_reg()); } inline int32_t rs() const { return get_register(rs_reg()); }
inline uint32_t rs_u() const { inline uint32_t rs_u() const {
return static_cast<uint32_t>(get_register(rs_reg())); return static_cast<uint32_t>(get_register(rs_reg()));
} }
inline int32_t rt_reg() const { return currentInstr_->RtValue(); } inline int32_t rt_reg() const { return instr_.RtValue(); }
inline int32_t rt() const { return get_register(rt_reg()); } inline int32_t rt() const { return get_register(rt_reg()); }
inline uint32_t rt_u() const { inline uint32_t rt_u() const {
return static_cast<uint32_t>(get_register(rt_reg())); return static_cast<uint32_t>(get_register(rt_reg()));
} }
inline int32_t rd_reg() const { return currentInstr_->RdValue(); } inline int32_t rd_reg() const { return instr_.RdValue(); }
inline int32_t fr_reg() const { return currentInstr_->FrValue(); } inline int32_t fr_reg() const { return instr_.FrValue(); }
inline int32_t fs_reg() const { return currentInstr_->FsValue(); } inline int32_t fs_reg() const { return instr_.FsValue(); }
inline int32_t ft_reg() const { return currentInstr_->FtValue(); } inline int32_t ft_reg() const { return instr_.FtValue(); }
inline int32_t fd_reg() const { return currentInstr_->FdValue(); } inline int32_t fd_reg() const { return instr_.FdValue(); }
inline int32_t sa() const { return currentInstr_->SaValue(); } inline int32_t sa() const { return instr_.SaValue(); }
inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); } inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
inline void SetResult(int32_t rd_reg, int32_t alu_out) { inline void SetResult(int32_t rd_reg, int32_t alu_out) {
set_register(rd_reg, alu_out); set_register(rd_reg, alu_out);
TraceRegWr(alu_out); TraceRegWr(alu_out);
} }
void DecodeTypeImmediate(Instruction* instr); void DecodeTypeImmediate();
void DecodeTypeJump(Instruction* instr); void DecodeTypeJump();
// Used for breakpoints and traps. // Used for breakpoints and traps.
void SoftwareInterrupt(Instruction* instr); void SoftwareInterrupt();
// Compact branch guard. // Compact branch guard.
void CheckForbiddenSlot(int32_t current_pc) { void CheckForbiddenSlot(int32_t current_pc) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment