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