Index: src/arm/simulator-arm.cc |
=================================================================== |
--- src/arm/simulator-arm.cc (revision 4136) |
+++ src/arm/simulator-arm.cc (working copy) |
@@ -72,6 +72,8 @@ |
int32_t GetRegisterValue(int regnum); |
bool GetValue(const char* desc, int32_t* value); |
+ bool GetVFPSingleValue(const char* desc, float* value); |
+ bool GetVFPDoubleValue(const char* desc, double* value); |
// Set or delete a breakpoint. Returns true if successful. |
bool SetBreakpoint(Instr* breakpc); |
@@ -154,6 +156,28 @@ |
} |
+bool Debugger::GetVFPSingleValue(const char* desc, float* value) { |
+ bool is_double; |
+ int regnum = VFPRegisters::Number(desc, &is_double); |
+ if (regnum != kNoRegister && !is_double) { |
+ *value = sim_->get_float_from_s_register(regnum); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
+bool Debugger::GetVFPDoubleValue(const char* desc, double* value) { |
+ bool is_double; |
+ int regnum = VFPRegisters::Number(desc, &is_double); |
+ if (regnum != kNoRegister && is_double) { |
+ *value = sim_->get_double_from_d_register(regnum); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
bool Debugger::SetBreakpoint(Instr* breakpc) { |
// Check if a breakpoint can be set. If not return without any side-effects. |
if (sim_->break_pc_ != NULL) { |
@@ -249,6 +273,8 @@ |
} else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
if (args == 2) { |
int32_t value; |
+ float svalue; |
+ double dvalue; |
if (strcmp(arg1, "all") == 0) { |
for (int i = 0; i < kNumRegisters; i++) { |
value = GetRegisterValue(i); |
@@ -257,6 +283,10 @@ |
} else { |
if (GetValue(arg1, &value)) { |
PrintF("%s: 0x%08x %d \n", arg1, value, value); |
+ } else if (GetVFPSingleValue(arg1, &svalue)) { |
+ PrintF("%s: %f \n", arg1, svalue); |
+ } else if (GetVFPDoubleValue(arg1, &dvalue)) { |
+ PrintF("%s: %lf \n", arg1, dvalue); |
} else { |
PrintF("%s unrecognized\n", arg1); |
} |
@@ -1919,6 +1949,13 @@ |
} |
+// Depending on value of last_bit flag glue register code from vm and m values |
+// (where m is expected to be a single bit). |
+static int GlueRegCode(bool last_bit, int vm, int m) { |
+ return last_bit ? ((vm << 1) | m) : ((m << 4) | vm); |
+} |
+ |
+ |
// void Simulator::DecodeTypeVFP(Instr* instr) |
// The Following ARMv7 VFPv instructions are currently supported. |
// vmov :Sn = Rt |
@@ -1933,114 +1970,212 @@ |
// VMRS |
void Simulator::DecodeTypeVFP(Instr* instr) { |
ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); |
+ ASSERT(instr->Bits(11, 9) == 0x5); |
- int rt = instr->RtField(); |
int vm = instr->VmField(); |
+ int vd = instr->VdField(); |
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)) { |
+ if (instr->Bit(4) == 0) { |
+ if (instr->Opc1Field() == 0x7) { |
+ // Other data processing instructions |
+ if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) { |
+ DecodeVCVTBetweenDoubleAndSingle(instr); |
+ } else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) { |
+ DecodeVCVTBetweenFloatingPointAndInteger(instr); |
+ } else if (((instr->Opc2Field() >> 1) == 0x6) && |
+ (instr->Opc3Field() & 0x1)) { |
+ DecodeVCVTBetweenFloatingPointAndInteger(instr); |
+ } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && |
+ (instr->Opc3Field() & 0x1)) { |
+ DecodeVCMP(instr); |
+ } else { |
+ UNREACHABLE(); // Not used by V8. |
+ } |
+ } else if (instr->Opc1Field() == 0x3) { |
+ if (instr->SzField() != 0x1) { |
+ UNREACHABLE(); // Not used by V8. |
+ } |
+ |
+ if (instr->Opc3Field() & 0x1) { |
+ // vsub |
+ 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 { |
+ // vadd |
+ 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->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) { |
+ // vmul |
+ if (instr->SzField() != 0x1) { |
+ UNREACHABLE(); // Not used by V8. |
+ } |
+ |
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->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) { |
+ // vdiv |
+ if (instr->SzField() != 0x1) { |
+ UNREACHABLE(); // Not used by V8. |
+ } |
+ |
+ 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) |
+ } else { |
+ UNIMPLEMENTED(); // Not used by V8. |
+ } |
+ } else { |
+ if ((instr->VCField() == 0x0) && |
+ (instr->VAField() == 0x0)) { |
+ DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr); |
+ } else if ((instr->VLField() == 0x1) && |
+ (instr->VCField() == 0x0) && |
+ (instr->VAField() == 0x7) && |
+ (instr->Bits(19, 16) == 0x1)) { |
+ // vmrs |
+ if (instr->RtField() == 0xF) |
Copy_FPSCR_to_APSR(); |
else |
UNIMPLEMENTED(); // Not used by V8. |
} else { |
UNIMPLEMENTED(); // Not used by V8. |
} |
- } 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 { |
+ } |
+} |
+ |
+ |
+void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { |
+ ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) && |
+ (instr->VAField() == 0x0)); |
+ |
+ int t = instr->RtField(); |
+ int n = GlueRegCode(true, instr->VnField(), instr->NField()); |
+ bool to_arm_register = (instr->VLField() == 0x1); |
+ |
+ if (to_arm_register) { |
+ int32_t int_value = get_sinteger_from_s_register(n); |
+ set_register(t, int_value); |
+ } else { |
+ int32_t rs_val = get_register(t); |
+ set_s_register_from_sinteger(n, rs_val); |
+ } |
+} |
+ |
+ |
+void Simulator::DecodeVCMP(Instr* instr) { |
+ ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); |
+ ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && |
+ (instr->Opc3Field() & 0x1)); |
+ |
+ // Comparison. |
+ bool dp_operation = (instr->SzField() == 1); |
+ |
+ if (instr->Bit(7) != 0) { |
+ // Raising exceptions for quiet NaNs are not supported. |
+ UNIMPLEMENTED(); // Not used by V8. |
+ } |
+ |
+ int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField()); |
+ int m = GlueRegCode(!dp_operation, instr->VmField(), instr->MField()); |
+ |
+ if (dp_operation) { |
+ double dd_value = get_double_from_d_register(d); |
+ double dm_value = get_double_from_d_register(m); |
+ |
+ Compute_FPSCR_Flags(dd_value, dm_value); |
+ } else { |
+ UNIMPLEMENTED(); // Not used by V8. |
+ } |
+} |
+ |
+ |
+void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { |
+ ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); |
+ ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)); |
+ |
+ bool double_to_single = (instr->SzField() == 1); |
+ int dst = GlueRegCode(double_to_single, instr->VdField(), instr->DField()); |
+ int src = GlueRegCode(!double_to_single, instr->VmField(), instr->MField()); |
+ |
+ if (double_to_single) { |
+ double val = get_double_from_d_register(src); |
+ set_s_register_from_float(dst, static_cast<float>(val)); |
+ } else { |
+ float val = get_float_from_s_register(src); |
+ set_d_register_from_double(dst, static_cast<double>(val)); |
+ } |
+} |
+ |
+ |
+void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { |
+ ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); |
+ ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) || |
+ (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1))); |
+ |
+ // Conversion between floating-point and integer. |
+ int vd = instr->VdField(); |
+ int d = instr->DField(); |
+ int vm = instr->VmField(); |
+ int m = instr->MField(); |
+ |
+ bool to_integer = (instr->Bit(18) == 1); |
+ bool dp_operation = (instr->SzField() == 1); |
+ if (to_integer) { |
+ bool unsigned_integer = (instr->Bit(16) == 0); |
+ if (instr->Bit(7) != 1) { |
+ // Only rounding towards zero supported. |
UNIMPLEMENTED(); // Not used by V8. |
} |
+ |
+ int dst = GlueRegCode(true, vd, d); |
+ int src = GlueRegCode(!dp_operation, vm, m); |
+ |
+ if (dp_operation) { |
+ double val = get_double_from_d_register(src); |
+ |
+ int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
+ static_cast<int32_t>(val); |
+ |
+ set_s_register_from_sinteger(dst, sint); |
+ } else { |
+ float val = get_float_from_s_register(src); |
+ |
+ int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
+ static_cast<int32_t>(val); |
+ |
+ set_s_register_from_sinteger(dst, sint); |
+ } |
} 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); |
+ bool unsigned_integer = (instr->Bit(7) == 0); |
+ |
+ int dst = GlueRegCode(!dp_operation, vd, d); |
+ int src = GlueRegCode(true, vm, m); |
+ |
+ int val = get_sinteger_from_s_register(src); |
+ |
+ if (dp_operation) { |
+ if (unsigned_integer) { |
+ set_d_register_from_double(dst, |
+ static_cast<double>((uint32_t)val)); |
+ } else { |
+ set_d_register_from_double(dst, static_cast<double>(val)); |
+ } |
} else { |
- UNIMPLEMENTED(); // Not used by V8. |
+ if (unsigned_integer) { |
+ set_s_register_from_float(dst, |
+ static_cast<float>((uint32_t)val)); |
+ } else { |
+ set_s_register_from_float(dst, static_cast<float>(val)); |
+ } |
} |
} |
} |
@@ -2055,10 +2190,33 @@ |
void Simulator::DecodeType6CoprocessorIns(Instr* instr) { |
ASSERT((instr->TypeField() == 6)); |
- if (instr->CoprocessorField() != 0xB) { |
- UNIMPLEMENTED(); // Not used by V8. |
- } else { |
+ if (instr->CoprocessorField() == 0xA) { |
switch (instr->OpcodeField()) { |
+ case 0x8: |
+ case 0xC: { // Load and store float to memory. |
+ int rn = instr->RnField(); |
+ int vd = instr->VdField(); |
+ int offset = instr->Immed8Field(); |
+ if (!instr->HasU()) { |
+ offset = -offset; |
+ } |
+ |
+ int32_t address = get_register(rn) + 4 * offset; |
+ if (instr->HasL()) { |
+ // Load double from memory: vldr. |
+ set_s_register_from_sinteger(vd, ReadW(address, instr)); |
+ } else { |
+ // Store double to memory: vstr. |
+ WriteW(address, get_sinteger_from_s_register(vd), instr); |
+ } |
+ break; |
+ } |
+ default: |
+ UNIMPLEMENTED(); // Not used by V8. |
+ break; |
+ } |
+ } else if (instr->CoprocessorField() == 0xB) { |
+ switch (instr->OpcodeField()) { |
case 0x2: |
// Load and store double to two GP registers |
if (instr->Bits(7, 4) != 0x1) { |
@@ -2106,6 +2264,8 @@ |
UNIMPLEMENTED(); // Not used by V8. |
break; |
} |
+ } else { |
+ UNIMPLEMENTED(); // Not used by V8. |
} |
} |