simulator-arm.h revision 5913587db4c6bab03d97bfe44b06289fd6d7270d
1// Copyright 2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 29// Declares a Simulator for ARM instructions if we are not generating a native 30// ARM binary. This Simulator allows us to run and debug ARM code generation on 31// regular desktop machines. 32// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro, 33// which will start execution in the Simulator or forwards to the real entry 34// on a ARM HW platform. 35 36#ifndef V8_ARM_SIMULATOR_ARM_H_ 37#define V8_ARM_SIMULATOR_ARM_H_ 38 39#include "allocation.h" 40 41#if !defined(USE_SIMULATOR) 42// Running without a simulator on a native arm platform. 43 44namespace v8 { 45namespace internal { 46 47// When running without a simulator we call the entry directly. 48#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 49 (entry(p0, p1, p2, p3, p4)) 50 51// Call the generated regexp code directly. The entry function pointer should 52// expect seven int/pointer sized arguments and return an int. 53#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ 54 (entry(p0, p1, p2, p3, p4, p5, p6)) 55 56#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 57 (reinterpret_cast<TryCatch*>(try_catch_address)) 58 59// The stack limit beyond which we will throw stack overflow errors in 60// generated code. Because generated code on arm uses the C stack, we 61// just use the C stack limit. 62class SimulatorStack : public v8::internal::AllStatic { 63 public: 64 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) { 65 return c_limit; 66 } 67 68 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 69 return try_catch_address; 70 } 71 72 static inline void UnregisterCTryCatch() { } 73}; 74 75} } // namespace v8::internal 76 77#else // !defined(USE_SIMULATOR) 78// Running with a simulator. 79 80#include "constants-arm.h" 81#include "hashmap.h" 82 83namespace assembler { 84namespace arm { 85 86class CachePage { 87 public: 88 static const int LINE_VALID = 0; 89 static const int LINE_INVALID = 1; 90 91 static const int kPageShift = 12; 92 static const int kPageSize = 1 << kPageShift; 93 static const int kPageMask = kPageSize - 1; 94 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 95 static const int kLineLength = 1 << kLineShift; 96 static const int kLineMask = kLineLength - 1; 97 98 CachePage() { 99 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 100 } 101 102 char* ValidityByte(int offset) { 103 return &validity_map_[offset >> kLineShift]; 104 } 105 106 char* CachedData(int offset) { 107 return &data_[offset]; 108 } 109 110 private: 111 char data_[kPageSize]; // The cached data. 112 static const int kValidityMapSize = kPageSize >> kLineShift; 113 char validity_map_[kValidityMapSize]; // One byte per line. 114}; 115 116 117class Simulator { 118 public: 119 friend class Debugger; 120 enum Register { 121 no_reg = -1, 122 r0 = 0, r1, r2, r3, r4, r5, r6, r7, 123 r8, r9, r10, r11, r12, r13, r14, r15, 124 num_registers, 125 sp = 13, 126 lr = 14, 127 pc = 15, 128 s0 = 0, s1, s2, s3, s4, s5, s6, s7, 129 s8, s9, s10, s11, s12, s13, s14, s15, 130 s16, s17, s18, s19, s20, s21, s22, s23, 131 s24, s25, s26, s27, s28, s29, s30, s31, 132 num_s_registers = 32, 133 d0 = 0, d1, d2, d3, d4, d5, d6, d7, 134 d8, d9, d10, d11, d12, d13, d14, d15, 135 num_d_registers = 16 136 }; 137 138 Simulator(); 139 ~Simulator(); 140 141 // The currently executing Simulator instance. Potentially there can be one 142 // for each native thread. 143 static Simulator* current(); 144 145 // Accessors for register state. Reading the pc value adheres to the ARM 146 // architecture specification and is off by a 8 from the currently executing 147 // instruction. 148 void set_register(int reg, int32_t value); 149 int32_t get_register(int reg) const; 150 void set_dw_register(int dreg, const int* dbl); 151 152 // Support for VFP. 153 void set_s_register(int reg, unsigned int value); 154 unsigned int get_s_register(int reg) const; 155 void set_d_register_from_double(int dreg, const double& dbl); 156 double get_double_from_d_register(int dreg); 157 void set_s_register_from_float(int sreg, const float dbl); 158 float get_float_from_s_register(int sreg); 159 void set_s_register_from_sinteger(int reg, const int value); 160 int get_sinteger_from_s_register(int reg); 161 162 // Special case of set_register and get_register to access the raw PC value. 163 void set_pc(int32_t value); 164 int32_t get_pc() const; 165 166 // Accessor to the internal simulator stack area. 167 uintptr_t StackLimit() const; 168 169 // Executes ARM instructions until the PC reaches end_sim_pc. 170 void Execute(); 171 172 // Call on program start. 173 static void Initialize(); 174 175 // V8 generally calls into generated JS code with 5 parameters and into 176 // generated RegExp code with 7 parameters. This is a convenience function, 177 // which sets up the simulator state and grabs the result on return. 178 int32_t Call(byte* entry, int argument_count, ...); 179 180 // Push an address onto the JS stack. 181 uintptr_t PushAddress(uintptr_t address); 182 183 // Pop an address from the JS stack. 184 uintptr_t PopAddress(); 185 186 // ICache checking. 187 static void FlushICache(void* start, size_t size); 188 189 private: 190 enum special_values { 191 // Known bad pc value to ensure that the simulator does not execute 192 // without being properly setup. 193 bad_lr = -1, 194 // A pc value used to signal the simulator to stop execution. Generally 195 // the lr is set to this value on transition from native C code to 196 // simulated execution, so that the simulator can "return" to the native 197 // C code. 198 end_sim_pc = -2 199 }; 200 201 // Unsupported instructions use Format to print an error and stop execution. 202 void Format(Instr* instr, const char* format); 203 204 // Checks if the current instruction should be executed based on its 205 // condition bits. 206 bool ConditionallyExecute(Instr* instr); 207 208 // Helper functions to set the conditional flags in the architecture state. 209 void SetNZFlags(int32_t val); 210 void SetCFlag(bool val); 211 void SetVFlag(bool val); 212 bool CarryFrom(int32_t left, int32_t right); 213 bool BorrowFrom(int32_t left, int32_t right); 214 bool OverflowFrom(int32_t alu_out, 215 int32_t left, 216 int32_t right, 217 bool addition); 218 219 // Support for VFP. 220 void Compute_FPSCR_Flags(double val1, double val2); 221 void Copy_FPSCR_to_APSR(); 222 223 // Helper functions to decode common "addressing" modes 224 int32_t GetShiftRm(Instr* instr, bool* carry_out); 225 int32_t GetImm(Instr* instr, bool* carry_out); 226 void HandleRList(Instr* instr, bool load); 227 void SoftwareInterrupt(Instr* instr); 228 229 // Read and write memory. 230 inline uint8_t ReadBU(int32_t addr); 231 inline int8_t ReadB(int32_t addr); 232 inline void WriteB(int32_t addr, uint8_t value); 233 inline void WriteB(int32_t addr, int8_t value); 234 235 inline uint16_t ReadHU(int32_t addr, Instr* instr); 236 inline int16_t ReadH(int32_t addr, Instr* instr); 237 // Note: Overloaded on the sign of the value. 238 inline void WriteH(int32_t addr, uint16_t value, Instr* instr); 239 inline void WriteH(int32_t addr, int16_t value, Instr* instr); 240 241 inline int ReadW(int32_t addr, Instr* instr); 242 inline void WriteW(int32_t addr, int value, Instr* instr); 243 244 int32_t* ReadDW(int32_t addr); 245 void WriteDW(int32_t addr, int32_t value1, int32_t value2); 246 247 // Executing is handled based on the instruction type. 248 void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into one 249 void DecodeType2(Instr* instr); 250 void DecodeType3(Instr* instr); 251 void DecodeType4(Instr* instr); 252 void DecodeType5(Instr* instr); 253 void DecodeType6(Instr* instr); 254 void DecodeType7(Instr* instr); 255 void DecodeUnconditional(Instr* instr); 256 257 // Support for VFP. 258 void DecodeTypeVFP(Instr* instr); 259 void DecodeType6CoprocessorIns(Instr* instr); 260 261 void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr); 262 void DecodeVCMP(Instr* instr); 263 void DecodeVCVTBetweenDoubleAndSingle(Instr* instr); 264 void DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr); 265 266 // Executes one instruction. 267 void InstructionDecode(Instr* instr); 268 269 // ICache. 270 static void CheckICache(Instr* instr); 271 static void FlushOnePage(intptr_t start, int size); 272 static CachePage* GetCachePage(void* page); 273 274 // Runtime call support. 275 static void* RedirectExternalReference(void* external_function, 276 bool fp_return); 277 278 // For use in calls that take two double values, constructed from r0, r1, r2 279 // and r3. 280 void GetFpArgs(double* x, double* y); 281 void SetFpResult(const double& result); 282 void TrashCallerSaveRegisters(); 283 284 // Architecture state. 285 // Saturating instructions require a Q flag to indicate saturation. 286 // There is currently no way to read the CPSR directly, and thus read the Q 287 // flag, so this is left unimplemented. 288 int32_t registers_[16]; 289 bool n_flag_; 290 bool z_flag_; 291 bool c_flag_; 292 bool v_flag_; 293 294 // VFP architecture state. 295 unsigned int vfp_register[num_s_registers]; 296 bool n_flag_FPSCR_; 297 bool z_flag_FPSCR_; 298 bool c_flag_FPSCR_; 299 bool v_flag_FPSCR_; 300 301 // VFP FP exception flags architecture state. 302 bool inv_op_vfp_flag_; 303 bool div_zero_vfp_flag_; 304 bool overflow_vfp_flag_; 305 bool underflow_vfp_flag_; 306 bool inexact_vfp_flag_; 307 308 // Simulator support. 309 char* stack_; 310 bool pc_modified_; 311 int icount_; 312 static bool initialized_; 313 314 // Icache simulation 315 static v8::internal::HashMap* i_cache_; 316 317 // Registered breakpoints. 318 Instr* break_pc_; 319 instr_t break_instr_; 320}; 321 322} } // namespace assembler::arm 323 324 325namespace v8 { 326namespace internal { 327 328// When running with the simulator transition into simulated execution at this 329// point. 330#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 331 reinterpret_cast<Object*>(assembler::arm::Simulator::current()->Call( \ 332 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) 333 334#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ 335 assembler::arm::Simulator::current()->Call( \ 336 FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) 337 338#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 339 try_catch_address == \ 340 NULL ? NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) 341 342 343// The simulator has its own stack. Thus it has a different stack limit from 344// the C-based native code. Setting the c_limit to indicate a very small 345// stack cause stack overflow errors, since the simulator ignores the input. 346// This is unlikely to be an issue in practice, though it might cause testing 347// trouble down the line. 348class SimulatorStack : public v8::internal::AllStatic { 349 public: 350 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) { 351 return assembler::arm::Simulator::current()->StackLimit(); 352 } 353 354 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 355 assembler::arm::Simulator* sim = assembler::arm::Simulator::current(); 356 return sim->PushAddress(try_catch_address); 357 } 358 359 static inline void UnregisterCTryCatch() { 360 assembler::arm::Simulator::current()->PopAddress(); 361 } 362}; 363 364} } // namespace v8::internal 365 366#endif // !defined(USE_SIMULATOR) 367#endif // V8_ARM_SIMULATOR_ARM_H_ 368