MIPS64: Improve performance of simulator in debug mode.
BUG= Review-Url: https://codereview.chromium.org/2375673002 Cr-Commit-Position: refs/heads/master@{#39860}
This commit is contained in:
parent
9b7264e30d
commit
96cb6d5a58
@ -121,118 +121,6 @@ int FPURegisters::Number(const char* name) {
|
||||
// No Cregister with the reguested name found.
|
||||
return kInvalidFPURegister;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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 v8
|
||||
|
||||
|
@ -899,8 +899,7 @@ static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) {
|
||||
return 1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift);
|
||||
}
|
||||
|
||||
|
||||
class Instruction {
|
||||
class InstructionBase {
|
||||
public:
|
||||
enum {
|
||||
kInstrSize = 4,
|
||||
@ -910,6 +909,9 @@ class Instruction {
|
||||
kPCReadOffset = 0
|
||||
};
|
||||
|
||||
// Instruction type.
|
||||
enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 };
|
||||
|
||||
// Get the raw instruction bits.
|
||||
inline Instr InstructionBits() const {
|
||||
return *reinterpret_cast<const Instr*>(this);
|
||||
@ -930,14 +932,6 @@ class Instruction {
|
||||
return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1);
|
||||
}
|
||||
|
||||
// Instruction type.
|
||||
enum Type {
|
||||
kRegisterType,
|
||||
kImmediateType,
|
||||
kJumpType,
|
||||
kUnsupported = -1
|
||||
};
|
||||
|
||||
enum TypeChecks { NORMAL, EXTRA };
|
||||
|
||||
static constexpr uint64_t kOpcodeImmediateTypeMask =
|
||||
@ -996,9 +990,6 @@ class Instruction {
|
||||
FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
|
||||
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.
|
||||
inline Opcode OpcodeValue() const {
|
||||
@ -1006,78 +997,8 @@ class Instruction {
|
||||
Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift));
|
||||
}
|
||||
|
||||
inline int RsValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType ||
|
||||
InstructionType() == kImmediateType);
|
||||
return Bits(kRsShift + kRsBits - 1, kRsShift);
|
||||
}
|
||||
|
||||
inline int RtValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType ||
|
||||
InstructionType() == kImmediateType);
|
||||
return Bits(kRtShift + kRtBits - 1, kRtShift);
|
||||
}
|
||||
|
||||
inline int RdValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return Bits(kRdShift + kRdBits - 1, kRdShift);
|
||||
}
|
||||
|
||||
inline int SaValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return Bits(kSaShift + kSaBits - 1, kSaShift);
|
||||
}
|
||||
|
||||
inline int LsaSaValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return Bits(kSaShift + kLsaSaBits - 1, kSaShift);
|
||||
}
|
||||
|
||||
inline int FunctionValue() const {
|
||||
DCHECK(InstructionType() == kRegisterType ||
|
||||
InstructionType() == kImmediateType);
|
||||
return Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
|
||||
}
|
||||
|
||||
inline int FdValue() const {
|
||||
return Bits(kFdShift + kFdBits - 1, kFdShift);
|
||||
}
|
||||
|
||||
inline int FsValue() const {
|
||||
return Bits(kFsShift + kFsBits - 1, kFsShift);
|
||||
}
|
||||
|
||||
inline int FtValue() const {
|
||||
return Bits(kFtShift + kFtBits - 1, kFtShift);
|
||||
}
|
||||
|
||||
inline int FrValue() const {
|
||||
return Bits(kFrShift + kFrBits -1, kFrShift);
|
||||
}
|
||||
|
||||
inline int Bp2Value() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
|
||||
}
|
||||
|
||||
inline int Bp3Value() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift);
|
||||
}
|
||||
|
||||
// Float Compare condition code instruction bits.
|
||||
inline int FCccValue() const {
|
||||
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
|
||||
}
|
||||
|
||||
// Float Branch condition code instruction bits.
|
||||
inline int FBccValue() const {
|
||||
return Bits(kFBccShift + kFBccBits - 1, kFBccShift);
|
||||
}
|
||||
|
||||
// Float Branch true/false instruction bit.
|
||||
inline int FBtrueValue() const {
|
||||
return Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
|
||||
inline int FunctionFieldRaw() const {
|
||||
return InstructionBits() & kFunctionFieldMask;
|
||||
}
|
||||
|
||||
// Return the fields at their original place in the instruction encoding.
|
||||
@ -1085,39 +1006,135 @@ class Instruction {
|
||||
return static_cast<Opcode>(InstructionBits() & kOpcodeMask);
|
||||
}
|
||||
|
||||
inline int RsFieldRaw() const {
|
||||
DCHECK(InstructionType() == kRegisterType ||
|
||||
InstructionType() == kImmediateType);
|
||||
return InstructionBits() & kRsFieldMask;
|
||||
}
|
||||
|
||||
// Same as above function, but safe to call within InstructionType().
|
||||
// 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 {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
||||
this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kRsShift + kRsBits - 1, kRsShift);
|
||||
}
|
||||
|
||||
inline int RtValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
||||
this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kRtShift + kRtBits - 1, kRtShift);
|
||||
}
|
||||
|
||||
inline int RdValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kRdShift + kRdBits - 1, kRdShift);
|
||||
}
|
||||
|
||||
inline int SaValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kSaShift + kSaBits - 1, kSaShift);
|
||||
}
|
||||
|
||||
inline int LsaSaValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kSaShift + kLsaSaBits - 1, kSaShift);
|
||||
}
|
||||
|
||||
inline int FunctionValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
||||
this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
|
||||
}
|
||||
|
||||
inline int FdValue() const {
|
||||
return this->Bits(kFdShift + kFdBits - 1, kFdShift);
|
||||
}
|
||||
|
||||
inline int FsValue() const {
|
||||
return this->Bits(kFsShift + kFsBits - 1, kFsShift);
|
||||
}
|
||||
|
||||
inline int FtValue() const {
|
||||
return this->Bits(kFtShift + kFtBits - 1, kFtShift);
|
||||
}
|
||||
|
||||
inline int FrValue() const {
|
||||
return this->Bits(kFrShift + kFrBits - 1, kFrShift);
|
||||
}
|
||||
|
||||
inline int Bp2Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
|
||||
}
|
||||
|
||||
inline int Bp3Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift);
|
||||
}
|
||||
|
||||
// Float Compare condition code instruction bits.
|
||||
inline int FCccValue() const {
|
||||
return this->Bits(kFCccShift + kFCccBits - 1, kFCccShift);
|
||||
}
|
||||
|
||||
// Float Branch condition code instruction bits.
|
||||
inline int FBccValue() const {
|
||||
return this->Bits(kFBccShift + kFBccBits - 1, kFBccShift);
|
||||
}
|
||||
|
||||
// Float Branch true/false instruction bit.
|
||||
inline int FBtrueValue() const {
|
||||
return this->Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
|
||||
}
|
||||
|
||||
// Return the fields at their original place in the instruction encoding.
|
||||
inline Opcode OpcodeFieldRaw() const {
|
||||
return static_cast<Opcode>(this->InstructionBits() & kOpcodeMask);
|
||||
}
|
||||
|
||||
inline int RsFieldRaw() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
||||
this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->InstructionBits() & kRsFieldMask;
|
||||
}
|
||||
|
||||
// Same as above function, but safe to call within InstructionType().
|
||||
inline int RsFieldRawNoAssert() const {
|
||||
return this->InstructionBits() & kRsFieldMask;
|
||||
}
|
||||
|
||||
inline int RtFieldRaw() const {
|
||||
DCHECK(InstructionType() == kRegisterType ||
|
||||
InstructionType() == kImmediateType);
|
||||
return InstructionBits() & kRtFieldMask;
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
||||
this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->InstructionBits() & kRtFieldMask;
|
||||
}
|
||||
|
||||
inline int RdFieldRaw() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return InstructionBits() & kRdFieldMask;
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->InstructionBits() & kRdFieldMask;
|
||||
}
|
||||
|
||||
inline int SaFieldRaw() const {
|
||||
return InstructionBits() & kSaFieldMask;
|
||||
return this->InstructionBits() & kSaFieldMask;
|
||||
}
|
||||
|
||||
inline int FunctionFieldRaw() const {
|
||||
return InstructionBits() & kFunctionFieldMask;
|
||||
return this->InstructionBits() & kFunctionFieldMask;
|
||||
}
|
||||
|
||||
// Get the secondary field according to the opcode.
|
||||
inline int SecondaryValue() const {
|
||||
Opcode op = OpcodeFieldRaw();
|
||||
Opcode op = this->OpcodeFieldRaw();
|
||||
switch (op) {
|
||||
case SPECIAL:
|
||||
case SPECIAL2:
|
||||
@ -1132,34 +1149,34 @@ class Instruction {
|
||||
}
|
||||
|
||||
inline int32_t ImmValue(int bits) const {
|
||||
DCHECK(InstructionType() == kImmediateType);
|
||||
return Bits(bits - 1, 0);
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(bits - 1, 0);
|
||||
}
|
||||
|
||||
inline int32_t Imm16Value() const {
|
||||
DCHECK(InstructionType() == kImmediateType);
|
||||
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm18Value() const {
|
||||
DCHECK(InstructionType() == kImmediateType);
|
||||
return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm19Value() const {
|
||||
DCHECK(InstructionType() == kImmediateType);
|
||||
return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm21Value() const {
|
||||
DCHECK(InstructionType() == kImmediateType);
|
||||
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm26Value() const {
|
||||
DCHECK((InstructionType() == kJumpType) ||
|
||||
(InstructionType() == kImmediateType));
|
||||
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
|
||||
DCHECK((this->InstructionType() == InstructionBase::kJumpType) ||
|
||||
(this->InstructionType() == InstructionBase::kImmediateType));
|
||||
return this->Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
|
||||
}
|
||||
|
||||
static bool IsForbiddenAfterBranchInstr(Instr instr);
|
||||
@ -1167,14 +1184,21 @@ class Instruction {
|
||||
// Say if the instruction should not be used in a branch delay slot or
|
||||
// immediately after a compact branch.
|
||||
inline bool IsForbiddenAfterBranch() const {
|
||||
return IsForbiddenAfterBranchInstr(InstructionBits());
|
||||
return IsForbiddenAfterBranchInstr(this->InstructionBits());
|
||||
}
|
||||
|
||||
inline bool IsForbiddenInBranchDelay() const {
|
||||
return IsForbiddenAfterBranch();
|
||||
}
|
||||
|
||||
// Say if the instruction 'links'. e.g. jal, bal.
|
||||
bool IsLinkingInstruction() const;
|
||||
// Say if the instruction is a break or a trap.
|
||||
bool IsTrap() const;
|
||||
};
|
||||
|
||||
class Instruction : public InstructionGetters<InstructionBase> {
|
||||
public:
|
||||
// Instructions are read of out a code stream. The only way to get a
|
||||
// reference to an instruction is to convert a pointer. There is no way
|
||||
// to allocate or create instances of class Instruction.
|
||||
@ -1202,8 +1226,8 @@ const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize * 2;
|
||||
const int kInvalidStackOffset = -1;
|
||||
const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
|
||||
|
||||
|
||||
Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
|
||||
InstructionBase::Type InstructionBase::InstructionType(
|
||||
TypeChecks checks) const {
|
||||
if (checks == EXTRA) {
|
||||
if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) {
|
||||
return kImmediateType;
|
||||
@ -1306,9 +1330,119 @@ Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
|
||||
}
|
||||
return kUnsupported;
|
||||
}
|
||||
|
||||
#undef OpcodeToBitNumber
|
||||
#undef FunctionFieldToBitNumber
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Instructions.
|
||||
|
||||
template <class P>
|
||||
bool InstructionGetters<P>::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;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool InstructionGetters<P>::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 v8
|
||||
|
||||
|
@ -96,7 +96,7 @@ class MipsDebugger {
|
||||
void RedoBreakpoints();
|
||||
};
|
||||
|
||||
#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
|
||||
inline void UNSUPPORTED() { printf("Sim: Unsupported instruction.\n"); }
|
||||
|
||||
void MipsDebugger::Stop(Instruction* instr) {
|
||||
// Get the stop code.
|
||||
@ -1935,15 +1935,15 @@ typedef void (*SimulatorRuntimeProfilingGetterCall)(
|
||||
|
||||
// Software interrupt instructions are used by the simulator to call into the
|
||||
// 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,
|
||||
// the break_ instruction, or several variants of traps. All
|
||||
// Are "SPECIAL" class opcode, and are distinuished by function.
|
||||
int32_t func = instr->FunctionFieldRaw();
|
||||
uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
|
||||
int32_t func = instr_.FunctionFieldRaw();
|
||||
uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
|
||||
// We first check if we met a call_rt_redirected.
|
||||
if (instr->InstructionBits() == rtCallRedirInstr) {
|
||||
Redirection* redirection = Redirection::FromSwiInstruction(instr);
|
||||
if (instr_.InstructionBits() == rtCallRedirInstr) {
|
||||
Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr());
|
||||
int64_t arg0 = get_register(a0);
|
||||
int64_t arg1 = get_register(a1);
|
||||
int64_t arg2 = get_register(a2);
|
||||
@ -2169,7 +2169,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
||||
PrintWatchpoint(code);
|
||||
} else {
|
||||
IncreaseStopCounter(code);
|
||||
HandleStop(code, instr);
|
||||
HandleStop(code, instr_.instr());
|
||||
}
|
||||
} else {
|
||||
// All remaining break_ codes, and all traps are handled here.
|
||||
@ -2417,9 +2417,9 @@ void Simulator::DecodeTypeRegisterSRsType() {
|
||||
int32_t ft_int = bit_cast<int32_t>(ft);
|
||||
int32_t fd_int = bit_cast<int32_t>(fd);
|
||||
uint32_t cc, fcsr_cc;
|
||||
cc = get_instr()->FCccValue();
|
||||
cc = instr_.FCccValue();
|
||||
fcsr_cc = get_fcsr_condition_bit(cc);
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case RINT: {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
float result, temp_result;
|
||||
@ -2763,7 +2763,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
|
||||
uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
|
||||
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
|
||||
if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
|
||||
} else {
|
||||
@ -2784,15 +2784,14 @@ void Simulator::DecodeTypeRegisterDRsType() {
|
||||
double ft, fs, fd;
|
||||
uint32_t cc, fcsr_cc;
|
||||
fs = get_fpu_register_double(fs_reg());
|
||||
ft = (get_instr()->FunctionFieldRaw() != MOVF)
|
||||
? get_fpu_register_double(ft_reg())
|
||||
: 0.0;
|
||||
ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
|
||||
: 0.0;
|
||||
fd = get_fpu_register_double(fd_reg());
|
||||
cc = get_instr()->FCccValue();
|
||||
cc = 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 (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case RINT: {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
double result, temp, temp_result;
|
||||
@ -2860,7 +2859,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
|
||||
// Same function field for MOVT.D and MOVF.D
|
||||
uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
|
||||
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
|
||||
if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
|
||||
} else {
|
||||
@ -3151,7 +3150,7 @@ 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()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case CVT_S_W: // Convert word to float (single).
|
||||
alu_out = get_fpu_register_signed_word(fs_reg());
|
||||
set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
|
||||
@ -3243,7 +3242,7 @@ void Simulator::DecodeTypeRegisterLRsType() {
|
||||
double fs = get_fpu_register_double(fs_reg());
|
||||
double ft = get_fpu_register_double(ft_reg());
|
||||
int64_t i64;
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case CVT_D_L: // Mips32r2 instruction.
|
||||
i64 = get_fpu_register(fs_reg());
|
||||
set_fpu_register_double(fd_reg(), static_cast<double>(i64));
|
||||
@ -3332,7 +3331,7 @@ void Simulator::DecodeTypeRegisterLRsType() {
|
||||
|
||||
|
||||
void Simulator::DecodeTypeRegisterCOP1() {
|
||||
switch (get_instr()->RsFieldRaw()) {
|
||||
switch (instr_.RsFieldRaw()) {
|
||||
case BC1: // Branch on coprocessor condition.
|
||||
case BC1EQZ:
|
||||
case BC1NEZ:
|
||||
@ -3395,7 +3394,7 @@ void Simulator::DecodeTypeRegisterCOP1() {
|
||||
|
||||
|
||||
void Simulator::DecodeTypeRegisterCOP1X() {
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case MADD_S: {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
float fr, ft, fs;
|
||||
@ -3444,7 +3443,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
int64_t alu_out;
|
||||
bool do_interrupt = false;
|
||||
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case SELEQZ_S:
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
set_register(rd_reg(), rt() == 0 ? rs() : 0);
|
||||
@ -3690,7 +3689,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
case DIV:
|
||||
case DDIV: {
|
||||
const int64_t int_min_value =
|
||||
get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
|
||||
instr_.FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
|
||||
switch (kArchVariant) {
|
||||
case kMips64r2:
|
||||
// Divide by zero and overflow was not checked in the
|
||||
@ -3736,7 +3735,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
case kMips64r6: {
|
||||
uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
|
||||
uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
|
||||
switch (get_instr()->SaValue()) {
|
||||
switch (sa()) {
|
||||
case DIV_OP:
|
||||
if (rt_u_32 != 0) {
|
||||
set_register(rd_reg(), rs_u_32 / rt_u_32);
|
||||
@ -3765,7 +3764,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
case DDIVU:
|
||||
switch (kArchVariant) {
|
||||
case kMips64r6: {
|
||||
switch (get_instr()->SaValue()) {
|
||||
switch (instr_.SaValue()) {
|
||||
case DIV_OP:
|
||||
if (rt_u() != 0) {
|
||||
set_register(rd_reg(), rs_u() / rt_u());
|
||||
@ -3887,9 +3886,9 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
}
|
||||
break;
|
||||
case MOVCI: {
|
||||
uint32_t cc = get_instr()->FBccValue();
|
||||
uint32_t cc = instr_.FBccValue();
|
||||
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());
|
||||
} else {
|
||||
if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
|
||||
@ -3905,14 +3904,14 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (do_interrupt) {
|
||||
SoftwareInterrupt(get_instr());
|
||||
SoftwareInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeTypeRegisterSPECIAL2() {
|
||||
int64_t alu_out;
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case MUL:
|
||||
alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u());
|
||||
SetResult(rd_reg(), alu_out);
|
||||
@ -3941,7 +3940,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2() {
|
||||
|
||||
void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
int64_t alu_out;
|
||||
switch (get_instr()->FunctionFieldRaw()) {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case INS: { // Mips64r2 instruction.
|
||||
// Interpret rd field as 5-bit msb of insert.
|
||||
uint16_t msb = rd_reg();
|
||||
@ -4010,7 +4009,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
break;
|
||||
}
|
||||
case BSHFL: {
|
||||
int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
|
||||
int32_t sa = instr_.SaFieldRaw() >> kSaShift;
|
||||
switch (sa) {
|
||||
case BITSWAP: {
|
||||
uint32_t input = static_cast<uint32_t>(rt());
|
||||
@ -4088,7 +4087,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const uint8_t bp2 = get_instr()->Bp2Value();
|
||||
const uint8_t bp2 = instr_.Bp2Value();
|
||||
sa >>= kBp2Bits;
|
||||
switch (sa) {
|
||||
case ALIGN: {
|
||||
@ -4113,7 +4112,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
break;
|
||||
}
|
||||
case DBSHFL: {
|
||||
int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
|
||||
int32_t sa = instr_.SaFieldRaw() >> kSaShift;
|
||||
switch (sa) {
|
||||
case DBITSWAP: {
|
||||
switch (sa) {
|
||||
@ -4187,7 +4186,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const uint8_t bp3 = get_instr()->Bp3Value();
|
||||
const uint8_t bp3 = instr_.Bp3Value();
|
||||
sa >>= kBp3Bits;
|
||||
switch (sa) {
|
||||
case DALIGN: {
|
||||
@ -4216,12 +4215,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
set_instr(instr);
|
||||
|
||||
void Simulator::DecodeTypeRegister() {
|
||||
// ---------- Execution.
|
||||
switch (instr->OpcodeFieldRaw()) {
|
||||
switch (instr_.OpcodeFieldRaw()) {
|
||||
case COP1:
|
||||
DecodeTypeRegisterCOP1();
|
||||
break;
|
||||
@ -4247,18 +4243,18 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
|
||||
|
||||
// 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.
|
||||
Opcode op = instr->OpcodeFieldRaw();
|
||||
int32_t rs_reg = instr->RsValue();
|
||||
int64_t rs = get_register(instr->RsValue());
|
||||
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.
|
||||
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();
|
||||
int16_t imm16 = instr_.Imm16Value();
|
||||
int32_t imm18 = instr_.Imm18Value();
|
||||
|
||||
int32_t ft_reg = instr->FtValue(); // Destination register.
|
||||
int32_t ft_reg = instr_.FtValue(); // Destination register.
|
||||
|
||||
// Zero extended immediate.
|
||||
uint64_t oe_imm16 = 0xffff & imm16;
|
||||
@ -4283,38 +4279,36 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
const int kInt64AlignmentMask = sizeof(uint64_t) - 1;
|
||||
|
||||
// Branch instructions common part.
|
||||
auto BranchAndLinkHelper = [this, instr, &next_pc,
|
||||
&execute_branch_delay_instruction](
|
||||
bool do_branch) {
|
||||
execute_branch_delay_instruction = true;
|
||||
int64_t current_pc = get_pc();
|
||||
if (do_branch) {
|
||||
int16_t imm16 = instr->Imm16Value();
|
||||
next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
|
||||
set_register(31, current_pc + 2 * Instruction::kInstrSize);
|
||||
} else {
|
||||
next_pc = current_pc + 2 * Instruction::kInstrSize;
|
||||
}
|
||||
};
|
||||
auto BranchAndLinkHelper =
|
||||
[this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
|
||||
execute_branch_delay_instruction = true;
|
||||
int64_t current_pc = get_pc();
|
||||
if (do_branch) {
|
||||
int16_t imm16 = instr_.Imm16Value();
|
||||
next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
|
||||
set_register(31, current_pc + 2 * Instruction::kInstrSize);
|
||||
} else {
|
||||
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 = true;
|
||||
int64_t current_pc = get_pc();
|
||||
if (do_branch) {
|
||||
int16_t imm16 = instr->Imm16Value();
|
||||
int16_t imm16 = instr_.Imm16Value();
|
||||
next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
|
||||
} else {
|
||||
next_pc = current_pc + 2 * Instruction::kInstrSize;
|
||||
}
|
||||
};
|
||||
|
||||
auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
|
||||
int bits) {
|
||||
auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
|
||||
int64_t current_pc = get_pc();
|
||||
CheckForbiddenSlot(current_pc);
|
||||
if (do_branch) {
|
||||
int32_t imm = instr->ImmValue(bits);
|
||||
int32_t imm = instr_.ImmValue(bits);
|
||||
imm <<= 32 - bits;
|
||||
imm >>= 32 - bits;
|
||||
next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
|
||||
@ -4322,11 +4316,11 @@ 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) {
|
||||
int64_t current_pc = get_pc();
|
||||
CheckForbiddenSlot(current_pc);
|
||||
if (do_branch) {
|
||||
int32_t imm = instr->ImmValue(bits);
|
||||
int32_t imm = instr_.ImmValue(bits);
|
||||
imm <<= 32 - bits;
|
||||
imm >>= 32 - bits;
|
||||
next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
|
||||
@ -4336,12 +4330,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
switch (op) {
|
||||
// ------------- COP1. Coprocessor instructions.
|
||||
case COP1:
|
||||
switch (instr->RsFieldRaw()) {
|
||||
switch (instr_.RsFieldRaw()) {
|
||||
case BC1: { // Branch on coprocessor condition.
|
||||
uint32_t cc = instr->FBccValue();
|
||||
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;
|
||||
bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
|
||||
BranchHelper(do_branch);
|
||||
break;
|
||||
}
|
||||
@ -4357,7 +4351,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
break;
|
||||
// ------------- REGIMM class.
|
||||
case REGIMM:
|
||||
switch (instr->RtFieldRaw()) {
|
||||
switch (instr_.RtFieldRaw()) {
|
||||
case BLTZ:
|
||||
BranchHelper(rs < 0);
|
||||
break;
|
||||
@ -4575,7 +4569,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
set_register(rt_reg, ReadB(rs + se_imm16));
|
||||
break;
|
||||
case LH:
|
||||
set_register(rt_reg, ReadH(rs + se_imm16, instr));
|
||||
set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
case LWL: {
|
||||
// al_offset is offset of the effective address within an aligned word.
|
||||
@ -4583,26 +4577,26 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
uint8_t byte_shift = kInt32AlignmentMask - al_offset;
|
||||
uint32_t mask = (1 << byte_shift * 8) - 1;
|
||||
addr = rs + se_imm16 - al_offset;
|
||||
int32_t val = ReadW(addr, instr);
|
||||
int32_t val = ReadW(addr, instr_.instr());
|
||||
val <<= byte_shift * 8;
|
||||
val |= rt & mask;
|
||||
set_register(rt_reg, static_cast<int64_t>(val));
|
||||
break;
|
||||
}
|
||||
case LW:
|
||||
set_register(rt_reg, ReadW(rs + se_imm16, instr));
|
||||
set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
case LWU:
|
||||
set_register(rt_reg, ReadWU(rs + se_imm16, instr));
|
||||
set_register(rt_reg, ReadWU(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
case LD:
|
||||
set_register(rt_reg, Read2W(rs + se_imm16, instr));
|
||||
set_register(rt_reg, Read2W(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
case LBU:
|
||||
set_register(rt_reg, ReadBU(rs + se_imm16));
|
||||
break;
|
||||
case LHU:
|
||||
set_register(rt_reg, ReadHU(rs + se_imm16, instr));
|
||||
set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
case LWR: {
|
||||
// al_offset is offset of the effective address within an aligned word.
|
||||
@ -4610,7 +4604,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
uint8_t byte_shift = kInt32AlignmentMask - al_offset;
|
||||
uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
|
||||
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 |= rt & mask;
|
||||
set_register(rt_reg, alu_out);
|
||||
@ -4622,7 +4616,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
uint8_t byte_shift = kInt64AlignmentMask - al_offset;
|
||||
uint64_t mask = (1UL << byte_shift * 8) - 1;
|
||||
addr = rs + se_imm16 - al_offset;
|
||||
alu_out = Read2W(addr, instr);
|
||||
alu_out = Read2W(addr, instr_.instr());
|
||||
alu_out <<= byte_shift * 8;
|
||||
alu_out |= rt & mask;
|
||||
set_register(rt_reg, alu_out);
|
||||
@ -4634,7 +4628,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
uint8_t byte_shift = kInt64AlignmentMask - al_offset;
|
||||
uint64_t mask = al_offset ? (~0UL << (byte_shift + 1) * 8) : 0UL;
|
||||
addr = rs + se_imm16 - al_offset;
|
||||
alu_out = Read2W(addr, instr);
|
||||
alu_out = Read2W(addr, instr_.instr());
|
||||
alu_out = alu_out >> al_offset * 8;
|
||||
alu_out |= rt & mask;
|
||||
set_register(rt_reg, alu_out);
|
||||
@ -4644,31 +4638,31 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
WriteB(rs + se_imm16, static_cast<int8_t>(rt));
|
||||
break;
|
||||
case SH:
|
||||
WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
|
||||
WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.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;
|
||||
uint64_t mem_value = ReadW(addr, instr) & mask;
|
||||
uint64_t mem_value = ReadW(addr, instr_.instr()) & mask;
|
||||
mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
|
||||
WriteW(addr, static_cast<int32_t>(mem_value), instr);
|
||||
WriteW(addr, static_cast<int32_t>(mem_value), instr_.instr());
|
||||
break;
|
||||
}
|
||||
case SW:
|
||||
WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr);
|
||||
WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr_.instr());
|
||||
break;
|
||||
case SD:
|
||||
Write2W(rs + se_imm16, rt, instr);
|
||||
Write2W(rs + se_imm16, rt, instr_.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;
|
||||
uint64_t mem_value = ReadW(addr, instr);
|
||||
uint64_t mem_value = ReadW(addr, instr_.instr());
|
||||
mem_value = (rt << al_offset * 8) | (mem_value & mask);
|
||||
WriteW(addr, static_cast<int32_t>(mem_value), instr);
|
||||
WriteW(addr, static_cast<int32_t>(mem_value), instr_.instr());
|
||||
break;
|
||||
}
|
||||
case SDL: {
|
||||
@ -4676,39 +4670,39 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
uint8_t byte_shift = kInt64AlignmentMask - al_offset;
|
||||
uint64_t mask = byte_shift ? (~0UL << (al_offset + 1) * 8) : 0;
|
||||
addr = rs + se_imm16 - al_offset;
|
||||
uint64_t mem_value = Read2W(addr, instr) & mask;
|
||||
uint64_t mem_value = Read2W(addr, instr_.instr()) & mask;
|
||||
mem_value |= rt >> byte_shift * 8;
|
||||
Write2W(addr, mem_value, instr);
|
||||
Write2W(addr, mem_value, instr_.instr());
|
||||
break;
|
||||
}
|
||||
case SDR: {
|
||||
uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
|
||||
uint64_t mask = (1UL << al_offset * 8) - 1;
|
||||
addr = rs + se_imm16 - al_offset;
|
||||
uint64_t mem_value = Read2W(addr, instr);
|
||||
uint64_t mem_value = Read2W(addr, instr_.instr());
|
||||
mem_value = (rt << al_offset * 8) | (mem_value & mask);
|
||||
Write2W(addr, mem_value, instr);
|
||||
Write2W(addr, mem_value, instr_.instr());
|
||||
break;
|
||||
}
|
||||
case LWC1:
|
||||
set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
|
||||
set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
|
||||
set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
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;
|
||||
case SWC1: {
|
||||
int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg));
|
||||
WriteW(rs + se_imm16, alu_out_32, instr);
|
||||
WriteW(rs + se_imm16, alu_out_32, instr_.instr());
|
||||
break;
|
||||
}
|
||||
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;
|
||||
// ------------- PC-Relative instructions.
|
||||
case PCREL: {
|
||||
// rt field: checking 5-bits.
|
||||
int32_t imm21 = instr->Imm21Value();
|
||||
int32_t imm21 = instr_.Imm21Value();
|
||||
int64_t current_pc = get_pc();
|
||||
uint8_t rt = (imm21 >> kImm16Bits);
|
||||
switch (rt) {
|
||||
@ -4720,14 +4714,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
alu_out = current_pc + (se_imm16 << 16);
|
||||
break;
|
||||
default: {
|
||||
int32_t imm19 = instr->Imm19Value();
|
||||
int32_t imm19 = instr_.Imm19Value();
|
||||
// rt field: checking the most significant 3-bits.
|
||||
rt = (imm21 >> kImm18Bits);
|
||||
switch (rt) {
|
||||
case LDPC:
|
||||
addr =
|
||||
(current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
|
||||
alu_out = Read2W(addr, instr);
|
||||
alu_out = Read2W(addr, instr_.instr());
|
||||
break;
|
||||
default: {
|
||||
// rt field: checking the most significant 2-bits.
|
||||
@ -4791,13 +4785,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
|
||||
|
||||
// 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.
|
||||
int64_t current_pc = get_pc();
|
||||
// Get unchanged bits of pc.
|
||||
int64_t pc_high_bits = current_pc & 0xfffffffff0000000;
|
||||
// Next pc.
|
||||
int64_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
|
||||
int64_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2);
|
||||
|
||||
// Execute branch delay slot.
|
||||
// We don't check for end_sim_pc. First it should not be met as the current pc
|
||||
@ -4808,7 +4803,7 @@ void Simulator::DecodeTypeJump(Instruction* instr) {
|
||||
|
||||
// Update pc and ra if necessary.
|
||||
// Do this after the branch delay execution.
|
||||
if (instr->IsLinkingInstruction()) {
|
||||
if (simInstr.IsLinkingInstruction()) {
|
||||
set_register(31, current_pc + 2 * Instruction::kInstrSize);
|
||||
}
|
||||
set_pc(next_pc);
|
||||
@ -4833,15 +4828,16 @@ void Simulator::InstructionDecode(Instruction* instr) {
|
||||
dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
|
||||
}
|
||||
|
||||
switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
|
||||
instr_ = instr;
|
||||
switch (instr_.InstructionType()) {
|
||||
case Instruction::kRegisterType:
|
||||
DecodeTypeRegister(instr);
|
||||
DecodeTypeRegister();
|
||||
break;
|
||||
case Instruction::kImmediateType:
|
||||
DecodeTypeImmediate(instr);
|
||||
DecodeTypeImmediate();
|
||||
break;
|
||||
case Instruction::kJumpType:
|
||||
DecodeTypeJump(instr);
|
||||
DecodeTypeJump();
|
||||
break;
|
||||
default:
|
||||
UNSUPPORTED();
|
||||
|
@ -122,6 +122,39 @@ class CachePage {
|
||||
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 {
|
||||
public:
|
||||
friend class MipsDebugger;
|
||||
@ -314,6 +347,8 @@ class Simulator {
|
||||
inline int32_t SetDoubleHIW(double* addr);
|
||||
inline int32_t SetDoubleLOW(double* addr);
|
||||
|
||||
SimInstruction instr_;
|
||||
|
||||
// functions called from DecodeTypeRegister.
|
||||
void DecodeTypeRegisterCOP1();
|
||||
|
||||
@ -335,40 +370,36 @@ class Simulator {
|
||||
void DecodeTypeRegisterLRsType();
|
||||
|
||||
// Executing is handled based on the instruction type.
|
||||
void DecodeTypeRegister(Instruction* instr);
|
||||
void DecodeTypeRegister();
|
||||
|
||||
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 int32_t rs_reg() const { return instr_.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 int32_t rt_reg() const { return instr_.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 int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
|
||||
inline int32_t rd_reg() const { return instr_.RdValue(); }
|
||||
inline int32_t fr_reg() const { return instr_.FrValue(); }
|
||||
inline int32_t fs_reg() const { return instr_.FsValue(); }
|
||||
inline int32_t ft_reg() const { return instr_.FtValue(); }
|
||||
inline int32_t fd_reg() const { return instr_.FdValue(); }
|
||||
inline int32_t sa() const { return instr_.SaValue(); }
|
||||
inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
|
||||
|
||||
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);
|
||||
void DecodeTypeImmediate();
|
||||
void DecodeTypeJump();
|
||||
|
||||
// Used for breakpoints and traps.
|
||||
void SoftwareInterrupt(Instruction* instr);
|
||||
void SoftwareInterrupt();
|
||||
|
||||
// Compact branch guard.
|
||||
void CheckForbiddenSlot(int64_t current_pc) {
|
||||
|
Loading…
Reference in New Issue
Block a user