| 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.
|
| }
|
| }
|
|
|
|
|