Index: src/arm/simulator-arm.cc |
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc |
index 8f7c1e8bb2b740e7884c6ae52c6b867681c9e125..1f64d2bfa9f7e33eadd6940dce456e8bb9b40817 100644 |
--- a/src/arm/simulator-arm.cc |
+++ b/src/arm/simulator-arm.cc |
@@ -2885,6 +2885,7 @@ void Simulator::DecodeType7(Instruction* instr) { |
// vcvt: Dd = Sm |
// vcvt: Sd = Dm |
// vcvt.f64.s32 Dd, Dd, #<fbits> |
+// vcvt.u32.f64 Dd, Dd, #<fbits> |
// Dd = vabs(Dm) |
// Dd = vneg(Dm) |
// Dd = vadd(Dn, Dm) |
@@ -2933,13 +2934,10 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { |
DecodeVCVTBetweenDoubleAndSingle(instr); |
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) { |
DecodeVCVTBetweenFloatingPointAndInteger(instr); |
- } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) && |
- (instr->Bit(8) == 1)) { |
- // vcvt.f64.s32 Dd, Dd, #<fbits> |
- int fraction_bits = 32 - ((instr->Bit(5) << 4) | instr->Bits(3, 0)); |
- int fixed_value = get_sinteger_from_s_register(vd * 2); |
- double divide = 1 << fraction_bits; |
- set_d_register_from_double(vd, fixed_value / divide); |
+ } else if ((instr->Opc2Value() & 0x2) && (instr->Opc2Value() & 0x8) && |
+ (instr->Opc3Value() == 0x3) && |
+ (instr->Bit(5) || instr->Bits(3, 0))) { |
+ DecodeVCVTBetweenFloatingPointAndFixedPoint(instr); |
} else if (((instr->Opc2Value() >> 1) == 0x6) && |
(instr->Opc3Value() & 0x1)) { |
DecodeVCVTBetweenFloatingPointAndInteger(instr); |
@@ -3348,6 +3346,78 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) { |
} |
+void Simulator::DecodeVCVTBetweenFloatingPointAndFixedPoint( |
+ Instruction* instr) { |
+ ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); |
+ ASSERT((instr->Opc2Value() & 0x2) && (instr->Opc2Value() & 0x8)); |
+ ASSERT(instr->Opc3Value() == 0x3); |
+ ASSERT(instr->Bit(5) || instr->Bits(3, 0)); |
+ |
+ bool to_integer = (instr->Bit(18) == 1); |
+ bool unsigned_integer = (instr->Bit(16) == 1); |
+ |
+ VFPRegPrecision f_precision = (instr->SzValue() == 1) ? kDoublePrecision |
+ : kSinglePrecision; |
+ int fd = instr->VFPDRegValue(f_precision); |
+ int sd = instr->VFPDRegValue(kSinglePrecision); |
+ |
+ int sx = instr->Bit(7); |
+ int fraction_bits = (sx ? 32 : 16) - |
+ ((instr->Bits(3, 0) << 1) | instr->Bit(5)); |
+ double mult = 1 << fraction_bits; |
+ |
+ if (to_integer) { |
+ bool double_precision = (f_precision == kDoublePrecision); |
+ double val = double_precision ? get_double_from_d_register(fd) |
+ : get_float_from_s_register(fd); |
+ |
+ // First check if the value overflows the integer range without |
+ // multiplication. |
+ inv_op_vfp_flag_ = get_inv_op_vfp_flag(RZ, val, unsigned_integer); |
+ |
+ if (!inv_op_vfp_flag_) { |
+ // The original value did not overflow the integer range, so we can |
+ // safely multiply it without fear of double overflow. |
+ val *= mult; |
+ // ARM specifies rounding towards zero for float to fixed conversion. |
+ inv_op_vfp_flag_ = get_inv_op_vfp_flag(RZ, val, unsigned_integer); |
+ } |
+ |
+ int temp = unsigned_integer ? static_cast<uint32_t>(val) |
+ : static_cast<int32_t>(val); |
+ if (inv_op_vfp_flag_) { |
+ temp = VFPConversionSaturate(val, unsigned_integer); |
+ } |
+ |
+ // FIXME: inexact_vfp_flag_ does not model ARM behavior exactly if |
+ // inv_op_vfp_flag_ is set. |
+ double abs_diff = |
+ unsigned_integer ? std::fabs(val - static_cast<uint32_t>(temp)) |
+ : std::fabs(val - temp); |
+ inexact_vfp_flag_ = (abs_diff != 0); |
+ |
+ set_s_register_from_sinteger(sd, temp); |
+ |
+ } else { |
+ int val = get_sinteger_from_s_register(sd); |
+ if (f_precision == kDoublePrecision) { |
+ if (unsigned_integer) { |
+ set_d_register_from_double(fd, static_cast<uint32_t>(val) / mult); |
+ } else { |
+ set_d_register_from_double(fd, val / mult); |
+ } |
+ } else { |
+ if (unsigned_integer) { |
+ set_s_register_from_float( |
+ fd, static_cast<float>(static_cast<uint32_t>(val) / mult)); |
+ } else { |
+ set_s_register_from_float(fd, static_cast<float>(val / mult)); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
// void Simulator::DecodeType6CoprocessorIns(Instruction* instr) |
// Decode Type 6 coprocessor instructions. |
// Dm = vmov(Rt, Rt2) |