|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 // Copyright 2012 the V8 project authors. All rights reserved. |
|
3 // Redistribution and use in source and binary forms, with or without |
|
4 // modification, are permitted provided that the following conditions are |
|
5 // met: |
|
6 // |
|
7 // * Redistributions of source code must retain the above copyright |
|
8 // notice, this list of conditions and the following disclaimer. |
|
9 // * Redistributions in binary form must reproduce the above |
|
10 // copyright notice, this list of conditions and the following |
|
11 // disclaimer in the documentation and/or other materials provided |
|
12 // with the distribution. |
|
13 // * Neither the name of Google Inc. nor the names of its |
|
14 // contributors may be used to endorse or promote products derived |
|
15 // from this software without specific prior written permission. |
|
16 // |
|
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
28 |
|
29 #ifndef jit_arm_Simulator_arm_h |
|
30 #define jit_arm_Simulator_arm_h |
|
31 |
|
32 #ifdef JS_ARM_SIMULATOR |
|
33 |
|
34 #include "jit/arm/Architecture-arm.h" |
|
35 #include "jit/IonTypes.h" |
|
36 |
|
37 namespace js { |
|
38 namespace jit { |
|
39 |
|
40 class SimulatorRuntime; |
|
41 SimulatorRuntime *CreateSimulatorRuntime(); |
|
42 void DestroySimulatorRuntime(SimulatorRuntime *srt); |
|
43 |
|
44 // VFP rounding modes. See ARM DDI 0406B Page A2-29. |
|
45 enum VFPRoundingMode { |
|
46 SimRN = 0 << 22, // Round to Nearest. |
|
47 SimRP = 1 << 22, // Round towards Plus Infinity. |
|
48 SimRM = 2 << 22, // Round towards Minus Infinity. |
|
49 SimRZ = 3 << 22, // Round towards zero. |
|
50 |
|
51 // Aliases. |
|
52 kRoundToNearest = SimRN, |
|
53 kRoundToPlusInf = SimRP, |
|
54 kRoundToMinusInf = SimRM, |
|
55 kRoundToZero = SimRZ |
|
56 }; |
|
57 |
|
58 const uint32_t kVFPRoundingModeMask = 3 << 22; |
|
59 |
|
60 typedef int32_t Instr; |
|
61 class SimInstruction; |
|
62 |
|
63 class Simulator |
|
64 { |
|
65 friend class Redirection; |
|
66 |
|
67 public: |
|
68 friend class ArmDebugger; |
|
69 enum Register { |
|
70 no_reg = -1, |
|
71 r0 = 0, r1, r2, r3, r4, r5, r6, r7, |
|
72 r8, r9, r10, r11, r12, r13, r14, r15, |
|
73 num_registers, |
|
74 sp = 13, |
|
75 lr = 14, |
|
76 pc = 15, |
|
77 s0 = 0, s1, s2, s3, s4, s5, s6, s7, |
|
78 s8, s9, s10, s11, s12, s13, s14, s15, |
|
79 s16, s17, s18, s19, s20, s21, s22, s23, |
|
80 s24, s25, s26, s27, s28, s29, s30, s31, |
|
81 num_s_registers = 32, |
|
82 d0 = 0, d1, d2, d3, d4, d5, d6, d7, |
|
83 d8, d9, d10, d11, d12, d13, d14, d15, |
|
84 d16, d17, d18, d19, d20, d21, d22, d23, |
|
85 d24, d25, d26, d27, d28, d29, d30, d31, |
|
86 num_d_registers = 32, |
|
87 q0 = 0, q1, q2, q3, q4, q5, q6, q7, |
|
88 q8, q9, q10, q11, q12, q13, q14, q15, |
|
89 num_q_registers = 16 |
|
90 }; |
|
91 |
|
92 explicit Simulator(SimulatorRuntime *srt); |
|
93 ~Simulator(); |
|
94 |
|
95 // The currently executing Simulator instance. Potentially there can be one |
|
96 // for each native thread. |
|
97 static Simulator *Current(); |
|
98 |
|
99 static inline uintptr_t StackLimit() { |
|
100 return Simulator::Current()->stackLimit(); |
|
101 } |
|
102 |
|
103 // Accessors for register state. Reading the pc value adheres to the ARM |
|
104 // architecture specification and is off by a 8 from the currently executing |
|
105 // instruction. |
|
106 void set_register(int reg, int32_t value); |
|
107 int32_t get_register(int reg) const; |
|
108 double get_double_from_register_pair(int reg); |
|
109 void set_register_pair_from_double(int reg, double* value); |
|
110 void set_dw_register(int dreg, const int* dbl); |
|
111 |
|
112 // Support for VFP. |
|
113 void get_d_register(int dreg, uint64_t* value); |
|
114 void set_d_register(int dreg, const uint64_t* value); |
|
115 void get_d_register(int dreg, uint32_t* value); |
|
116 void set_d_register(int dreg, const uint32_t* value); |
|
117 void get_q_register(int qreg, uint64_t* value); |
|
118 void set_q_register(int qreg, const uint64_t* value); |
|
119 void get_q_register(int qreg, uint32_t* value); |
|
120 void set_q_register(int qreg, const uint32_t* value); |
|
121 void set_s_register(int reg, unsigned int value); |
|
122 unsigned int get_s_register(int reg) const; |
|
123 |
|
124 void set_d_register_from_double(int dreg, const double& dbl) { |
|
125 setVFPRegister<double, 2>(dreg, dbl); |
|
126 } |
|
127 double get_double_from_d_register(int dreg) { |
|
128 return getFromVFPRegister<double, 2>(dreg); |
|
129 } |
|
130 void set_s_register_from_float(int sreg, const float flt) { |
|
131 setVFPRegister<float, 1>(sreg, flt); |
|
132 } |
|
133 float get_float_from_s_register(int sreg) { |
|
134 return getFromVFPRegister<float, 1>(sreg); |
|
135 } |
|
136 void set_s_register_from_sinteger(int sreg, const int sint) { |
|
137 setVFPRegister<int, 1>(sreg, sint); |
|
138 } |
|
139 int get_sinteger_from_s_register(int sreg) { |
|
140 return getFromVFPRegister<int, 1>(sreg); |
|
141 } |
|
142 |
|
143 // Special case of set_register and get_register to access the raw PC value. |
|
144 void set_pc(int32_t value); |
|
145 int32_t get_pc() const; |
|
146 |
|
147 void set_resume_pc(int32_t value) { |
|
148 resume_pc_ = value; |
|
149 } |
|
150 |
|
151 uintptr_t stackLimit() const; |
|
152 bool overRecursed(uintptr_t newsp = 0) const; |
|
153 bool overRecursedWithExtra(uint32_t extra) const; |
|
154 |
|
155 // Executes ARM instructions until the PC reaches end_sim_pc. |
|
156 template<bool EnableStopSimAt> |
|
157 void execute(); |
|
158 |
|
159 // Sets up the simulator state and grabs the result on return. |
|
160 int64_t call(uint8_t* entry, int argument_count, ...); |
|
161 |
|
162 // Debugger input. |
|
163 void setLastDebuggerInput(char *input); |
|
164 char *lastDebuggerInput() { return lastDebuggerInput_; } |
|
165 |
|
166 // Returns true if pc register contains one of the 'special_values' defined |
|
167 // below (bad_lr, end_sim_pc). |
|
168 bool has_bad_pc() const; |
|
169 |
|
170 private: |
|
171 enum special_values { |
|
172 // Known bad pc value to ensure that the simulator does not execute |
|
173 // without being properly setup. |
|
174 bad_lr = -1, |
|
175 // A pc value used to signal the simulator to stop execution. Generally |
|
176 // the lr is set to this value on transition from native C code to |
|
177 // simulated execution, so that the simulator can "return" to the native |
|
178 // C code. |
|
179 end_sim_pc = -2 |
|
180 }; |
|
181 |
|
182 // Checks if the current instruction should be executed based on its |
|
183 // condition bits. |
|
184 inline bool conditionallyExecute(SimInstruction* instr); |
|
185 |
|
186 // Helper functions to set the conditional flags in the architecture state. |
|
187 void setNZFlags(int32_t val); |
|
188 void setCFlag(bool val); |
|
189 void setVFlag(bool val); |
|
190 bool carryFrom(int32_t left, int32_t right, int32_t carry = 0); |
|
191 bool borrowFrom(int32_t left, int32_t right); |
|
192 bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition); |
|
193 |
|
194 inline int getCarry() { return c_flag_ ? 1 : 0; }; |
|
195 |
|
196 // Support for VFP. |
|
197 void compute_FPSCR_Flags(double val1, double val2); |
|
198 void copy_FPSCR_to_APSR(); |
|
199 inline double canonicalizeNaN(double value); |
|
200 |
|
201 // Helper functions to decode common "addressing" modes |
|
202 int32_t getShiftRm(SimInstruction *instr, bool* carry_out); |
|
203 int32_t getImm(SimInstruction *instr, bool* carry_out); |
|
204 int32_t processPU(SimInstruction *instr, int num_regs, int operand_size, |
|
205 intptr_t *start_address, intptr_t *end_address); |
|
206 void handleRList(SimInstruction *instr, bool load); |
|
207 void handleVList(SimInstruction *inst); |
|
208 void softwareInterrupt(SimInstruction *instr); |
|
209 |
|
210 // Stop helper functions. |
|
211 inline bool isStopInstruction(SimInstruction *instr); |
|
212 inline bool isWatchedStop(uint32_t bkpt_code); |
|
213 inline bool isEnabledStop(uint32_t bkpt_code); |
|
214 inline void enableStop(uint32_t bkpt_code); |
|
215 inline void disableStop(uint32_t bkpt_code); |
|
216 inline void increaseStopCounter(uint32_t bkpt_code); |
|
217 void printStopInfo(uint32_t code); |
|
218 |
|
219 // Read and write memory. |
|
220 inline uint8_t readBU(int32_t addr); |
|
221 inline int8_t readB(int32_t addr); |
|
222 inline void writeB(int32_t addr, uint8_t value); |
|
223 inline void writeB(int32_t addr, int8_t value); |
|
224 |
|
225 inline uint16_t readHU(int32_t addr, SimInstruction *instr); |
|
226 inline int16_t readH(int32_t addr, SimInstruction *instr); |
|
227 // Note: Overloaded on the sign of the value. |
|
228 inline void writeH(int32_t addr, uint16_t value, SimInstruction *instr); |
|
229 inline void writeH(int32_t addr, int16_t value, SimInstruction *instr); |
|
230 |
|
231 inline int readW(int32_t addr, SimInstruction *instr); |
|
232 inline void writeW(int32_t addr, int value, SimInstruction *instr); |
|
233 |
|
234 int32_t *readDW(int32_t addr); |
|
235 void writeDW(int32_t addr, int32_t value1, int32_t value2); |
|
236 |
|
237 // Executing is handled based on the instruction type. |
|
238 // Both type 0 and type 1 rolled into one. |
|
239 void decodeType01(SimInstruction *instr); |
|
240 void decodeType2(SimInstruction *instr); |
|
241 void decodeType3(SimInstruction *instr); |
|
242 void decodeType4(SimInstruction *instr); |
|
243 void decodeType5(SimInstruction *instr); |
|
244 void decodeType6(SimInstruction *instr); |
|
245 void decodeType7(SimInstruction *instr); |
|
246 |
|
247 // Support for VFP. |
|
248 void decodeTypeVFP(SimInstruction *instr); |
|
249 void decodeType6CoprocessorIns(SimInstruction *instr); |
|
250 void decodeSpecialCondition(SimInstruction *instr); |
|
251 |
|
252 void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr); |
|
253 void decodeVCMP(SimInstruction *instr); |
|
254 void decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr); |
|
255 void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr); |
|
256 void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr); |
|
257 |
|
258 // Executes one instruction. |
|
259 void instructionDecode(SimInstruction *instr); |
|
260 |
|
261 public: |
|
262 static bool ICacheCheckingEnabled; |
|
263 static void FlushICache(void *start, size_t size); |
|
264 |
|
265 static int64_t StopSimAt; |
|
266 |
|
267 // Runtime call support. |
|
268 static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type); |
|
269 |
|
270 private: |
|
271 // Handle arguments and return value for runtime FP functions. |
|
272 void getFpArgs(double *x, double *y, int32_t *z); |
|
273 void setCallResultDouble(double result); |
|
274 void setCallResultFloat(float result); |
|
275 void setCallResult(int64_t res); |
|
276 void scratchVolatileRegisters(bool scratchFloat = true); |
|
277 |
|
278 template<class ReturnType, int register_size> |
|
279 ReturnType getFromVFPRegister(int reg_index); |
|
280 |
|
281 template<class InputType, int register_size> |
|
282 void setVFPRegister(int reg_index, const InputType& value); |
|
283 |
|
284 void callInternal(uint8_t* entry); |
|
285 |
|
286 // Architecture state. |
|
287 // Saturating instructions require a Q flag to indicate saturation. |
|
288 // There is currently no way to read the CPSR directly, and thus read the Q |
|
289 // flag, so this is left unimplemented. |
|
290 int32_t registers_[16]; |
|
291 bool n_flag_; |
|
292 bool z_flag_; |
|
293 bool c_flag_; |
|
294 bool v_flag_; |
|
295 |
|
296 // VFP architecture state. |
|
297 uint32_t vfp_registers_[num_d_registers * 2]; |
|
298 bool n_flag_FPSCR_; |
|
299 bool z_flag_FPSCR_; |
|
300 bool c_flag_FPSCR_; |
|
301 bool v_flag_FPSCR_; |
|
302 |
|
303 // VFP rounding mode. See ARM DDI 0406B Page A2-29. |
|
304 VFPRoundingMode FPSCR_rounding_mode_; |
|
305 bool FPSCR_default_NaN_mode_; |
|
306 |
|
307 // VFP FP exception flags architecture state. |
|
308 bool inv_op_vfp_flag_; |
|
309 bool div_zero_vfp_flag_; |
|
310 bool overflow_vfp_flag_; |
|
311 bool underflow_vfp_flag_; |
|
312 bool inexact_vfp_flag_; |
|
313 |
|
314 // Simulator support. |
|
315 char *stack_; |
|
316 bool pc_modified_; |
|
317 int64_t icount_; |
|
318 |
|
319 int32_t resume_pc_; |
|
320 |
|
321 // Debugger input. |
|
322 char *lastDebuggerInput_; |
|
323 |
|
324 // Registered breakpoints. |
|
325 SimInstruction *break_pc_; |
|
326 Instr break_instr_; |
|
327 |
|
328 SimulatorRuntime *srt_; |
|
329 |
|
330 // A stop is watched if its code is less than kNumOfWatchedStops. |
|
331 // Only watched stops support enabling/disabling and the counter feature. |
|
332 static const uint32_t kNumOfWatchedStops = 256; |
|
333 |
|
334 // Breakpoint is disabled if bit 31 is set. |
|
335 static const uint32_t kStopDisabledBit = 1 << 31; |
|
336 |
|
337 // A stop is enabled, meaning the simulator will stop when meeting the |
|
338 // instruction, if bit 31 of watched_stops_[code].count is unset. |
|
339 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times |
|
340 // the breakpoint was hit or gone through. |
|
341 struct StopCountAndDesc { |
|
342 uint32_t count; |
|
343 char *desc; |
|
344 }; |
|
345 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; |
|
346 |
|
347 public: |
|
348 int64_t icount() { |
|
349 return icount_; |
|
350 } |
|
351 |
|
352 }; |
|
353 |
|
354 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \ |
|
355 JS_BEGIN_MACRO \ |
|
356 if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) { \ |
|
357 js_ReportOverRecursed(cx); \ |
|
358 onerror; \ |
|
359 } \ |
|
360 JS_END_MACRO |
|
361 |
|
362 } // namespace jit |
|
363 } // namespace js |
|
364 |
|
365 #endif /* JS_ARM_SIMULATOR */ |
|
366 |
|
367 #endif /* jit_arm_Simulator_arm_h */ |