Home | History | Annotate | Download | only in mips
      1 // Copyright 2010 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 MIPS instructions if we are not generating a native
     30 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
     31 // on 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 MIPS HW platform.
     35 
     36 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
     37 #define V8_MIPS_SIMULATOR_MIPS_H_
     38 
     39 #include "allocation.h"
     40 
     41 #if defined(__mips)
     42 
     43 // When running without a simulator we call the entry directly.
     44 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
     45   entry(p0, p1, p2, p3, p4);
     46 
     47 // The stack limit beyond which we will throw stack overflow errors in
     48 // generated code. Because generated code on mips uses the C stack, we
     49 // just use the C stack limit.
     50 class SimulatorStack : public v8::internal::AllStatic {
     51  public:
     52   static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
     53     return c_limit;
     54   }
     55 
     56   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
     57     return try_catch_address;
     58   }
     59 
     60   static inline void UnregisterCTryCatch() { }
     61 };
     62 
     63 // Calculated the stack limit beyond which we will throw stack overflow errors.
     64 // This macro must be called from a C++ method. It relies on being able to take
     65 // the address of "this" to get a value on the current execution stack and then
     66 // calculates the stack limit based on that value.
     67 // NOTE: The check for overflow is not safe as there is no guarantee that the
     68 // running thread has its stack in all memory up to address 0x00000000.
     69 #define GENERATED_CODE_STACK_LIMIT(limit) \
     70   (reinterpret_cast<uintptr_t>(this) >= limit ? \
     71       reinterpret_cast<uintptr_t>(this) - limit : 0)
     72 
     73 // Call the generated regexp code directly. The entry function pointer should
     74 // expect seven int/pointer sized arguments and return an int.
     75 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
     76   entry(p0, p1, p2, p3, p4, p5, p6)
     77 
     78 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
     79   reinterpret_cast<TryCatch*>(try_catch_address)
     80 
     81 
     82 #else   // #if defined(__mips)
     83 
     84 // When running with the simulator transition into simulated execution at this
     85 // point.
     86 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
     87   reinterpret_cast<Object*>(\
     88       assembler::mips::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \
     89                                                   p0, p1, p2, p3, p4))
     90 
     91 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
     92   assembler::mips::Simulator::current()->Call(\
     93     FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6)
     94 
     95 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
     96   try_catch_address == NULL ? \
     97       NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
     98 
     99 
    100 namespace assembler {
    101 namespace mips {
    102 
    103 class Simulator {
    104  public:
    105   friend class Debugger;
    106 
    107   // Registers are declared in order. See SMRL chapter 2.
    108   enum Register {
    109     no_reg = -1,
    110     zero_reg = 0,
    111     at,
    112     v0, v1,
    113     a0, a1, a2, a3,
    114     t0, t1, t2, t3, t4, t5, t6, t7,
    115     s0, s1, s2, s3, s4, s5, s6, s7,
    116     t8, t9,
    117     k0, k1,
    118     gp,
    119     sp,
    120     s8,
    121     ra,
    122     // LO, HI, and pc
    123     LO,
    124     HI,
    125     pc,   // pc must be the last register.
    126     kNumSimuRegisters,
    127     // aliases
    128     fp = s8
    129   };
    130 
    131   // Coprocessor registers.
    132   // Generated code will always use doubles. So we will only use even registers.
    133   enum FPURegister {
    134     f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
    135     f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters
    136     f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
    137     f26, f27, f28, f29, f30, f31,
    138     kNumFPURegisters
    139   };
    140 
    141   Simulator();
    142   ~Simulator();
    143 
    144   // The currently executing Simulator instance. Potentially there can be one
    145   // for each native thread.
    146   static Simulator* current();
    147 
    148   // Accessors for register state. Reading the pc value adheres to the MIPS
    149   // architecture specification and is off by a 8 from the currently executing
    150   // instruction.
    151   void set_register(int reg, int32_t value);
    152   int32_t get_register(int reg) const;
    153   // Same for FPURegisters
    154   void set_fpu_register(int fpureg, int32_t value);
    155   void set_fpu_register_double(int fpureg, double value);
    156   int32_t get_fpu_register(int fpureg) const;
    157   double get_fpu_register_double(int fpureg) const;
    158 
    159   // Special case of set_register and get_register to access the raw PC value.
    160   void set_pc(int32_t value);
    161   int32_t get_pc() const;
    162 
    163   // Accessor to the internal simulator stack area.
    164   uintptr_t StackLimit() const;
    165 
    166   // Executes MIPS instructions until the PC reaches end_sim_pc.
    167   void Execute();
    168 
    169   // Call on program start.
    170   static void Initialize();
    171 
    172   // V8 generally calls into generated JS code with 5 parameters and into
    173   // generated RegExp code with 7 parameters. This is a convenience function,
    174   // which sets up the simulator state and grabs the result on return.
    175   int32_t Call(byte_* entry, int argument_count, ...);
    176 
    177   // Push an address onto the JS stack.
    178   uintptr_t PushAddress(uintptr_t address);
    179 
    180   // Pop an address from the JS stack.
    181   uintptr_t PopAddress();
    182 
    183  private:
    184   enum special_values {
    185     // Known bad pc value to ensure that the simulator does not execute
    186     // without being properly setup.
    187     bad_ra = -1,
    188     // A pc value used to signal the simulator to stop execution.  Generally
    189     // the ra is set to this value on transition from native C code to
    190     // simulated execution, so that the simulator can "return" to the native
    191     // C code.
    192     end_sim_pc = -2,
    193     // Unpredictable value.
    194     Unpredictable = 0xbadbeaf
    195   };
    196 
    197   // Unsupported instructions use Format to print an error and stop execution.
    198   void Format(Instruction* instr, const char* format);
    199 
    200   // Read and write memory.
    201   inline uint32_t ReadBU(int32_t addr);
    202   inline int32_t ReadB(int32_t addr);
    203   inline void WriteB(int32_t addr, uint8_t value);
    204   inline void WriteB(int32_t addr, int8_t value);
    205 
    206   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
    207   inline int16_t ReadH(int32_t addr, Instruction* instr);
    208   // Note: Overloaded on the sign of the value.
    209   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
    210   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
    211 
    212   inline int ReadW(int32_t addr, Instruction* instr);
    213   inline void WriteW(int32_t addr, int value, Instruction* instr);
    214 
    215   inline double ReadD(int32_t addr, Instruction* instr);
    216   inline void WriteD(int32_t addr, double value, Instruction* instr);
    217 
    218   // Operations depending on endianness.
    219   // Get Double Higher / Lower word.
    220   inline int32_t GetDoubleHIW(double* addr);
    221   inline int32_t GetDoubleLOW(double* addr);
    222   // Set Double Higher / Lower word.
    223   inline int32_t SetDoubleHIW(double* addr);
    224   inline int32_t SetDoubleLOW(double* addr);
    225 
    226 
    227   // Executing is handled based on the instruction type.
    228   void DecodeTypeRegister(Instruction* instr);
    229   void DecodeTypeImmediate(Instruction* instr);
    230   void DecodeTypeJump(Instruction* instr);
    231 
    232   // Used for breakpoints and traps.
    233   void SoftwareInterrupt(Instruction* instr);
    234 
    235   // Executes one instruction.
    236   void InstructionDecode(Instruction* instr);
    237   // Execute one instruction placed in a branch delay slot.
    238   void BranchDelayInstructionDecode(Instruction* instr) {
    239     if (instr->IsForbiddenInBranchDelay()) {
    240       V8_Fatal(__FILE__, __LINE__,
    241                "Eror:Unexpected %i opcode in a branch delay slot.",
    242                instr->OpcodeField());
    243     }
    244     InstructionDecode(instr);
    245   }
    246 
    247   enum Exception {
    248     none,
    249     kIntegerOverflow,
    250     kIntegerUnderflow,
    251     kDivideByZero,
    252     kNumExceptions
    253   };
    254   int16_t exceptions[kNumExceptions];
    255 
    256   // Exceptions.
    257   void SignalExceptions();
    258 
    259   // Runtime call support.
    260   static void* RedirectExternalReference(void* external_function,
    261                                          bool fp_return);
    262 
    263   // Used for real time calls that takes two double values as arguments and
    264   // returns a double.
    265   void SetFpResult(double result);
    266 
    267   // Architecture state.
    268   // Registers.
    269   int32_t registers_[kNumSimuRegisters];
    270   // Coprocessor Registers.
    271   int32_t FPUregisters_[kNumFPURegisters];
    272 
    273   // Simulator support.
    274   char* stack_;
    275   bool pc_modified_;
    276   int icount_;
    277   static bool initialized_;
    278 
    279   // Registered breakpoints.
    280   Instruction* break_pc_;
    281   Instr break_instr_;
    282 };
    283 
    284 } }   // namespace assembler::mips
    285 
    286 
    287 // The simulator has its own stack. Thus it has a different stack limit from
    288 // the C-based native code.  Setting the c_limit to indicate a very small
    289 // stack cause stack overflow errors, since the simulator ignores the input.
    290 // This is unlikely to be an issue in practice, though it might cause testing
    291 // trouble down the line.
    292 class SimulatorStack : public v8::internal::AllStatic {
    293  public:
    294   static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
    295     return assembler::mips::Simulator::current()->StackLimit();
    296   }
    297 
    298   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
    299     assembler::mips::Simulator* sim = assembler::mips::Simulator::current();
    300     return sim->PushAddress(try_catch_address);
    301   }
    302 
    303   static inline void UnregisterCTryCatch() {
    304     assembler::mips::Simulator::current()->PopAddress();
    305   }
    306 };
    307 
    308 #endif  // defined(__mips)
    309 
    310 #endif  // V8_MIPS_SIMULATOR_MIPS_H_
    311 
    312