Index: src/arm/simulator-arm.cc |
=================================================================== |
--- src/arm/simulator-arm.cc (revision 3208) |
+++ src/arm/simulator-arm.cc (working copy) |
@@ -342,6 +342,11 @@ |
PrintF("Z flag: %d; ", sim_->z_flag_); |
PrintF("C flag: %d; ", sim_->c_flag_); |
PrintF("V flag: %d\n", sim_->v_flag_); |
+ PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_); |
+ PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_); |
+ PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_); |
+ PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_); |
+ PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_); |
} else if (strcmp(cmd, "unstop") == 0) { |
intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
@@ -429,6 +434,24 @@ |
c_flag_ = false; |
v_flag_ = false; |
+ // Initializing VFP registers. |
+ // All registers are initialized to zero to start with. |
+ // even though s_registers_ & d_registers_ share the same |
+ // physical registers in the target |
+ for (int i = 0; i < num_s_registers; i++) { |
+ vfp_register[i] = 0; |
+ } |
+ n_flag_FPSCR_ = false; |
+ z_flag_FPSCR_ = false; |
+ c_flag_FPSCR_ = false; |
+ v_flag_FPSCR_ = false; |
+ |
+ inv_op_vfp_flag_ = false; |
+ div_zero_vfp_flag_ = false; |
+ overflow_vfp_flag_ = false; |
+ underflow_vfp_flag_ = false; |
+ inexact_vfp_flag_ = false; |
+ |
// 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 |
// some buffer below. |
@@ -544,7 +567,92 @@ |
return registers_[pc]; |
} |
+// Getting from and setting into VFP registers. |
+void Simulator::set_s_register(int sreg, unsigned int value) { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ vfp_register[sreg] = value; |
+} |
+unsigned int Simulator::get_s_register(int sreg) const { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ return vfp_register[sreg]; |
+} |
+ |
+void Simulator::set_s_register_from_float(int sreg, const float flt) { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ // Read the bits from the single precision floating point value |
+ // into the unsigned integer element of vfp_register[] given by index=sreg. |
+ char buffer[sizeof(vfp_register[0])]; |
+ memcpy(buffer, &flt, sizeof(vfp_register[0])); |
+ memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0])); |
+} |
+ |
+void Simulator::set_s_register_from_sinteger(int sreg, const int sint) { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ // Read the bits from the integer value |
+ // into the unsigned integer element of vfp_register[] given by index=sreg. |
+ char buffer[sizeof(vfp_register[0])]; |
+ memcpy(buffer, &sint, sizeof(vfp_register[0])); |
+ memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0])); |
+} |
+ |
+void Simulator::set_d_register_from_double(int dreg, const double& dbl) { |
+ ASSERT((dreg >= 0) && (dreg < num_d_registers)); |
+ // Read the bits from the double precision floating point value |
+ // into the two consecutive unsigned integer elements of vfp_register[] |
+ // given by index 2*sreg and 2*sreg+1. |
+ char buffer[2 * sizeof(vfp_register[0])]; |
+ memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0])); |
+#ifndef BIG_ENDIAN_FLOATING_POINT |
+ memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0])); |
+#else |
+ memcpy(&vfp_register[dreg * 2], &buffer[4], sizeof(vfp_register[0])); |
+ memcpy(&vfp_register[dreg * 2 + 1], &buffer[0], sizeof(vfp_register[0])); |
+#endif |
+} |
+ |
+float Simulator::get_float_from_s_register(int sreg) { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ |
+ float sm_val = 0.0; |
+ // Read the bits from the unsigned integer vfp_register[] array |
+ // into the single precision floating point value and return it. |
+ char buffer[sizeof(vfp_register[0])]; |
+ memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0])); |
+ memcpy(&sm_val, buffer, sizeof(vfp_register[0])); |
+ return(sm_val); |
+} |
+ |
+int Simulator::get_sinteger_from_s_register(int sreg) { |
+ ASSERT((sreg >= 0) && (sreg < num_s_registers)); |
+ |
+ int sm_val = 0; |
+ // Read the bits from the unsigned integer vfp_register[] array |
+ // into the single precision floating point value and return it. |
+ char buffer[sizeof(vfp_register[0])]; |
+ memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0])); |
+ memcpy(&sm_val, buffer, sizeof(vfp_register[0])); |
+ return(sm_val); |
+} |
+ |
+double Simulator::get_double_from_d_register(int dreg) { |
+ ASSERT((dreg >= 0) && (dreg < num_d_registers)); |
+ |
+ double dm_val = 0.0; |
+ // Read the bits from the unsigned integer vfp_register[] array |
+ // into the double precision floating point value and return it. |
+ char buffer[2 * sizeof(vfp_register[0])]; |
+#ifndef BIG_ENDIAN_FLOATING_POINT |
+ memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0])); |
+#else |
+ memcpy(&buffer[0], &vfp_register[2 * dreg + 1], sizeof(vfp_register[0])); |
+ memcpy(&buffer[4], &vfp_register[2 * dreg], sizeof(vfp_register[0])); |
+#endif |
+ memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0])); |
+ return(dm_val); |
+} |
+ |
+ |
// For use in calls that take two double values, constructed from r0, r1, r2 |
// and r3. |
void Simulator::GetFpArgs(double* x, double* y) { |
@@ -771,7 +879,38 @@ |
return overflow; |
} |
+// Support for VFP comparisons. |
+void Simulator::Compute_FPSCR_Flags(double val1, double val2) { |
+ // All Non-Nan cases |
+ if (val1 == val2) { |
+ n_flag_FPSCR_ = false; |
+ z_flag_FPSCR_ = true; |
+ c_flag_FPSCR_ = true; |
+ v_flag_FPSCR_ = false; |
+ } else if (val1 < val2) { |
+ n_flag_FPSCR_ = true; |
+ z_flag_FPSCR_ = false; |
+ c_flag_FPSCR_ = false; |
+ v_flag_FPSCR_ = false; |
+ } else { |
+ // Case when (val1 > val2). |
+ n_flag_FPSCR_ = false; |
+ z_flag_FPSCR_ = false; |
+ c_flag_FPSCR_ = true; |
+ v_flag_FPSCR_ = false; |
+ } |
+} |
+ |
+void Simulator::Copy_FPSCR_to_APSR() { |
+ n_flag_ = n_flag_FPSCR_; |
+ z_flag_ = z_flag_FPSCR_; |
+ c_flag_ = c_flag_FPSCR_; |
+ v_flag_ = v_flag_FPSCR_; |
+} |
+ |
+ |
+ |
// Addressing Mode 1 - Data-processing operands: |
// Get the value based on the shifter_operand with register. |
int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { |
@@ -1664,16 +1803,15 @@ |
void Simulator::DecodeType6(Instr* instr) { |
- UNIMPLEMENTED(); |
+ DecodeType6CoprocessorIns(instr); |
} |
void Simulator::DecodeType7(Instr* instr) { |
if (instr->Bit(24) == 1) { |
- // Format(instr, "swi 'swi"); |
SoftwareInterrupt(instr); |
} else { |
- UNIMPLEMENTED(); |
+ DecodeTypeVFP(instr); |
} |
} |
@@ -1745,6 +1883,178 @@ |
} |
+// void Simulator::DecodeTypeVFP(Instr* instr) |
+// The Following ARMv7 VFPv instructions are currently supported. |
+// fmsr :Sn = Rt |
+// fmrs :Rt = Sn |
+// fsitod: Dd = Sm |
+// ftosid: Sd = Dm |
+// Dd = faddd(Dn, Dm) |
+// Dd = fsubd(Dn, Dm) |
+// Dd = fmuld(Dn, Dm) |
+// Dd = fdivd(Dn, Dm) |
+// vcmp(Dd, Dm) |
+// VMRS |
+void Simulator::DecodeTypeVFP(Instr* instr) { |
+ ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); |
+ |
+ int rt = instr->RtField(); |
+ int vm = instr->VmField(); |
+ int vn = instr->VnField(); |
+ int vd = instr->VdField(); |
+ |
+ if (instr->Bit(23) == 1) { |
+ if ((instr->Bits(21, 19) == 0x7) && |
+ (instr->Bits(18, 16) == 0x5) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 1) && |
+ (instr->Bit(6) == 1) && |
+ (instr->Bit(4) == 0)) { |
+ double dm_val = get_double_from_d_register(vm); |
+ int32_t int_value = static_cast<int32_t>(dm_val); |
+ set_s_register_from_sinteger(((vd<<1) | instr->DField()), int_value); |
+ } else if ((instr->Bits(21, 19) == 0x7) && |
+ (instr->Bits(18, 16) == 0x0) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 1) && |
+ (instr->Bit(7) == 1) && |
+ (instr->Bit(6) == 1) && |
+ (instr->Bit(4) == 0)) { |
+ int32_t int_value = get_sinteger_from_s_register(((vm<<1) | |
+ instr->MField())); |
+ double dbl_value = static_cast<double>(int_value); |
+ set_d_register_from_double(vd, dbl_value); |
+ } else if ((instr->Bit(21) == 0x0) && |
+ (instr->Bit(20) == 0x0) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 1) && |
+ (instr->Bit(6) == 0) && |
+ (instr->Bit(4) == 0)) { |
+ double dn_value = get_double_from_d_register(vn); |
+ double dm_value = get_double_from_d_register(vm); |
+ double dd_value = dn_value / dm_value; |
+ set_d_register_from_double(vd, dd_value); |
+ } else if ((instr->Bits(21, 20) == 0x3) && |
+ (instr->Bits(19, 16) == 0x4) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 0x1) && |
+ (instr->Bit(6) == 0x1) && |
+ (instr->Bit(4) == 0x0)) { |
+ double dd_value = get_double_from_d_register(vd); |
+ double dm_value = get_double_from_d_register(vm); |
+ Compute_FPSCR_Flags(dd_value, dm_value); |
+ } else if ((instr->Bits(23, 20) == 0xF) && |
+ (instr->Bits(19, 16) == 0x1) && |
+ (instr->Bits(11, 8) == 0xA) && |
+ (instr->Bits(7, 5) == 0x0) && |
+ (instr->Bit(4) == 0x1) && |
+ (instr->Bits(3, 0) == 0x0)) { |
+ if (instr->Bits(15, 12) == 0xF) |
+ Copy_FPSCR_to_APSR(); |
+ else |
+ UNIMPLEMENTED(); // not used by V8 now |
+ } else { |
+ UNIMPLEMENTED(); // not used by V8 now |
+ } |
+ } else if (instr->Bit(21) == 1) { |
+ if ((instr->Bit(20) == 0x1) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 0x1) && |
+ (instr->Bit(6) == 0) && |
+ (instr->Bit(4) == 0)) { |
+ double dn_value = get_double_from_d_register(vn); |
+ double dm_value = get_double_from_d_register(vm); |
+ double dd_value = dn_value + dm_value; |
+ set_d_register_from_double(vd, dd_value); |
+ } else if ((instr->Bit(20) == 0x1) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 0x1) && |
+ (instr->Bit(6) == 1) && |
+ (instr->Bit(4) == 0)) { |
+ double dn_value = get_double_from_d_register(vn); |
+ double dm_value = get_double_from_d_register(vm); |
+ double dd_value = dn_value - dm_value; |
+ set_d_register_from_double(vd, dd_value); |
+ } else if ((instr->Bit(20) == 0x0) && |
+ (instr->Bits(11, 9) == 0x5) && |
+ (instr->Bit(8) == 0x1) && |
+ (instr->Bit(6) == 0) && |
+ (instr->Bit(4) == 0)) { |
+ double dn_value = get_double_from_d_register(vn); |
+ double dm_value = get_double_from_d_register(vm); |
+ double dd_value = dn_value * dm_value; |
+ set_d_register_from_double(vd, dd_value); |
+ } else { |
+ UNIMPLEMENTED(); // not used by V8 now |
+ } |
+ } else { |
+ if ((instr->Bit(20) == 0x0) && |
+ (instr->Bits(11, 8) == 0xA) && |
+ (instr->Bits(6, 5) == 0x0) && |
+ (instr->Bit(4) == 1) && |
+ (instr->Bits(3, 0) == 0x0)) { |
+ int32_t rs_val = get_register(rt); |
+ set_s_register_from_sinteger(((vn<<1) | instr->NField()), rs_val); |
+ } else if ((instr->Bit(20) == 0x1) && |
+ (instr->Bits(11, 8) == 0xA) && |
+ (instr->Bits(6, 5) == 0x0) && |
+ (instr->Bit(4) == 1) && |
+ (instr->Bits(3, 0) == 0x0)) { |
+ int32_t int_value = get_sinteger_from_s_register(((vn<<1) | |
+ instr->NField())); |
+ set_register(rt, int_value); |
+ } else { |
+ UNIMPLEMENTED(); // not used by V8 now |
+ } |
+ } |
+} |
+ |
+ |
+ |
+// void Simulator::DecodeType6CoprocessorIns(Instr* instr) |
+// Decode Type 6 coprocessor instructions |
+// Dm = fmdrr(Rt, Rt2) |
+// <Rt, Rt2> = fmrrd(Dm) |
+void Simulator::DecodeType6CoprocessorIns(Instr* instr) { |
+ ASSERT((instr->TypeField() == 6)); |
+ |
+ int rt = instr->RtField(); |
+ int rn = instr->RnField(); |
+ int vm = instr->VmField(); |
+ |
+ if (instr->Bit(23) == 1) { |
+ UNIMPLEMENTED(); |
+ } else if (instr->Bit(22) == 1) { |
+ if ((instr->Bits(27, 24) == 0xC) && |
+ (instr->Bit(22) == 1) && |
+ (instr->Bits(11, 8) == 0xB) && |
+ (instr->Bits(7, 6) == 0x0) && |
+ (instr->Bit(4) == 1)) { |
+ if (instr->Bit(20) == 0) { |
+ int32_t rs_val = get_register(rt); |
+ int32_t rn_val = get_register(rn); |
+ |
+ set_s_register_from_sinteger(2*vm, rs_val); |
+ set_s_register_from_sinteger((2*vm+1), rn_val); |
+ |
+ } else if (instr->Bit(20) == 1) { |
+ int32_t rt_int_value = get_sinteger_from_s_register(2*vm); |
+ int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1); |
+ |
+ set_register(rt, rt_int_value); |
+ set_register(rn, rn_int_value); |
+ } |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
+ } else if (instr->Bit(21) == 1) { |
+ UNIMPLEMENTED(); |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
+} |
+ |
+ |
// Executes the current instruction. |
void Simulator::InstructionDecode(Instr* instr) { |
pc_modified_ = false; |
@@ -1802,7 +2112,6 @@ |
} |
-// |
void Simulator::Execute() { |
// Get the PC to simulate. Cannot use the accessor here as we need the |
// raw PC value and not the one used as input to arithmetic instructions. |