michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: // Copyright 2012 the V8 project authors. All rights reserved. michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following michael@0: // disclaimer in the documentation and/or other materials provided michael@0: // with the distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived michael@0: // from this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #ifndef jit_arm_Simulator_arm_h michael@0: #define jit_arm_Simulator_arm_h michael@0: michael@0: #ifdef JS_ARM_SIMULATOR michael@0: michael@0: #include "jit/arm/Architecture-arm.h" michael@0: #include "jit/IonTypes.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class SimulatorRuntime; michael@0: SimulatorRuntime *CreateSimulatorRuntime(); michael@0: void DestroySimulatorRuntime(SimulatorRuntime *srt); michael@0: michael@0: // VFP rounding modes. See ARM DDI 0406B Page A2-29. michael@0: enum VFPRoundingMode { michael@0: SimRN = 0 << 22, // Round to Nearest. michael@0: SimRP = 1 << 22, // Round towards Plus Infinity. michael@0: SimRM = 2 << 22, // Round towards Minus Infinity. michael@0: SimRZ = 3 << 22, // Round towards zero. michael@0: michael@0: // Aliases. michael@0: kRoundToNearest = SimRN, michael@0: kRoundToPlusInf = SimRP, michael@0: kRoundToMinusInf = SimRM, michael@0: kRoundToZero = SimRZ michael@0: }; michael@0: michael@0: const uint32_t kVFPRoundingModeMask = 3 << 22; michael@0: michael@0: typedef int32_t Instr; michael@0: class SimInstruction; michael@0: michael@0: class Simulator michael@0: { michael@0: friend class Redirection; michael@0: michael@0: public: michael@0: friend class ArmDebugger; michael@0: enum Register { michael@0: no_reg = -1, michael@0: r0 = 0, r1, r2, r3, r4, r5, r6, r7, michael@0: r8, r9, r10, r11, r12, r13, r14, r15, michael@0: num_registers, michael@0: sp = 13, michael@0: lr = 14, michael@0: pc = 15, michael@0: s0 = 0, s1, s2, s3, s4, s5, s6, s7, michael@0: s8, s9, s10, s11, s12, s13, s14, s15, michael@0: s16, s17, s18, s19, s20, s21, s22, s23, michael@0: s24, s25, s26, s27, s28, s29, s30, s31, michael@0: num_s_registers = 32, michael@0: d0 = 0, d1, d2, d3, d4, d5, d6, d7, michael@0: d8, d9, d10, d11, d12, d13, d14, d15, michael@0: d16, d17, d18, d19, d20, d21, d22, d23, michael@0: d24, d25, d26, d27, d28, d29, d30, d31, michael@0: num_d_registers = 32, michael@0: q0 = 0, q1, q2, q3, q4, q5, q6, q7, michael@0: q8, q9, q10, q11, q12, q13, q14, q15, michael@0: num_q_registers = 16 michael@0: }; michael@0: michael@0: explicit Simulator(SimulatorRuntime *srt); michael@0: ~Simulator(); michael@0: michael@0: // The currently executing Simulator instance. Potentially there can be one michael@0: // for each native thread. michael@0: static Simulator *Current(); michael@0: michael@0: static inline uintptr_t StackLimit() { michael@0: return Simulator::Current()->stackLimit(); michael@0: } michael@0: michael@0: // Accessors for register state. Reading the pc value adheres to the ARM michael@0: // architecture specification and is off by a 8 from the currently executing michael@0: // instruction. michael@0: void set_register(int reg, int32_t value); michael@0: int32_t get_register(int reg) const; michael@0: double get_double_from_register_pair(int reg); michael@0: void set_register_pair_from_double(int reg, double* value); michael@0: void set_dw_register(int dreg, const int* dbl); michael@0: michael@0: // Support for VFP. michael@0: void get_d_register(int dreg, uint64_t* value); michael@0: void set_d_register(int dreg, const uint64_t* value); michael@0: void get_d_register(int dreg, uint32_t* value); michael@0: void set_d_register(int dreg, const uint32_t* value); michael@0: void get_q_register(int qreg, uint64_t* value); michael@0: void set_q_register(int qreg, const uint64_t* value); michael@0: void get_q_register(int qreg, uint32_t* value); michael@0: void set_q_register(int qreg, const uint32_t* value); michael@0: void set_s_register(int reg, unsigned int value); michael@0: unsigned int get_s_register(int reg) const; michael@0: michael@0: void set_d_register_from_double(int dreg, const double& dbl) { michael@0: setVFPRegister(dreg, dbl); michael@0: } michael@0: double get_double_from_d_register(int dreg) { michael@0: return getFromVFPRegister(dreg); michael@0: } michael@0: void set_s_register_from_float(int sreg, const float flt) { michael@0: setVFPRegister(sreg, flt); michael@0: } michael@0: float get_float_from_s_register(int sreg) { michael@0: return getFromVFPRegister(sreg); michael@0: } michael@0: void set_s_register_from_sinteger(int sreg, const int sint) { michael@0: setVFPRegister(sreg, sint); michael@0: } michael@0: int get_sinteger_from_s_register(int sreg) { michael@0: return getFromVFPRegister(sreg); michael@0: } michael@0: michael@0: // Special case of set_register and get_register to access the raw PC value. michael@0: void set_pc(int32_t value); michael@0: int32_t get_pc() const; michael@0: michael@0: void set_resume_pc(int32_t value) { michael@0: resume_pc_ = value; michael@0: } michael@0: michael@0: uintptr_t stackLimit() const; michael@0: bool overRecursed(uintptr_t newsp = 0) const; michael@0: bool overRecursedWithExtra(uint32_t extra) const; michael@0: michael@0: // Executes ARM instructions until the PC reaches end_sim_pc. michael@0: template michael@0: void execute(); michael@0: michael@0: // Sets up the simulator state and grabs the result on return. michael@0: int64_t call(uint8_t* entry, int argument_count, ...); michael@0: michael@0: // Debugger input. michael@0: void setLastDebuggerInput(char *input); michael@0: char *lastDebuggerInput() { return lastDebuggerInput_; } michael@0: michael@0: // Returns true if pc register contains one of the 'special_values' defined michael@0: // below (bad_lr, end_sim_pc). michael@0: bool has_bad_pc() const; michael@0: michael@0: private: michael@0: enum special_values { michael@0: // Known bad pc value to ensure that the simulator does not execute michael@0: // without being properly setup. michael@0: bad_lr = -1, michael@0: // A pc value used to signal the simulator to stop execution. Generally michael@0: // the lr is set to this value on transition from native C code to michael@0: // simulated execution, so that the simulator can "return" to the native michael@0: // C code. michael@0: end_sim_pc = -2 michael@0: }; michael@0: michael@0: // Checks if the current instruction should be executed based on its michael@0: // condition bits. michael@0: inline bool conditionallyExecute(SimInstruction* instr); michael@0: michael@0: // Helper functions to set the conditional flags in the architecture state. michael@0: void setNZFlags(int32_t val); michael@0: void setCFlag(bool val); michael@0: void setVFlag(bool val); michael@0: bool carryFrom(int32_t left, int32_t right, int32_t carry = 0); michael@0: bool borrowFrom(int32_t left, int32_t right); michael@0: bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition); michael@0: michael@0: inline int getCarry() { return c_flag_ ? 1 : 0; }; michael@0: michael@0: // Support for VFP. michael@0: void compute_FPSCR_Flags(double val1, double val2); michael@0: void copy_FPSCR_to_APSR(); michael@0: inline double canonicalizeNaN(double value); michael@0: michael@0: // Helper functions to decode common "addressing" modes michael@0: int32_t getShiftRm(SimInstruction *instr, bool* carry_out); michael@0: int32_t getImm(SimInstruction *instr, bool* carry_out); michael@0: int32_t processPU(SimInstruction *instr, int num_regs, int operand_size, michael@0: intptr_t *start_address, intptr_t *end_address); michael@0: void handleRList(SimInstruction *instr, bool load); michael@0: void handleVList(SimInstruction *inst); michael@0: void softwareInterrupt(SimInstruction *instr); michael@0: michael@0: // Stop helper functions. michael@0: inline bool isStopInstruction(SimInstruction *instr); michael@0: inline bool isWatchedStop(uint32_t bkpt_code); michael@0: inline bool isEnabledStop(uint32_t bkpt_code); michael@0: inline void enableStop(uint32_t bkpt_code); michael@0: inline void disableStop(uint32_t bkpt_code); michael@0: inline void increaseStopCounter(uint32_t bkpt_code); michael@0: void printStopInfo(uint32_t code); michael@0: michael@0: // Read and write memory. michael@0: inline uint8_t readBU(int32_t addr); michael@0: inline int8_t readB(int32_t addr); michael@0: inline void writeB(int32_t addr, uint8_t value); michael@0: inline void writeB(int32_t addr, int8_t value); michael@0: michael@0: inline uint16_t readHU(int32_t addr, SimInstruction *instr); michael@0: inline int16_t readH(int32_t addr, SimInstruction *instr); michael@0: // Note: Overloaded on the sign of the value. michael@0: inline void writeH(int32_t addr, uint16_t value, SimInstruction *instr); michael@0: inline void writeH(int32_t addr, int16_t value, SimInstruction *instr); michael@0: michael@0: inline int readW(int32_t addr, SimInstruction *instr); michael@0: inline void writeW(int32_t addr, int value, SimInstruction *instr); michael@0: michael@0: int32_t *readDW(int32_t addr); michael@0: void writeDW(int32_t addr, int32_t value1, int32_t value2); michael@0: michael@0: // Executing is handled based on the instruction type. michael@0: // Both type 0 and type 1 rolled into one. michael@0: void decodeType01(SimInstruction *instr); michael@0: void decodeType2(SimInstruction *instr); michael@0: void decodeType3(SimInstruction *instr); michael@0: void decodeType4(SimInstruction *instr); michael@0: void decodeType5(SimInstruction *instr); michael@0: void decodeType6(SimInstruction *instr); michael@0: void decodeType7(SimInstruction *instr); michael@0: michael@0: // Support for VFP. michael@0: void decodeTypeVFP(SimInstruction *instr); michael@0: void decodeType6CoprocessorIns(SimInstruction *instr); michael@0: void decodeSpecialCondition(SimInstruction *instr); michael@0: michael@0: void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr); michael@0: void decodeVCMP(SimInstruction *instr); michael@0: void decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr); michael@0: void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr); michael@0: void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr); michael@0: michael@0: // Executes one instruction. michael@0: void instructionDecode(SimInstruction *instr); michael@0: michael@0: public: michael@0: static bool ICacheCheckingEnabled; michael@0: static void FlushICache(void *start, size_t size); michael@0: michael@0: static int64_t StopSimAt; michael@0: michael@0: // Runtime call support. michael@0: static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type); michael@0: michael@0: private: michael@0: // Handle arguments and return value for runtime FP functions. michael@0: void getFpArgs(double *x, double *y, int32_t *z); michael@0: void setCallResultDouble(double result); michael@0: void setCallResultFloat(float result); michael@0: void setCallResult(int64_t res); michael@0: void scratchVolatileRegisters(bool scratchFloat = true); michael@0: michael@0: template michael@0: ReturnType getFromVFPRegister(int reg_index); michael@0: michael@0: template michael@0: void setVFPRegister(int reg_index, const InputType& value); michael@0: michael@0: void callInternal(uint8_t* entry); michael@0: michael@0: // Architecture state. michael@0: // Saturating instructions require a Q flag to indicate saturation. michael@0: // There is currently no way to read the CPSR directly, and thus read the Q michael@0: // flag, so this is left unimplemented. michael@0: int32_t registers_[16]; michael@0: bool n_flag_; michael@0: bool z_flag_; michael@0: bool c_flag_; michael@0: bool v_flag_; michael@0: michael@0: // VFP architecture state. michael@0: uint32_t vfp_registers_[num_d_registers * 2]; michael@0: bool n_flag_FPSCR_; michael@0: bool z_flag_FPSCR_; michael@0: bool c_flag_FPSCR_; michael@0: bool v_flag_FPSCR_; michael@0: michael@0: // VFP rounding mode. See ARM DDI 0406B Page A2-29. michael@0: VFPRoundingMode FPSCR_rounding_mode_; michael@0: bool FPSCR_default_NaN_mode_; michael@0: michael@0: // VFP FP exception flags architecture state. michael@0: bool inv_op_vfp_flag_; michael@0: bool div_zero_vfp_flag_; michael@0: bool overflow_vfp_flag_; michael@0: bool underflow_vfp_flag_; michael@0: bool inexact_vfp_flag_; michael@0: michael@0: // Simulator support. michael@0: char *stack_; michael@0: bool pc_modified_; michael@0: int64_t icount_; michael@0: michael@0: int32_t resume_pc_; michael@0: michael@0: // Debugger input. michael@0: char *lastDebuggerInput_; michael@0: michael@0: // Registered breakpoints. michael@0: SimInstruction *break_pc_; michael@0: Instr break_instr_; michael@0: michael@0: SimulatorRuntime *srt_; michael@0: michael@0: // A stop is watched if its code is less than kNumOfWatchedStops. michael@0: // Only watched stops support enabling/disabling and the counter feature. michael@0: static const uint32_t kNumOfWatchedStops = 256; michael@0: michael@0: // Breakpoint is disabled if bit 31 is set. michael@0: static const uint32_t kStopDisabledBit = 1 << 31; michael@0: michael@0: // A stop is enabled, meaning the simulator will stop when meeting the michael@0: // instruction, if bit 31 of watched_stops_[code].count is unset. michael@0: // The value watched_stops_[code].count & ~(1 << 31) indicates how many times michael@0: // the breakpoint was hit or gone through. michael@0: struct StopCountAndDesc { michael@0: uint32_t count; michael@0: char *desc; michael@0: }; michael@0: StopCountAndDesc watched_stops_[kNumOfWatchedStops]; michael@0: michael@0: public: michael@0: int64_t icount() { michael@0: return icount_; michael@0: } michael@0: michael@0: }; michael@0: michael@0: #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) { \ michael@0: js_ReportOverRecursed(cx); \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* JS_ARM_SIMULATOR */ michael@0: michael@0: #endif /* jit_arm_Simulator_arm_h */