| Index: runtime/vm/simulator_arm64.cc
|
| ===================================================================
|
| --- runtime/vm/simulator_arm64.cc (revision 35658)
|
| +++ runtime/vm/simulator_arm64.cc (working copy)
|
| @@ -93,7 +93,7 @@
|
| Simulator* sim_;
|
|
|
| bool GetValue(char* desc, int64_t* value);
|
| - // TODO(zra): GetVValue for doubles.
|
| + bool GetDValue(char* desc, int64_t* value);
|
| // TODO(zra): Breakpoints.
|
| };
|
|
|
| @@ -143,6 +143,16 @@
|
| }
|
|
|
|
|
| +static VRegister LookupVRegisterByName(const char* name) {
|
| + int reg_nr = -1;
|
| + bool ok = SScanF(name, "v%d", ®_nr);
|
| + if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfVRegisters)) {
|
| + return static_cast<VRegister>(reg_nr);
|
| + }
|
| + return kNoVRegister;
|
| +}
|
| +
|
| +
|
| bool SimulatorDebugger::GetValue(char* desc, int64_t* value) {
|
| Register reg = LookupCpuRegisterByName(desc);
|
| if (reg != kNoRegister) {
|
| @@ -175,6 +185,26 @@
|
| }
|
|
|
|
|
| +bool SimulatorDebugger::GetDValue(char* desc, int64_t* value) {
|
| + VRegister vreg = LookupVRegisterByName(desc);
|
| + if (vreg != kNoVRegister) {
|
| + *value = sim_->get_vregisterd(vreg);
|
| + return true;
|
| + }
|
| + if (desc[0] == '*') {
|
| + int64_t addr;
|
| + if (GetValue(desc + 1, &addr)) {
|
| + if (Simulator::IsIllegalAddress(addr)) {
|
| + return false;
|
| + }
|
| + *value = *(reinterpret_cast<int64_t*>(addr));
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| void SimulatorDebugger::Debug() {
|
| intptr_t last_pc = -1;
|
| bool done = false;
|
| @@ -225,9 +255,11 @@
|
| " disasm <address>\n"
|
| " disasm <address> <number_of_instructions>\n"
|
| " by default 10 instrs are disassembled\n"
|
| + "flags -- print flag values\n"
|
| "gdb -- transfer control to gdb\n"
|
| "h/help -- print this help string\n"
|
| "p/print <reg or value or *addr> -- print integer value\n"
|
| + "pd/printdouble <dreg or *addr> -- print double value\n"
|
| "po/printobject <*reg or *addr> -- print object\n"
|
| "si/stepi -- single step an instruction\n"
|
| "q/quit -- Quit the debugger and exit the program\n");
|
| @@ -252,6 +284,20 @@
|
| } else {
|
| OS::Print("print <reg or value or *addr>\n");
|
| }
|
| + } else if ((strcmp(cmd, "pd") == 0) ||
|
| + (strcmp(cmd, "printdouble") == 0)) {
|
| + if (args == 2) {
|
| + int64_t long_value;
|
| + if (GetDValue(arg1, &long_value)) {
|
| + double dvalue = bit_cast<double, int64_t>(long_value);
|
| + OS::Print("%s: %"Pu64" 0x%"Px64" %.8g\n",
|
| + arg1, long_value, long_value, dvalue);
|
| + } else {
|
| + OS::Print("%s unrecognized\n", arg1);
|
| + }
|
| + } else {
|
| + OS::Print("printdouble <dreg or *addr>\n");
|
| + }
|
| } else if ((strcmp(cmd, "po") == 0) ||
|
| (strcmp(cmd, "printobject") == 0)) {
|
| if (args == 2) {
|
| @@ -307,6 +353,17 @@
|
| }
|
| }
|
| Disassembler::Disassemble(start, end);
|
| + } else if (strcmp(cmd, "flags") == 0) {
|
| + OS::Print("APSR: ");
|
| + OS::Print("N flag: %d; ", sim_->n_flag_);
|
| + OS::Print("Z flag: %d; ", sim_->z_flag_);
|
| + OS::Print("C flag: %d; ", sim_->c_flag_);
|
| + OS::Print("V flag: %d\n", sim_->v_flag_);
|
| + OS::Print("FPSCR: ");
|
| + OS::Print("N flag: %d; ", sim_->fp_n_flag_);
|
| + OS::Print("Z flag: %d; ", sim_->fp_z_flag_);
|
| + OS::Print("C flag: %d; ", sim_->fp_c_flag_);
|
| + OS::Print("V flag: %d\n", sim_->fp_v_flag_);
|
| } else if (strcmp(cmd, "gdb") == 0) {
|
| OS::Print("relinquishing control to gdb\n");
|
| OS::DebugBreak();
|
| @@ -418,6 +475,15 @@
|
| c_flag_ = false;
|
| v_flag_ = false;
|
|
|
| + for (int i = 0; i < kNumberOfVRegisters; i++) {
|
| + vregisters_[i].lo = 0;
|
| + vregisters_[i].hi = 0;
|
| + }
|
| + fp_n_flag_ = false;
|
| + fp_z_flag_ = false;
|
| + fp_c_flag_ = false;
|
| + fp_v_flag_ = false;
|
| +
|
| // The sp is initialized to point to the bottom (high address) of the
|
| // allocated stack area.
|
| registers_[R31] = StackTop();
|
| @@ -559,6 +625,19 @@
|
| }
|
|
|
|
|
| +int64_t Simulator::get_vregisterd(VRegister reg) {
|
| + ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
|
| + return vregisters_[reg].lo;
|
| +}
|
| +
|
| +
|
| +void Simulator::set_vregisterd(VRegister reg, int64_t value) {
|
| + ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
|
| + vregisters_[reg].lo = value;
|
| + vregisters_[reg].hi = 0;
|
| +}
|
| +
|
| +
|
| // Raw access to the PC register.
|
| void Simulator::set_pc(int64_t value) {
|
| pc_modified_ = true;
|
| @@ -843,7 +922,7 @@
|
| const int hw = instr->HWField();
|
| const int64_t shift = hw << 4;
|
| const int64_t shifted_imm =
|
| - static_cast<uint64_t>(instr->Imm16Field()) << shift;
|
| + static_cast<int64_t>(instr->Imm16Field()) << shift;
|
|
|
| if (instr->SFField()) {
|
| if (instr->Bits(29, 2) == 0) {
|
| @@ -1899,8 +1978,66 @@
|
| }
|
|
|
|
|
| +void Simulator::DecodeFPImm(Instr* instr) {
|
| + if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || (instr->Bit(23) != 0) ||
|
| + (instr->Bits(5, 5) != 0)) {
|
| + UnimplementedInstruction(instr);
|
| + return;
|
| + }
|
| + if (instr->Bit(22) == 1) {
|
| + // Double.
|
| + // Format(instr, "fmovd 'vd, #'immd");
|
| + const VRegister vd = instr->VdField();
|
| + const int64_t immd = Instr::VFPExpandImm(instr->Imm8Field());
|
| + set_vregisterd(vd, immd);
|
| + } else {
|
| + // Single.
|
| + UnimplementedInstruction(instr);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Simulator::DecodeFPIntCvt(Instr* instr) {
|
| + if ((instr->SFField() != 1) || (instr->Bit(29) != 0) ||
|
| + (instr->Bits(22, 2) != 1)) {
|
| + UnimplementedInstruction(instr);
|
| + return;
|
| + }
|
| + if (instr->Bits(16, 3) == 6) {
|
| + // Format(instr, "fmovrd 'rd, 'vn");
|
| + const VRegister vn = instr->VnField();
|
| + const Register rd = instr->RdField();
|
| + const int64_t vn_val = get_vregisterd(vn);
|
| + set_register(rd, vn_val, R31IsZR);
|
| + } else if (instr->Bits(16, 3) == 7) {
|
| + // Format(instr, "fmovdr 'vd, 'rn");
|
| + const VRegister vd = instr->VdField();
|
| + const Register rn = instr->RnField();
|
| + const int64_t rn_val = get_register(rn, R31IsZR);
|
| + set_vregisterd(vd, rn_val);
|
| + } else {
|
| + UnimplementedInstruction(instr);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Simulator::DecodeFP(Instr* instr) {
|
| + if (instr->IsFPImmOp()) {
|
| + DecodeFPImm(instr);
|
| + } else if (instr->IsFPIntCvtOp()) {
|
| + DecodeFPIntCvt(instr);
|
| + } else {
|
| + UnimplementedInstruction(instr);
|
| + }
|
| +}
|
| +
|
| +
|
| void Simulator::DecodeDPSimd2(Instr* instr) {
|
| - UnimplementedInstruction(instr);
|
| + if (instr->IsFPOp()) {
|
| + DecodeFP(instr);
|
| + } else {
|
| + UnimplementedInstruction(instr);
|
| + }
|
| }
|
|
|
|
|
| @@ -1977,15 +2114,24 @@
|
| int64_t parameter0,
|
| int64_t parameter1,
|
| int64_t parameter2,
|
| - int64_t parameter3) {
|
| + int64_t parameter3,
|
| + bool fp_return,
|
| + bool fp_args) {
|
| // Save the SP register before the call so we can restore it.
|
| intptr_t sp_before_call = get_register(R31, R31IsSP);
|
|
|
| // Setup parameters.
|
| - set_register(R0, parameter0);
|
| - set_register(R1, parameter1);
|
| - set_register(R2, parameter2);
|
| - set_register(R3, parameter3);
|
| + if (fp_args) {
|
| + set_vregisterd(V0, parameter0);
|
| + set_vregisterd(V1, parameter1);
|
| + set_vregisterd(V2, parameter2);
|
| + set_vregisterd(V3, parameter3);
|
| + } else {
|
| + set_register(R0, parameter0);
|
| + set_register(R1, parameter1);
|
| + set_register(R2, parameter2);
|
| + set_register(R3, parameter3);
|
| + }
|
|
|
| // Make sure the activation frames are properly aligned.
|
| intptr_t stack_pointer = sp_before_call;
|
| @@ -2002,67 +2148,50 @@
|
| // the LR the simulation stops when returning to this call point.
|
| set_register(LR, kEndSimulatingPC);
|
|
|
| - // Remember the values of callee-saved registers.
|
| - int64_t r19_val = get_register(R19);
|
| - int64_t r20_val = get_register(R20);
|
| - int64_t r21_val = get_register(R21);
|
| - int64_t r22_val = get_register(R22);
|
| - int64_t r23_val = get_register(R23);
|
| - int64_t r24_val = get_register(R24);
|
| - int64_t r25_val = get_register(R25);
|
| - int64_t r26_val = get_register(R26);
|
| - int64_t r27_val = get_register(R27);
|
| - int64_t r28_val = get_register(R28);
|
| - int64_t r29_val = get_register(R29);
|
| -
|
| - // Setup the callee-saved registers with a known value. To be able to check
|
| - // that they are preserved properly across dart execution.
|
| + // Remember the values of callee-saved registers, and set them up with a
|
| + // known value so that we are able to check that they are preserved
|
| + // properly across Dart execution.
|
| + int64_t preserved_vals[kAbiPreservedCpuRegCount];
|
| int64_t callee_saved_value = icount_;
|
| - set_register(R19, callee_saved_value);
|
| - set_register(R20, callee_saved_value);
|
| - set_register(R21, callee_saved_value);
|
| - set_register(R22, callee_saved_value);
|
| - set_register(R23, callee_saved_value);
|
| - set_register(R24, callee_saved_value);
|
| - set_register(R25, callee_saved_value);
|
| - set_register(R26, callee_saved_value);
|
| - set_register(R27, callee_saved_value);
|
| - set_register(R28, callee_saved_value);
|
| - set_register(R29, callee_saved_value);
|
| + for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) {
|
| + const Register r = static_cast<Register>(i);
|
| + preserved_vals[i - kAbiFirstPreservedCpuReg] = get_register(r);
|
| + set_register(r, callee_saved_value);
|
| + }
|
|
|
| + // Only the bottom half of the V registers must be preserved.
|
| + int64_t preserved_dvals[kAbiPreservedFpuRegCount];
|
| + for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) {
|
| + const VRegister r = static_cast<VRegister>(i);
|
| + preserved_dvals[i - kAbiFirstPreservedFpuReg] = get_vregisterd(r);
|
| + set_vregisterd(r, callee_saved_value);
|
| + }
|
| +
|
| // Start the simulation
|
| Execute();
|
|
|
| - // Check that the callee-saved registers have been preserved.
|
| - ASSERT(callee_saved_value == get_register(R19));
|
| - ASSERT(callee_saved_value == get_register(R20));
|
| - ASSERT(callee_saved_value == get_register(R21));
|
| - ASSERT(callee_saved_value == get_register(R22));
|
| - ASSERT(callee_saved_value == get_register(R23));
|
| - ASSERT(callee_saved_value == get_register(R24));
|
| - ASSERT(callee_saved_value == get_register(R25));
|
| - ASSERT(callee_saved_value == get_register(R26));
|
| - ASSERT(callee_saved_value == get_register(R27));
|
| - ASSERT(callee_saved_value == get_register(R28));
|
| - ASSERT(callee_saved_value == get_register(R29));
|
| + // Check that the callee-saved registers have been preserved,
|
| + // and restore them with the original value
|
| + for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) {
|
| + const Register r = static_cast<Register>(i);
|
| + ASSERT(callee_saved_value == get_register(r));
|
| + set_register(r, preserved_vals[i - kAbiFirstPreservedCpuReg]);
|
| + }
|
|
|
| - // Restore callee-saved registers with the original value.
|
| - set_register(R19, r19_val);
|
| - set_register(R20, r20_val);
|
| - set_register(R21, r21_val);
|
| - set_register(R22, r22_val);
|
| - set_register(R23, r23_val);
|
| - set_register(R24, r24_val);
|
| - set_register(R25, r25_val);
|
| - set_register(R26, r26_val);
|
| - set_register(R27, r27_val);
|
| - set_register(R28, r28_val);
|
| - set_register(R29, r29_val);
|
| + for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) {
|
| + const VRegister r = static_cast<VRegister>(i);
|
| + ASSERT(callee_saved_value == get_vregisterd(r));
|
| + set_vregisterd(r, preserved_dvals[i - kAbiFirstPreservedFpuReg]);
|
| + }
|
|
|
| // Restore the SP register and return R0.
|
| set_register(R31, sp_before_call, R31IsSP);
|
| int64_t return_value;
|
| - return_value = get_register(R0);
|
| + if (fp_return) {
|
| + return_value = get_vregisterd(V0);
|
| + } else {
|
| + return_value = get_register(R0);
|
| + }
|
| return return_value;
|
| }
|
|
|
|
|