simulator-mips.h revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
1// Copyright 2011 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#include "constants-mips.h"
41
42#if !defined(USE_SIMULATOR)
43// Running without a simulator on a native mips platform.
44
45namespace v8 {
46namespace internal {
47
48// When running without a simulator we call the entry directly.
49#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
50  entry(p0, p1, p2, p3, p4)
51
52typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
53                                   void*, int*, Address, int, Isolate*);
54
55
56// Call the generated regexp code directly. The code at the entry address
57// should act as a function matching the type arm_regexp_matcher.
58// The fifth argument is a dummy that reserves the space used for
59// the return address added by the ExitFrame in native calls.
60#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
61  (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
62      p0, p1, p2, p3, NULL, p4, p5, p6, p7))
63
64#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
65  reinterpret_cast<TryCatch*>(try_catch_address)
66
67// The stack limit beyond which we will throw stack overflow errors in
68// generated code. Because generated code on mips uses the C stack, we
69// just use the C stack limit.
70class SimulatorStack : public v8::internal::AllStatic {
71 public:
72  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
73                                            uintptr_t c_limit) {
74    return c_limit;
75  }
76
77  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
78    return try_catch_address;
79  }
80
81  static inline void UnregisterCTryCatch() { }
82};
83
84} }  // namespace v8::internal
85
86// Calculated the stack limit beyond which we will throw stack overflow errors.
87// This macro must be called from a C++ method. It relies on being able to take
88// the address of "this" to get a value on the current execution stack and then
89// calculates the stack limit based on that value.
90// NOTE: The check for overflow is not safe as there is no guarantee that the
91// running thread has its stack in all memory up to address 0x00000000.
92#define GENERATED_CODE_STACK_LIMIT(limit) \
93  (reinterpret_cast<uintptr_t>(this) >= limit ? \
94      reinterpret_cast<uintptr_t>(this) - limit : 0)
95
96#else  // !defined(USE_SIMULATOR)
97// Running with a simulator.
98
99#include "hashmap.h"
100#include "assembler.h"
101
102namespace v8 {
103namespace internal {
104
105// -----------------------------------------------------------------------------
106// Utility functions
107
108class CachePage {
109 public:
110  static const int LINE_VALID = 0;
111  static const int LINE_INVALID = 1;
112
113  static const int kPageShift = 12;
114  static const int kPageSize = 1 << kPageShift;
115  static const int kPageMask = kPageSize - 1;
116  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
117  static const int kLineLength = 1 << kLineShift;
118  static const int kLineMask = kLineLength - 1;
119
120  CachePage() {
121    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
122  }
123
124  char* ValidityByte(int offset) {
125    return &validity_map_[offset >> kLineShift];
126  }
127
128  char* CachedData(int offset) {
129    return &data_[offset];
130  }
131
132 private:
133  char data_[kPageSize];   // The cached data.
134  static const int kValidityMapSize = kPageSize >> kLineShift;
135  char validity_map_[kValidityMapSize];  // One byte per line.
136};
137
138class Simulator {
139 public:
140  friend class MipsDebugger;
141
142  // Registers are declared in order. See SMRL chapter 2.
143  enum Register {
144    no_reg = -1,
145    zero_reg = 0,
146    at,
147    v0, v1,
148    a0, a1, a2, a3,
149    t0, t1, t2, t3, t4, t5, t6, t7,
150    s0, s1, s2, s3, s4, s5, s6, s7,
151    t8, t9,
152    k0, k1,
153    gp,
154    sp,
155    s8,
156    ra,
157    // LO, HI, and pc.
158    LO,
159    HI,
160    pc,   // pc must be the last register.
161    kNumSimuRegisters,
162    // aliases
163    fp = s8
164  };
165
166  // Coprocessor registers.
167  // Generated code will always use doubles. So we will only use even registers.
168  enum FPURegister {
169    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
170    f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
171    f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
172    f26, f27, f28, f29, f30, f31,
173    kNumFPURegisters
174  };
175
176  explicit Simulator(Isolate* isolate);
177  ~Simulator();
178
179  // The currently executing Simulator instance. Potentially there can be one
180  // for each native thread.
181  static Simulator* current(v8::internal::Isolate* isolate);
182
183  // Accessors for register state. Reading the pc value adheres to the MIPS
184  // architecture specification and is off by a 8 from the currently executing
185  // instruction.
186  void set_register(int reg, int32_t value);
187  int32_t get_register(int reg) const;
188  // Same for FPURegisters.
189  void set_fpu_register(int fpureg, int32_t value);
190  void set_fpu_register_float(int fpureg, float value);
191  void set_fpu_register_double(int fpureg, double value);
192  int32_t get_fpu_register(int fpureg) const;
193  int64_t get_fpu_register_long(int fpureg) const;
194  float get_fpu_register_float(int fpureg) const;
195  double get_fpu_register_double(int fpureg) const;
196  void set_fcsr_bit(uint32_t cc, bool value);
197  bool test_fcsr_bit(uint32_t cc);
198  bool set_fcsr_round_error(double original, double rounded);
199
200  // Special case of set_register and get_register to access the raw PC value.
201  void set_pc(int32_t value);
202  int32_t get_pc() const;
203
204  // Accessor to the internal simulator stack area.
205  uintptr_t StackLimit() const;
206
207  // Executes MIPS instructions until the PC reaches end_sim_pc.
208  void Execute();
209
210  // Call on program start.
211  static void Initialize(Isolate* isolate);
212
213  // V8 generally calls into generated JS code with 5 parameters and into
214  // generated RegExp code with 7 parameters. This is a convenience function,
215  // which sets up the simulator state and grabs the result on return.
216  int32_t Call(byte* entry, int argument_count, ...);
217
218  // Push an address onto the JS stack.
219  uintptr_t PushAddress(uintptr_t address);
220
221  // Pop an address from the JS stack.
222  uintptr_t PopAddress();
223
224  // ICache checking.
225  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
226                          size_t size);
227
228  // Returns true if pc register contains one of the 'special_values' defined
229  // below (bad_ra, end_sim_pc).
230  bool has_bad_pc() const;
231
232 private:
233  enum special_values {
234    // Known bad pc value to ensure that the simulator does not execute
235    // without being properly setup.
236    bad_ra = -1,
237    // A pc value used to signal the simulator to stop execution.  Generally
238    // the ra is set to this value on transition from native C code to
239    // simulated execution, so that the simulator can "return" to the native
240    // C code.
241    end_sim_pc = -2,
242    // Unpredictable value.
243    Unpredictable = 0xbadbeaf
244  };
245
246  // Unsupported instructions use Format to print an error and stop execution.
247  void Format(Instruction* instr, const char* format);
248
249  // Read and write memory.
250  inline uint32_t ReadBU(int32_t addr);
251  inline int32_t ReadB(int32_t addr);
252  inline void WriteB(int32_t addr, uint8_t value);
253  inline void WriteB(int32_t addr, int8_t value);
254
255  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
256  inline int16_t ReadH(int32_t addr, Instruction* instr);
257  // Note: Overloaded on the sign of the value.
258  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
259  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
260
261  inline int ReadW(int32_t addr, Instruction* instr);
262  inline void WriteW(int32_t addr, int value, Instruction* instr);
263
264  inline double ReadD(int32_t addr, Instruction* instr);
265  inline void WriteD(int32_t addr, double value, Instruction* instr);
266
267  // Operations depending on endianness.
268  // Get Double Higher / Lower word.
269  inline int32_t GetDoubleHIW(double* addr);
270  inline int32_t GetDoubleLOW(double* addr);
271  // Set Double Higher / Lower word.
272  inline int32_t SetDoubleHIW(double* addr);
273  inline int32_t SetDoubleLOW(double* addr);
274
275  // Executing is handled based on the instruction type.
276  void DecodeTypeRegister(Instruction* instr);
277
278  // Helper function for DecodeTypeRegister.
279  void ConfigureTypeRegister(Instruction* instr,
280                             int32_t& alu_out,
281                             int64_t& i64hilo,
282                             uint64_t& u64hilo,
283                             int32_t& next_pc,
284                             bool& do_interrupt);
285
286  void DecodeTypeImmediate(Instruction* instr);
287  void DecodeTypeJump(Instruction* instr);
288
289  // Used for breakpoints and traps.
290  void SoftwareInterrupt(Instruction* instr);
291
292  // Stop helper functions.
293  bool IsWatchpoint(uint32_t code);
294  void PrintWatchpoint(uint32_t code);
295  void HandleStop(uint32_t code, Instruction* instr);
296  bool IsStopInstruction(Instruction* instr);
297  bool IsEnabledStop(uint32_t code);
298  void EnableStop(uint32_t code);
299  void DisableStop(uint32_t code);
300  void IncreaseStopCounter(uint32_t code);
301  void PrintStopInfo(uint32_t code);
302
303
304  // Executes one instruction.
305  void InstructionDecode(Instruction* instr);
306  // Execute one instruction placed in a branch delay slot.
307  void BranchDelayInstructionDecode(Instruction* instr) {
308    if (instr->IsForbiddenInBranchDelay()) {
309      V8_Fatal(__FILE__, __LINE__,
310               "Eror:Unexpected %i opcode in a branch delay slot.",
311               instr->OpcodeValue());
312    }
313    InstructionDecode(instr);
314  }
315
316  // ICache.
317  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
318  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
319                           int size);
320  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
321
322  enum Exception {
323    none,
324    kIntegerOverflow,
325    kIntegerUnderflow,
326    kDivideByZero,
327    kNumExceptions
328  };
329  int16_t exceptions[kNumExceptions];
330
331  // Exceptions.
332  void SignalExceptions();
333
334  // Runtime call support.
335  static void* RedirectExternalReference(void* external_function,
336                                         ExternalReference::Type type);
337
338  // For use in calls that take double value arguments.
339  void GetFpArgs(double* x, double* y);
340  void GetFpArgs(double* x);
341  void GetFpArgs(double* x, int32_t* y);
342  void SetFpResult(const double& result);
343
344
345  // Architecture state.
346  // Registers.
347  int32_t registers_[kNumSimuRegisters];
348  // Coprocessor Registers.
349  int32_t FPUregisters_[kNumFPURegisters];
350  // FPU control register.
351  uint32_t FCSR_;
352
353  // Simulator support.
354  // Allocate 1MB for stack.
355  static const size_t stack_size_ = 1 * 1024*1024;
356  char* stack_;
357  bool pc_modified_;
358  int icount_;
359  int break_count_;
360
361  // Icache simulation.
362  v8::internal::HashMap* i_cache_;
363
364  v8::internal::Isolate* isolate_;
365
366  // Registered breakpoints.
367  Instruction* break_pc_;
368  Instr break_instr_;
369
370  // Stop is disabled if bit 31 is set.
371  static const uint32_t kStopDisabledBit = 1 << 31;
372
373  // A stop is enabled, meaning the simulator will stop when meeting the
374  // instruction, if bit 31 of watched_stops[code].count is unset.
375  // The value watched_stops[code].count & ~(1 << 31) indicates how many times
376  // the breakpoint was hit or gone through.
377  struct StopCountAndDesc {
378    uint32_t count;
379    char* desc;
380  };
381  StopCountAndDesc watched_stops[kMaxStopCode + 1];
382};
383
384
385// When running with the simulator transition into simulated execution at this
386// point.
387#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
388    reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
389      FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
390
391#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
392    Simulator::current(Isolate::Current())->Call( \
393        entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
394
395#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
396  try_catch_address == NULL ?                                                  \
397      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
398
399
400// The simulator has its own stack. Thus it has a different stack limit from
401// the C-based native code.  Setting the c_limit to indicate a very small
402// stack cause stack overflow errors, since the simulator ignores the input.
403// This is unlikely to be an issue in practice, though it might cause testing
404// trouble down the line.
405class SimulatorStack : public v8::internal::AllStatic {
406 public:
407  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
408                                            uintptr_t c_limit) {
409    return Simulator::current(isolate)->StackLimit();
410  }
411
412  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
413    Simulator* sim = Simulator::current(Isolate::Current());
414    return sim->PushAddress(try_catch_address);
415  }
416
417  static inline void UnregisterCTryCatch() {
418    Simulator::current(Isolate::Current())->PopAddress();
419  }
420};
421
422} }  // namespace v8::internal
423
424#endif  // !defined(USE_SIMULATOR)
425#endif  // V8_MIPS_SIMULATOR_MIPS_H_
426