1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5
6// Declares a Simulator for MIPS instructions if we are not generating a native
7// MIPS binary. This Simulator allows us to run and debug MIPS code generation
8// on regular desktop machines.
9// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
10// which will start execution in the Simulator or forwards to the real entry
11// on a MIPS HW platform.
12
13#ifndef V8_MIPS_SIMULATOR_MIPS_H_
14#define V8_MIPS_SIMULATOR_MIPS_H_
15
16#include "src/allocation.h"
17#include "src/mips64/constants-mips64.h"
18
19#if !defined(USE_SIMULATOR)
20// Running without a simulator on a native mips platform.
21
22namespace v8 {
23namespace internal {
24
25// When running without a simulator we call the entry directly.
26#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
27  entry(p0, p1, p2, p3, p4)
28
29
30// Call the generated regexp code directly. The code at the entry address
31// should act as a function matching the type arm_regexp_matcher.
32// The fifth (or ninth) argument is a dummy that reserves the space used for
33// the return address added by the ExitFrame in native calls.
34typedef int (*mips_regexp_matcher)(String* input,
35                                   int64_t start_offset,
36                                   const byte* input_start,
37                                   const byte* input_end,
38                                   int* output,
39                                   int64_t output_size,
40                                   Address stack_base,
41                                   int64_t direct_call,
42                                   void* return_address,
43                                   Isolate* isolate);
44
45#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
46                                   p7, p8)                                     \
47  (FUNCTION_CAST<mips_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7,   \
48                                             NULL, p8))
49
50
51// The stack limit beyond which we will throw stack overflow errors in
52// generated code. Because generated code on mips uses the C stack, we
53// just use the C stack limit.
54class SimulatorStack : public v8::internal::AllStatic {
55 public:
56  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
57                                            uintptr_t c_limit) {
58    return c_limit;
59  }
60
61  static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
62                                            uintptr_t try_catch_address) {
63    USE(isolate);
64    return try_catch_address;
65  }
66
67  static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); }
68};
69
70}  // namespace internal
71}  // namespace v8
72
73// Calculated the stack limit beyond which we will throw stack overflow errors.
74// This macro must be called from a C++ method. It relies on being able to take
75// the address of "this" to get a value on the current execution stack and then
76// calculates the stack limit based on that value.
77// NOTE: The check for overflow is not safe as there is no guarantee that the
78// running thread has its stack in all memory up to address 0x00000000.
79#define GENERATED_CODE_STACK_LIMIT(limit) \
80  (reinterpret_cast<uintptr_t>(this) >= limit ? \
81      reinterpret_cast<uintptr_t>(this) - limit : 0)
82
83#else  // !defined(USE_SIMULATOR)
84// Running with a simulator.
85
86#include "src/assembler.h"
87#include "src/base/hashmap.h"
88
89namespace v8 {
90namespace internal {
91
92// -----------------------------------------------------------------------------
93// Utility functions
94
95class CachePage {
96 public:
97  static const int LINE_VALID = 0;
98  static const int LINE_INVALID = 1;
99
100  static const int kPageShift = 12;
101  static const int kPageSize = 1 << kPageShift;
102  static const int kPageMask = kPageSize - 1;
103  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
104  static const int kLineLength = 1 << kLineShift;
105  static const int kLineMask = kLineLength - 1;
106
107  CachePage() {
108    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
109  }
110
111  char* ValidityByte(int offset) {
112    return &validity_map_[offset >> kLineShift];
113  }
114
115  char* CachedData(int offset) {
116    return &data_[offset];
117  }
118
119 private:
120  char data_[kPageSize];   // The cached data.
121  static const int kValidityMapSize = kPageSize >> kLineShift;
122  char validity_map_[kValidityMapSize];  // One byte per line.
123};
124
125class Simulator {
126 public:
127  friend class MipsDebugger;
128
129  // Registers are declared in order. See SMRL chapter 2.
130  enum Register {
131    no_reg = -1,
132    zero_reg = 0,
133    at,
134    v0, v1,
135    a0, a1, a2, a3, a4, a5, a6, a7,
136    t0, t1, t2, t3,
137    s0, s1, s2, s3, s4, s5, s6, s7,
138    t8, t9,
139    k0, k1,
140    gp,
141    sp,
142    s8,
143    ra,
144    // LO, HI, and pc.
145    LO,
146    HI,
147    pc,   // pc must be the last register.
148    kNumSimuRegisters,
149    // aliases
150    fp = s8
151  };
152
153  // Coprocessor registers.
154  // Generated code will always use doubles. So we will only use even registers.
155  enum FPURegister {
156    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
157    f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
158    f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
159    f26, f27, f28, f29, f30, f31,
160    kNumFPURegisters
161  };
162
163  explicit Simulator(Isolate* isolate);
164  ~Simulator();
165
166  // The currently executing Simulator instance. Potentially there can be one
167  // for each native thread.
168  static Simulator* current(v8::internal::Isolate* isolate);
169
170  // Accessors for register state. Reading the pc value adheres to the MIPS
171  // architecture specification and is off by a 8 from the currently executing
172  // instruction.
173  void set_register(int reg, int64_t value);
174  void set_register_word(int reg, int32_t value);
175  void set_dw_register(int dreg, const int* dbl);
176  int64_t get_register(int reg) const;
177  double get_double_from_register_pair(int reg);
178  // Same for FPURegisters.
179  void set_fpu_register(int fpureg, int64_t value);
180  void set_fpu_register_word(int fpureg, int32_t value);
181  void set_fpu_register_hi_word(int fpureg, int32_t value);
182  void set_fpu_register_float(int fpureg, float value);
183  void set_fpu_register_double(int fpureg, double value);
184  void set_fpu_register_invalid_result64(float original, float rounded);
185  void set_fpu_register_invalid_result(float original, float rounded);
186  void set_fpu_register_word_invalid_result(float original, float rounded);
187  void set_fpu_register_invalid_result64(double original, double rounded);
188  void set_fpu_register_invalid_result(double original, double rounded);
189  void set_fpu_register_word_invalid_result(double original, double rounded);
190  int64_t get_fpu_register(int fpureg) const;
191  int32_t get_fpu_register_word(int fpureg) const;
192  int32_t get_fpu_register_signed_word(int fpureg) const;
193  int32_t get_fpu_register_hi_word(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  bool set_fcsr_round64_error(double original, double rounded);
200  bool set_fcsr_round_error(float original, float rounded);
201  bool set_fcsr_round64_error(float original, float rounded);
202  void round_according_to_fcsr(double toRound, double& rounded,
203                               int32_t& rounded_int, double fs);
204  void round64_according_to_fcsr(double toRound, double& rounded,
205                                 int64_t& rounded_int, double fs);
206  void round_according_to_fcsr(float toRound, float& rounded,
207                               int32_t& rounded_int, float fs);
208  void round64_according_to_fcsr(float toRound, float& rounded,
209                                 int64_t& rounded_int, float fs);
210  void set_fcsr_rounding_mode(FPURoundingMode mode);
211  unsigned int get_fcsr_rounding_mode();
212  // Special case of set_register and get_register to access the raw PC value.
213  void set_pc(int64_t value);
214  int64_t get_pc() const;
215
216  Address get_sp() const {
217    return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
218  }
219
220  // Accessor to the internal simulator stack area.
221  uintptr_t StackLimit(uintptr_t c_limit) const;
222
223  // Executes MIPS instructions until the PC reaches end_sim_pc.
224  void Execute();
225
226  // Call on program start.
227  static void Initialize(Isolate* isolate);
228
229  static void TearDown(base::HashMap* i_cache, Redirection* first);
230
231  // V8 generally calls into generated JS code with 5 parameters and into
232  // generated RegExp code with 7 parameters. This is a convenience function,
233  // which sets up the simulator state and grabs the result on return.
234  int64_t Call(byte* entry, int argument_count, ...);
235  // Alternative: call a 2-argument double function.
236  double CallFP(byte* entry, double d0, double d1);
237
238  // Push an address onto the JS stack.
239  uintptr_t PushAddress(uintptr_t address);
240
241  // Pop an address from the JS stack.
242  uintptr_t PopAddress();
243
244  // Debugger input.
245  void set_last_debugger_input(char* input);
246  char* last_debugger_input() { return last_debugger_input_; }
247
248  // ICache checking.
249  static void FlushICache(base::HashMap* i_cache, void* start, size_t size);
250
251  // Returns true if pc register contains one of the 'special_values' defined
252  // below (bad_ra, end_sim_pc).
253  bool has_bad_pc() const;
254
255 private:
256  enum special_values {
257    // Known bad pc value to ensure that the simulator does not execute
258    // without being properly setup.
259    bad_ra = -1,
260    // A pc value used to signal the simulator to stop execution.  Generally
261    // the ra is set to this value on transition from native C code to
262    // simulated execution, so that the simulator can "return" to the native
263    // C code.
264    end_sim_pc = -2,
265    // Unpredictable value.
266    Unpredictable = 0xbadbeaf
267  };
268
269  // Unsupported instructions use Format to print an error and stop execution.
270  void Format(Instruction* instr, const char* format);
271
272  // Read and write memory.
273  inline uint32_t ReadBU(int64_t addr);
274  inline int32_t ReadB(int64_t addr);
275  inline void WriteB(int64_t addr, uint8_t value);
276  inline void WriteB(int64_t addr, int8_t value);
277
278  inline uint16_t ReadHU(int64_t addr, Instruction* instr);
279  inline int16_t ReadH(int64_t addr, Instruction* instr);
280  // Note: Overloaded on the sign of the value.
281  inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
282  inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
283
284  inline uint32_t ReadWU(int64_t addr, Instruction* instr);
285  inline int32_t ReadW(int64_t addr, Instruction* instr);
286  inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
287  inline int64_t Read2W(int64_t addr, Instruction* instr);
288  inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
289
290  inline double ReadD(int64_t addr, Instruction* instr);
291  inline void WriteD(int64_t addr, double value, Instruction* instr);
292
293  // Helper for debugging memory access.
294  inline void DieOrDebug();
295
296  // Helpers for data value tracing.
297    enum TraceType {
298    BYTE,
299    HALF,
300    WORD,
301    DWORD
302    // DFLOAT - Floats may have printing issues due to paired lwc1's
303  };
304
305  void TraceRegWr(int64_t value);
306  void TraceMemWr(int64_t addr, int64_t value, TraceType t);
307  void TraceMemRd(int64_t addr, int64_t value);
308
309  // Operations depending on endianness.
310  // Get Double Higher / Lower word.
311  inline int32_t GetDoubleHIW(double* addr);
312  inline int32_t GetDoubleLOW(double* addr);
313  // Set Double Higher / Lower word.
314  inline int32_t SetDoubleHIW(double* addr);
315  inline int32_t SetDoubleLOW(double* addr);
316
317  // functions called from DecodeTypeRegister.
318  void DecodeTypeRegisterCOP1();
319
320  void DecodeTypeRegisterCOP1X();
321
322  void DecodeTypeRegisterSPECIAL();
323
324
325  void DecodeTypeRegisterSPECIAL2();
326
327  void DecodeTypeRegisterSPECIAL3();
328
329  void DecodeTypeRegisterSRsType();
330
331  void DecodeTypeRegisterDRsType();
332
333  void DecodeTypeRegisterWRsType();
334
335  void DecodeTypeRegisterLRsType();
336
337  // Executing is handled based on the instruction type.
338  void DecodeTypeRegister(Instruction* instr);
339
340  Instruction* currentInstr_;
341  inline Instruction* get_instr() const { return currentInstr_; }
342  inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
343
344  inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
345  inline int64_t rs() const { return get_register(rs_reg()); }
346  inline uint64_t rs_u() const {
347    return static_cast<uint64_t>(get_register(rs_reg()));
348  }
349  inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
350  inline int64_t rt() const { return get_register(rt_reg()); }
351  inline uint64_t rt_u() const {
352    return static_cast<uint64_t>(get_register(rt_reg()));
353  }
354  inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
355  inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
356  inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
357  inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
358  inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
359  inline int32_t sa() const { return currentInstr_->SaValue(); }
360  inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
361
362  inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
363    set_register(rd_reg, alu_out);
364    TraceRegWr(alu_out);
365  }
366
367  void DecodeTypeImmediate(Instruction* instr);
368  void DecodeTypeJump(Instruction* instr);
369
370  // Used for breakpoints and traps.
371  void SoftwareInterrupt(Instruction* instr);
372
373  // Compact branch guard.
374  void CheckForbiddenSlot(int64_t current_pc) {
375    Instruction* instr_after_compact_branch =
376        reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
377    if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
378      V8_Fatal(__FILE__, __LINE__,
379               "Error: Unexpected instruction 0x%08x immediately after a "
380               "compact branch instruction.",
381               *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
382    }
383  }
384
385  // Stop helper functions.
386  bool IsWatchpoint(uint64_t code);
387  void PrintWatchpoint(uint64_t code);
388  void HandleStop(uint64_t code, Instruction* instr);
389  bool IsStopInstruction(Instruction* instr);
390  bool IsEnabledStop(uint64_t code);
391  void EnableStop(uint64_t code);
392  void DisableStop(uint64_t code);
393  void IncreaseStopCounter(uint64_t code);
394  void PrintStopInfo(uint64_t code);
395
396
397  // Executes one instruction.
398  void InstructionDecode(Instruction* instr);
399  // Execute one instruction placed in a branch delay slot.
400  void BranchDelayInstructionDecode(Instruction* instr) {
401    if (instr->InstructionBits() == nopInstr) {
402      // Short-cut generic nop instructions. They are always valid and they
403      // never change the simulator state.
404      return;
405    }
406
407    if (instr->IsForbiddenAfterBranch()) {
408      V8_Fatal(__FILE__, __LINE__,
409               "Eror:Unexpected %i opcode in a branch delay slot.",
410               instr->OpcodeValue());
411    }
412    InstructionDecode(instr);
413    SNPrintF(trace_buf_, " ");
414  }
415
416  // ICache.
417  static void CheckICache(base::HashMap* i_cache, Instruction* instr);
418  static void FlushOnePage(base::HashMap* i_cache, intptr_t start, size_t size);
419  static CachePage* GetCachePage(base::HashMap* i_cache, void* page);
420
421  enum Exception {
422    none,
423    kIntegerOverflow,
424    kIntegerUnderflow,
425    kDivideByZero,
426    kNumExceptions
427  };
428
429  // Exceptions.
430  void SignalException(Exception e);
431
432  // Runtime call support.
433  static void* RedirectExternalReference(Isolate* isolate,
434                                         void* external_function,
435                                         ExternalReference::Type type);
436
437  // Handle arguments and return value for runtime FP functions.
438  void GetFpArgs(double* x, double* y, int32_t* z);
439  void SetFpResult(const double& result);
440
441  void CallInternal(byte* entry);
442
443  // Architecture state.
444  // Registers.
445  int64_t registers_[kNumSimuRegisters];
446  // Coprocessor Registers.
447  int64_t FPUregisters_[kNumFPURegisters];
448  // FPU control register.
449  uint32_t FCSR_;
450
451  // Simulator support.
452  // Allocate 1MB for stack.
453  size_t stack_size_;
454  char* stack_;
455  bool pc_modified_;
456  int64_t icount_;
457  int break_count_;
458  EmbeddedVector<char, 128> trace_buf_;
459
460  // Debugger input.
461  char* last_debugger_input_;
462
463  // Icache simulation.
464  base::HashMap* i_cache_;
465
466  v8::internal::Isolate* isolate_;
467
468  // Registered breakpoints.
469  Instruction* break_pc_;
470  Instr break_instr_;
471
472  // Stop is disabled if bit 31 is set.
473  static const uint32_t kStopDisabledBit = 1 << 31;
474
475  // A stop is enabled, meaning the simulator will stop when meeting the
476  // instruction, if bit 31 of watched_stops_[code].count is unset.
477  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
478  // the breakpoint was hit or gone through.
479  struct StopCountAndDesc {
480    uint32_t count;
481    char* desc;
482  };
483  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
484};
485
486
487// When running with the simulator transition into simulated execution at this
488// point.
489#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4)       \
490  reinterpret_cast<Object*>(Simulator::current(isolate)->Call(        \
491      FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0),        \
492      reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2), \
493      reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
494
495
496#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
497                                   p7, p8)                                     \
498  static_cast<int>(Simulator::current(isolate)->Call(                          \
499      entry, 10, p0, p1, p2, p3, p4, reinterpret_cast<int64_t*>(p5), p6, p7,   \
500      NULL, p8))
501
502
503// The simulator has its own stack. Thus it has a different stack limit from
504// the C-based native code.  The JS-based limit normally points near the end of
505// the simulator stack.  When the C-based limit is exhausted we reflect that by
506// lowering the JS-based limit as well, to make stack checks trigger.
507class SimulatorStack : public v8::internal::AllStatic {
508 public:
509  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
510                                            uintptr_t c_limit) {
511    return Simulator::current(isolate)->StackLimit(c_limit);
512  }
513
514  static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
515                                            uintptr_t try_catch_address) {
516    Simulator* sim = Simulator::current(isolate);
517    return sim->PushAddress(try_catch_address);
518  }
519
520  static inline void UnregisterCTryCatch(Isolate* isolate) {
521    Simulator::current(isolate)->PopAddress();
522  }
523};
524
525}  // namespace internal
526}  // namespace v8
527
528#endif  // !defined(USE_SIMULATOR)
529#endif  // V8_MIPS_SIMULATOR_MIPS_H_
530