aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/mips64/simulator-mips64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/mips64/simulator-mips64.cc')
-rw-r--r--deps/v8/src/mips64/simulator-mips64.cc603
1 files changed, 452 insertions, 151 deletions
diff --git a/deps/v8/src/mips64/simulator-mips64.cc b/deps/v8/src/mips64/simulator-mips64.cc
index 4a7fd7c10f..7fa96442f9 100644
--- a/deps/v8/src/mips64/simulator-mips64.cc
+++ b/deps/v8/src/mips64/simulator-mips64.cc
@@ -146,7 +146,7 @@ void MipsDebugger::Stop(Instruction* instr) {
#else // GENERATED_CODE_COVERAGE
-#define UNSUPPORTED() printf("Unsupported instruction.\n");
+#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
static void InitializeCoverage() {}
@@ -519,7 +519,7 @@ void MipsDebugger::Debug() {
reinterpret_cast<intptr_t>(cur), *cur, *cur);
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
int64_t value = *cur;
- Heap* current_heap = v8::internal::Isolate::Current()->heap();
+ Heap* current_heap = sim_->isolate_->heap();
if (((value & 1) == 0) || current_heap->Contains(obj)) {
PrintF(" (");
if ((value & 1) == 0) {
@@ -898,7 +898,12 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
for (int i = 0; i < kNumFPURegisters; i++) {
FPUregisters_[i] = 0;
}
- FCSR_ = 0;
+
+ if (kArchVariant == kMips64r6) {
+ FCSR_ = kFCSRNaN2008FlagMask;
+ } else {
+ FCSR_ = 0;
+ }
// The sp is initialized to point to the bottom (high address) of the
// allocated stack area. To be safe in potential stack underflows we leave
@@ -926,12 +931,12 @@ Simulator::~Simulator() { free(stack_); }
// offset from the swi instruction so the simulator knows what to call.
class Redirection {
public:
- Redirection(void* external_function, ExternalReference::Type type)
+ Redirection(Isolate* isolate, void* external_function,
+ ExternalReference::Type type)
: external_function_(external_function),
swi_instruction_(rtCallRedirInstr),
type_(type),
next_(NULL) {
- Isolate* isolate = Isolate::Current();
next_ = isolate->simulator_redirection();
Simulator::current(isolate)->
FlushICache(isolate->simulator_i_cache(),
@@ -947,14 +952,13 @@ class Redirection {
void* external_function() { return external_function_; }
ExternalReference::Type type() { return type_; }
- static Redirection* Get(void* external_function,
+ static Redirection* Get(Isolate* isolate, void* external_function,
ExternalReference::Type type) {
- Isolate* isolate = Isolate::Current();
Redirection* current = isolate->simulator_redirection();
for (; current != NULL; current = current->next_) {
if (current->external_function_ == external_function) return current;
}
- return new Redirection(external_function, type);
+ return new Redirection(isolate, external_function, type);
}
static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
@@ -999,9 +1003,10 @@ void Simulator::TearDown(HashMap* i_cache, Redirection* first) {
}
-void* Simulator::RedirectExternalReference(void* external_function,
+void* Simulator::RedirectExternalReference(Isolate* isolate,
+ void* external_function,
ExternalReference::Type type) {
- Redirection* redirection = Redirection::Get(external_function, type);
+ Redirection* redirection = Redirection::Get(isolate, external_function, type);
return redirection->address_of_swi_instruction();
}
@@ -1256,6 +1261,8 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round64_error(double original, double rounded) {
bool ret = false;
+ // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
+ // loading the most accurate representation into max_int64, which is 2^63.
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
@@ -1273,7 +1280,7 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
ret = true;
}
- if (rounded > max_int64 || rounded < min_int64) {
+ if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true);
// The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
@@ -1315,11 +1322,135 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) {
return ret;
}
+void Simulator::set_fpu_register_word_invalid_result(float original,
+ float rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ double max_int32 = std::numeric_limits<int32_t>::max();
+ double min_int32 = std::numeric_limits<int32_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register_word(fd_reg(), 0);
+ } else if (rounded > max_int32) {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ } else if (rounded < min_int32) {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ }
+}
+
+
+void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ double max_int32 = std::numeric_limits<int32_t>::max();
+ double min_int32 = std::numeric_limits<int32_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register(fd_reg(), 0);
+ } else if (rounded > max_int32) {
+ set_fpu_register(fd_reg(), kFPUInvalidResult);
+ } else if (rounded < min_int32) {
+ set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register(fd_reg(), kFPUInvalidResult);
+ }
+}
+
+
+void Simulator::set_fpu_register_invalid_result64(float original,
+ float rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
+ // loading the most accurate representation into max_int64, which is 2^63.
+ double max_int64 = std::numeric_limits<int64_t>::max();
+ double min_int64 = std::numeric_limits<int64_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register(fd_reg(), 0);
+ } else if (rounded >= max_int64) {
+ set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ } else if (rounded < min_int64) {
+ set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ }
+}
+
+
+void Simulator::set_fpu_register_word_invalid_result(double original,
+ double rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ double max_int32 = std::numeric_limits<int32_t>::max();
+ double min_int32 = std::numeric_limits<int32_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register_word(fd_reg(), 0);
+ } else if (rounded > max_int32) {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ } else if (rounded < min_int32) {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ }
+}
+
+
+void Simulator::set_fpu_register_invalid_result(double original,
+ double rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ double max_int32 = std::numeric_limits<int32_t>::max();
+ double min_int32 = std::numeric_limits<int32_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register(fd_reg(), 0);
+ } else if (rounded > max_int32) {
+ set_fpu_register(fd_reg(), kFPUInvalidResult);
+ } else if (rounded < min_int32) {
+ set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register(fd_reg(), kFPUInvalidResult);
+ }
+}
+
+
+void Simulator::set_fpu_register_invalid_result64(double original,
+ double rounded) {
+ if (FCSR_ & kFCSRNaN2008FlagMask) {
+ // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
+ // loading the most accurate representation into max_int64, which is 2^63.
+ double max_int64 = std::numeric_limits<int64_t>::max();
+ double min_int64 = std::numeric_limits<int64_t>::min();
+ if (std::isnan(original)) {
+ set_fpu_register(fd_reg(), 0);
+ } else if (rounded >= max_int64) {
+ set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ } else if (rounded < min_int64) {
+ set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ }
+}
+
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round64_error(float original, float rounded) {
bool ret = false;
+ // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
+ // loading the most accurate representation into max_int64, which is 2^63.
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
@@ -1337,7 +1468,7 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) {
ret = true;
}
- if (rounded > max_int64 || rounded < min_int64) {
+ if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true);
// The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
@@ -2259,10 +2390,12 @@ void Simulator::DecodeTypeRegisterSRsType() {
set_fpu_register_float(fd_reg(), -fs);
break;
case SQRT_S:
- set_fpu_register_float(fd_reg(), fast_sqrt(fs));
+ lazily_initialize_fast_sqrt(isolate_);
+ set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
break;
case RSQRT_S: {
- float result = 1.0 / fast_sqrt(fs);
+ lazily_initialize_fast_sqrt(isolate_);
+ float result = 1.0 / fast_sqrt(fs, isolate_);
set_fpu_register_float(fd_reg(), result);
break;
}
@@ -2369,7 +2502,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2379,7 +2512,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
@@ -2388,7 +2521,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case TRUNC_L_S: { // Mips64r2 instruction.
@@ -2396,7 +2529,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2410,7 +2543,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
@@ -2425,7 +2558,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t i64 = static_cast<int64_t>(result);
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2434,7 +2567,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2444,7 +2577,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case CEIL_W_S: // Round double to word towards positive infinity.
@@ -2453,7 +2586,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CEIL_L_S: { // Mips64r2 instruction.
@@ -2461,7 +2594,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2764,10 +2897,12 @@ void Simulator::DecodeTypeRegisterDRsType() {
set_fpu_register_double(fd_reg(), -fs);
break;
case SQRT_D:
- set_fpu_register_double(fd_reg(), fast_sqrt(fs));
+ lazily_initialize_fast_sqrt(isolate_);
+ set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
break;
case RSQRT_D: {
- double result = 1.0 / fast_sqrt(fs);
+ lazily_initialize_fast_sqrt(isolate_);
+ double result = 1.0 / fast_sqrt(fs, isolate_);
set_fpu_register_double(fd_reg(), result);
break;
}
@@ -2803,7 +2938,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register_word(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
@@ -2818,7 +2953,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_invalid_result(fs, rounded);
}
} break;
case TRUNC_W_D: // Truncate double to word (round towards 0).
@@ -2827,7 +2962,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_invalid_result(fs, rounded);
}
} break;
case FLOOR_W_D: // Round double to word towards negative infinity.
@@ -2836,7 +2971,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CEIL_W_D: // Round double to word towards positive infinity.
@@ -2845,7 +2980,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPUInvalidResult);
+ set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CVT_S_D: // Convert double to float (single).
@@ -2857,7 +2992,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2872,7 +3007,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t i64 = static_cast<int64_t>(result);
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2881,7 +3016,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2890,7 +3025,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -2899,7 +3034,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
- set_fpu_register(fd_reg(), kFPU64InvalidResult);
+ set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
@@ -3184,11 +3319,18 @@ void Simulator::DecodeTypeRegisterCOP1() {
case MFHC1:
set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
break;
- case CTC1:
+ case CTC1: {
// At the moment only FCSR is supported.
DCHECK(fs_reg() == kFCSRRegister);
- FCSR_ = static_cast<uint32_t>(rt());
+ uint32_t reg = static_cast<uint32_t>(rt());
+ if (kArchVariant == kMips64r6) {
+ FCSR_ = reg | kFCSRNaN2008FlagMask;
+ } else {
+ DCHECK(kArchVariant == kMips64r2);
+ FCSR_ = reg & ~kFCSRNaN2008FlagMask;
+ }
break;
+ }
case MTC1:
// Hardware writes upper 32-bits to zero on mtc1.
set_fpu_register_hi_word(fs_reg(), 0);
@@ -3352,6 +3494,20 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
case DSRAV:
SetResult(rd_reg(), rt() >> rs());
break;
+ case LSA: {
+ DCHECK(kArchVariant == kMips64r6);
+ int8_t sa = lsa_sa() + 1;
+ int32_t _rt = static_cast<int32_t>(rt());
+ int32_t _rs = static_cast<int32_t>(rs());
+ int32_t res = _rs << sa;
+ res += _rt;
+ SetResult(rd_reg(), static_cast<int64_t>(res));
+ break;
+ }
+ case DLSA:
+ DCHECK(kArchVariant == kMips64r6);
+ SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
+ break;
case MFHI: // MFHI == CLZ on R6.
if (kArchVariant != kMips64r6) {
DCHECK(sa() == 0);
@@ -3692,7 +3848,19 @@ void Simulator::DecodeTypeRegisterSPECIAL2() {
void Simulator::DecodeTypeRegisterSPECIAL3() {
int64_t alu_out;
switch (get_instr()->FunctionFieldRaw()) {
- case INS: { // Mips32r2 instruction.
+ case INS: { // Mips64r2 instruction.
+ // Interpret rd field as 5-bit msb of insert.
+ uint16_t msb = rd_reg();
+ // Interpret sa field as 5-bit lsb of insert.
+ uint16_t lsb = sa();
+ uint16_t size = msb - lsb + 1;
+ uint64_t mask = (1ULL << size) - 1;
+ alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) |
+ ((rs_u() & mask) << lsb));
+ SetResult(rt_reg(), alu_out);
+ break;
+ }
+ case DINS: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of insert.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of insert.
@@ -3703,7 +3871,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out);
break;
}
- case EXT: { // Mips32r2 instruction.
+ case EXT: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract.
@@ -3714,11 +3882,33 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out);
break;
}
- case DEXT: { // Mips32r2 instruction.
+ case DEXT: { // Mips64r2 instruction.
+ // Interpret rd field as 5-bit msb of extract.
+ uint16_t msb = rd_reg();
+ // Interpret sa field as 5-bit lsb of extract.
+ uint16_t lsb = sa();
+ uint16_t size = msb + 1;
+ uint64_t mask = (1ULL << size) - 1;
+ alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
+ SetResult(rt_reg(), alu_out);
+ break;
+ }
+ case DEXTM: {
// Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract.
uint16_t lsb = sa();
+ uint16_t size = msb + 33;
+ uint64_t mask = (1ULL << size) - 1;
+ alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
+ SetResult(rt_reg(), alu_out);
+ break;
+ }
+ case DEXTU: {
+ // Interpret rd field as 5-bit msb of extract.
+ uint16_t msb = rd_reg();
+ // Interpret sa field as 5-bit lsb of extract.
+ uint16_t lsb = sa() + 32;
uint16_t size = msb + 1;
uint64_t mask = (1ULL << size) - 1;
alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
@@ -3905,27 +4095,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
}
-// Branch instructions common part.
-#define BranchAndLinkHelper(do_branch) \
- execute_branch_delay_instruction = true; \
- if (do_branch) { \
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \
- set_register(31, current_pc + kBranchReturnOffset); \
- } else { \
- next_pc = current_pc + kBranchReturnOffset; \
- }
-
-
-#define BranchHelper(do_branch) \
- execute_branch_delay_instruction = true; \
- if (do_branch) { \
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \
- } else { \
- next_pc = current_pc + kBranchReturnOffset; \
- }
-
-
-// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
+// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
@@ -3936,21 +4106,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
int64_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
int32_t imm18 = instr->Imm18Value();
- int32_t imm21 = instr->Imm21Value();
- int32_t imm26 = instr->Imm26Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
- int64_t ft = get_fpu_register(ft_reg);
// Zero extended immediate.
uint64_t oe_imm16 = 0xffff & imm16;
// Sign extended immediate.
int64_t se_imm16 = imm16;
int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
- int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0);
- // Get current pc.
- int64_t current_pc = get_pc();
// Next pc.
int64_t next_pc = bad_ra;
@@ -3965,7 +4129,57 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Alignment for 32-bit integers used in LWL, LWR, etc.
const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
- // ---------- Configuration (and execution for REGIMM).
+ // 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 BranchHelper = [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;
+ } else {
+ next_pc = current_pc + 2 * Instruction::kInstrSize;
+ }
+ };
+
+ auto BranchAndLinkCompactHelper = [this, instr, &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);
+ imm <<= 32 - bits;
+ imm >>= 32 - bits;
+ next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
+ set_register(31, current_pc + Instruction::kInstrSize);
+ }
+ };
+
+ auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
+ int64_t current_pc = get_pc();
+ CheckForbiddenSlot(current_pc);
+ if (do_branch) {
+ int32_t imm = instr->ImmValue(bits);
+ imm <<= 32 - bits;
+ imm >>= 32 - bits;
+ next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
+ }
+ };
+
switch (op) {
// ------------- COP1. Coprocessor instructions.
case COP1:
@@ -3975,32 +4189,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
uint32_t cc_value = test_fcsr_bit(fcsr_cc);
bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
- execute_branch_delay_instruction = true;
- // Set next_pc.
- if (do_branch) {
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
- } else {
- next_pc = current_pc + kBranchReturnOffset;
- }
+ BranchHelper(do_branch);
break;
}
case BC1EQZ:
- execute_branch_delay_instruction = true;
- // Set next_pc.
- if (!(ft & 0x1)) {
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
- } else {
- next_pc = current_pc + kBranchReturnOffset;
- }
+ BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
break;
case BC1NEZ:
- execute_branch_delay_instruction = true;
- // Set next_pc.
- if (ft & 0x1) {
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
- } else {
- next_pc = current_pc + kBranchReturnOffset;
- }
+ BranchHelper(get_fpu_register(ft_reg) & 0x1);
break;
default:
UNREACHABLE();
@@ -4021,6 +4217,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case BGEZAL:
BranchAndLinkHelper(rs >= 0);
break;
+ case DAHI:
+ SetResult(rs_reg, rs + (se_imm16 << 32));
+ break;
+ case DATI:
+ SetResult(rs_reg, rs + (se_imm16 << 48));
+ break;
default:
UNREACHABLE();
}
@@ -4034,55 +4236,156 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case BNE:
BranchHelper(rs != rt);
break;
- case BLEZ:
- BranchHelper(rs <= 0);
- break;
- case BGTZ:
- BranchHelper(rs > 0);
- break;
- case POP66: {
- if (rs_reg) { // BEQZC
- int32_t se_imm21 =
- static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits));
- se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits);
- if (rs == 0)
- next_pc = current_pc + 4 + (se_imm21 << 2);
- else
- next_pc = current_pc + 4;
+ case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rt_reg != 0) {
+ if (rs_reg == 0) { // BLEZALC
+ BranchAndLinkCompactHelper(rt <= 0, 16);
+ } else {
+ if (rs_reg == rt_reg) { // BGEZALC
+ BranchAndLinkCompactHelper(rt >= 0, 16);
+ } else { // BGEUC
+ BranchCompactHelper(
+ static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16);
+ }
+ }
+ } else { // BLEZ
+ BranchHelper(rs <= 0);
+ }
+ } else { // BLEZ
+ BranchHelper(rs <= 0);
+ }
+ break;
+ case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rt_reg != 0) {
+ if (rs_reg == 0) { // BGTZALC
+ BranchAndLinkCompactHelper(rt > 0, 16);
+ } else {
+ if (rt_reg == rs_reg) { // BLTZALC
+ BranchAndLinkCompactHelper(rt < 0, 16);
+ } else { // BLTUC
+ BranchCompactHelper(
+ static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16);
+ }
+ }
+ } else { // BGTZ
+ BranchHelper(rs > 0);
+ }
+ } else { // BGTZ
+ BranchHelper(rs > 0);
+ }
+ break;
+ case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rt_reg != 0) {
+ if (rs_reg == 0) { // BLEZC
+ BranchCompactHelper(rt <= 0, 16);
+ } else {
+ if (rs_reg == rt_reg) { // BGEZC
+ BranchCompactHelper(rt >= 0, 16);
+ } else { // BGEC/BLEC
+ BranchCompactHelper(rs >= rt, 16);
+ }
+ }
+ }
+ } else { // BLEZL
+ BranchAndLinkHelper(rs <= 0);
+ }
+ break;
+ case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rt_reg != 0) {
+ if (rs_reg == 0) { // BGTZC
+ BranchCompactHelper(rt > 0, 16);
+ } else {
+ if (rs_reg == rt_reg) { // BLTZC
+ BranchCompactHelper(rt < 0, 16);
+ } else { // BLTC/BGTC
+ BranchCompactHelper(rs < rt, 16);
+ }
+ }
+ }
+ } else { // BGTZL
+ BranchAndLinkHelper(rs > 0);
+ }
+ break;
+ case POP66: // BEQZC, JIC
+ if (rs_reg != 0) { // BEQZC
+ BranchCompactHelper(rs == 0, 21);
} else { // JIC
next_pc = rt + imm16;
}
break;
- }
- case BC: {
- next_pc = current_pc + 4 + (se_imm26 << 2);
- set_pc(next_pc);
- pc_modified_ = true;
+ case POP76: // BNEZC, JIALC
+ if (rs_reg != 0) { // BNEZC
+ BranchCompactHelper(rs != 0, 21);
+ } else { // JIALC
+ int64_t current_pc = get_pc();
+ set_register(31, current_pc + Instruction::kInstrSize);
+ next_pc = rt + imm16;
+ }
break;
- }
- case BALC: {
- set_register(31, current_pc + 4);
- next_pc = current_pc + 4 + (se_imm26 << 2);
- set_pc(next_pc);
- pc_modified_ = true;
+ case BC:
+ BranchCompactHelper(true, 26);
break;
- }
- // ------------- Arithmetic instructions.
- case ADDI:
- case DADDI:
- if (HaveSameSign(rs, se_imm16)) {
- if (rs > 0) {
- if (rs > Registers::kMaxValue - se_imm16) {
- SignalException(kIntegerOverflow);
+ case BALC:
+ BranchAndLinkCompactHelper(true, 26);
+ break;
+ case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rs_reg >= rt_reg) { // BOVC
+ if (HaveSameSign(rs, rt)) {
+ if (rs > 0) {
+ BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
+ } else if (rs < 0) {
+ BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
+ }
}
- } else if (rs < 0) {
- if (rs < Registers::kMinValue - se_imm16) {
- SignalException(kIntegerUnderflow);
+ } else {
+ if (rs_reg == 0) { // BEQZALC
+ BranchAndLinkCompactHelper(rt == 0, 16);
+ } else { // BEQC
+ BranchCompactHelper(rt == rs, 16);
}
}
+ } else { // ADDI
+ if (HaveSameSign(rs, se_imm16)) {
+ if (rs > 0) {
+ if (rs <= Registers::kMaxValue - se_imm16) {
+ SignalException(kIntegerOverflow);
+ }
+ } else if (rs < 0) {
+ if (rs >= Registers::kMinValue - se_imm16) {
+ SignalException(kIntegerUnderflow);
+ }
+ }
+ }
+ SetResult(rt_reg, rs + se_imm16);
}
- SetResult(rt_reg, rs + se_imm16);
break;
+ case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
+ if (kArchVariant == kMips64r6) {
+ if (rs_reg >= rt_reg) { // BNVC
+ if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
+ BranchCompactHelper(true, 16);
+ } else {
+ if (rs > 0) {
+ BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
+ } else if (rs < 0) {
+ BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
+ }
+ }
+ } else {
+ if (rs_reg == 0) { // BNEZALC
+ BranchAndLinkCompactHelper(rt != 0, 16);
+ } else { // BNEC
+ BranchCompactHelper(rt != rs, 16);
+ }
+ }
+ }
+ break;
+ // ------------- Arithmetic instructions.
case ADDIU: {
int32_t alu32_out = static_cast<int32_t>(rs + se_imm16);
// Sign-extend result of 32bit operation into 64bit register.
@@ -4107,12 +4410,24 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case XORI:
SetResult(rt_reg, rs ^ oe_imm16);
break;
- case LUI: {
- int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
- // Sign-extend result of 32bit operation into 64bit register.
- SetResult(rt_reg, static_cast<int64_t>(alu32_out));
+ case LUI:
+ if (rs_reg != 0) {
+ // AUI instruction.
+ DCHECK(kArchVariant == kMips64r6);
+ int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16));
+ SetResult(rt_reg, static_cast<int64_t>(alu32_out));
+ } else {
+ // LUI instruction.
+ int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
+ // Sign-extend result of 32bit operation into 64bit register.
+ SetResult(rt_reg, static_cast<int64_t>(alu32_out));
+ }
+ break;
+ case DAUI:
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs_reg != 0);
+ SetResult(rt_reg, rs + (se_imm16 << 16));
break;
- }
// ------------- Memory instructions.
case LB:
set_register(rt_reg, ReadB(rs + se_imm16));
@@ -4205,22 +4520,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case SDC1:
WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
break;
- // ------------- JIALC and BNEZC instructions.
- case POP76: {
- // Next pc.
- next_pc = rt + se_imm16;
- // The instruction after the jump is NOT executed.
- uint16_t pc_increment = Instruction::kInstrSize;
- if (instr->IsLinkingInstruction()) {
- set_register(31, current_pc + pc_increment);
- }
- set_pc(next_pc);
- pc_modified_ = true;
- break;
- }
// ------------- PC-Relative instructions.
case PCREL: {
// rt field: checking 5-bits.
+ int32_t imm21 = instr->Imm21Value();
+ int64_t current_pc = get_pc();
uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) {
case ALUIPC:
@@ -4290,7 +4594,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// We don't check for end_sim_pc. First it should not be met as the current
// pc is valid. Secondly a jump should always execute its branch delay slot.
Instruction* branch_delay_instr =
- reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
+ reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
BranchDelayInstructionDecode(branch_delay_instr);
}
@@ -4300,9 +4604,6 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
}
}
-#undef BranchHelper
-#undef BranchAndLinkHelper
-
// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
void Simulator::DecodeTypeJump(Instruction* instr) {
@@ -4393,7 +4694,7 @@ void Simulator::Execute() {
while (program_counter != end_sim_pc) {
Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
icount_++;
- if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) {
+ if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
MipsDebugger dbg(this);
dbg.Debug();
} else {