V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
simulator-mips.h
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 // Declares a Simulator for MIPS instructions if we are not generating a native
6 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
7 // on regular desktop machines.
8 // V8 calls into generated code via the GeneratedCode wrapper,
9 // which will start execution in the Simulator or forwards to the real entry
10 // on a MIPS HW platform.
11 
12 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
13 #define V8_MIPS_SIMULATOR_MIPS_H_
14 
15 #include "src/allocation.h"
16 #include "src/mips/constants-mips.h"
17 
18 #if defined(USE_SIMULATOR)
19 // Running with a simulator.
20 
21 #include "src/assembler.h"
22 #include "src/base/hashmap.h"
23 #include "src/simulator-base.h"
24 
25 namespace v8 {
26 namespace internal {
27 
28 // -----------------------------------------------------------------------------
29 // Utility functions
30 
31 class CachePage {
32  public:
33  static const int LINE_VALID = 0;
34  static const int LINE_INVALID = 1;
35 
36  static const int kPageShift = 12;
37  static const int kPageSize = 1 << kPageShift;
38  static const int kPageMask = kPageSize - 1;
39  static const int kLineShift = 2; // The cache line is only 4 bytes right now.
40  static const int kLineLength = 1 << kLineShift;
41  static const int kLineMask = kLineLength - 1;
42 
43  CachePage() {
44  memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
45  }
46 
47  char* ValidityByte(int offset) {
48  return &validity_map_[offset >> kLineShift];
49  }
50 
51  char* CachedData(int offset) {
52  return &data_[offset];
53  }
54 
55  private:
56  char data_[kPageSize]; // The cached data.
57  static const int kValidityMapSize = kPageSize >> kLineShift;
58  char validity_map_[kValidityMapSize]; // One byte per line.
59 };
60 
61 class SimInstructionBase : public InstructionBase {
62  public:
63  Type InstructionType() const { return type_; }
64  inline Instruction* instr() const { return instr_; }
65  inline int32_t operand() const { return operand_; }
66 
67  protected:
68  SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
69  explicit SimInstructionBase(Instruction* instr) {}
70 
71  int32_t operand_;
72  Instruction* instr_;
73  Type type_;
74 
75  private:
76  DISALLOW_ASSIGN(SimInstructionBase);
77 };
78 
79 class SimInstruction : public InstructionGetters<SimInstructionBase> {
80  public:
81  SimInstruction() {}
82 
83  explicit SimInstruction(Instruction* instr) { *this = instr; }
84 
85  SimInstruction& operator=(Instruction* instr) {
86  operand_ = *reinterpret_cast<const int32_t*>(instr);
87  instr_ = instr;
88  type_ = InstructionBase::InstructionType();
89  DCHECK(reinterpret_cast<void*>(&operand_) == this);
90  return *this;
91  }
92 };
93 
94 class Simulator : public SimulatorBase {
95  public:
96  friend class MipsDebugger;
97 
98  // Registers are declared in order. See SMRL chapter 2.
99  enum Register {
100  no_reg = -1,
101  zero_reg = 0,
102  at,
103  v0, v1,
104  a0, a1, a2, a3,
105  t0, t1, t2, t3, t4, t5, t6, t7,
106  s0, s1, s2, s3, s4, s5, s6, s7,
107  t8, t9,
108  k0, k1,
109  gp,
110  sp,
111  s8,
112  ra,
113  // LO, HI, and pc.
114  LO,
115  HI,
116  pc, // pc must be the last register.
117  kNumSimuRegisters,
118  // aliases
119  fp = s8
120  };
121 
122  // Coprocessor registers.
123  // Generated code will always use doubles. So we will only use even registers.
124  enum FPURegister {
125  f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
126  f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
127  f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
128  f26, f27, f28, f29, f30, f31,
129  kNumFPURegisters
130  };
131 
132  // MSA registers
133  enum MSARegister {
134  w0,
135  w1,
136  w2,
137  w3,
138  w4,
139  w5,
140  w6,
141  w7,
142  w8,
143  w9,
144  w10,
145  w11,
146  w12,
147  w13,
148  w14,
149  w15,
150  w16,
151  w17,
152  w18,
153  w19,
154  w20,
155  w21,
156  w22,
157  w23,
158  w24,
159  w25,
160  w26,
161  w27,
162  w28,
163  w29,
164  w30,
165  w31,
166  kNumMSARegisters
167  };
168 
169  explicit Simulator(Isolate* isolate);
170  ~Simulator();
171 
172  // The currently executing Simulator instance. Potentially there can be one
173  // for each native thread.
174  V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate);
175 
176  // Accessors for register state. Reading the pc value adheres to the MIPS
177  // architecture specification and is off by a 8 from the currently executing
178  // instruction.
179  void set_register(int reg, int32_t value);
180  void set_dw_register(int dreg, const int* dbl);
181  int32_t get_register(int reg) const;
182  double get_double_from_register_pair(int reg);
183  // Same for FPURegisters.
184  void set_fpu_register(int fpureg, int64_t value);
185  void set_fpu_register_word(int fpureg, int32_t value);
186  void set_fpu_register_hi_word(int fpureg, int32_t value);
187  void set_fpu_register_float(int fpureg, float value);
188  void set_fpu_register_double(int fpureg, double value);
189  void set_fpu_register_invalid_result64(float original, float rounded);
190  void set_fpu_register_invalid_result(float original, float rounded);
191  void set_fpu_register_word_invalid_result(float original, float rounded);
192  void set_fpu_register_invalid_result64(double original, double rounded);
193  void set_fpu_register_invalid_result(double original, double rounded);
194  void set_fpu_register_word_invalid_result(double original, double rounded);
195  int64_t get_fpu_register(int fpureg) const;
196  int32_t get_fpu_register_word(int fpureg) const;
197  int32_t get_fpu_register_signed_word(int fpureg) const;
198  int32_t get_fpu_register_hi_word(int fpureg) const;
199  float get_fpu_register_float(int fpureg) const;
200  double get_fpu_register_double(int fpureg) const;
201  template <typename T>
202  void get_msa_register(int wreg, T* value);
203  template <typename T>
204  void set_msa_register(int wreg, const T* value);
205  void set_fcsr_bit(uint32_t cc, bool value);
206  bool test_fcsr_bit(uint32_t cc);
207  void set_fcsr_rounding_mode(FPURoundingMode mode);
208  void set_msacsr_rounding_mode(FPURoundingMode mode);
209  unsigned int get_fcsr_rounding_mode();
210  unsigned int get_msacsr_rounding_mode();
211  bool set_fcsr_round_error(double original, double rounded);
212  bool set_fcsr_round_error(float original, float rounded);
213  bool set_fcsr_round64_error(double original, double rounded);
214  bool set_fcsr_round64_error(float original, float rounded);
215  void round_according_to_fcsr(double toRound, double& rounded,
216  int32_t& rounded_int, double fs);
217  void round_according_to_fcsr(float toRound, float& rounded,
218  int32_t& rounded_int, float fs);
219  template <typename Tfp, typename Tint>
220  void round_according_to_msacsr(Tfp toRound, Tfp& rounded, Tint& rounded_int);
221  void round64_according_to_fcsr(double toRound, double& rounded,
222  int64_t& rounded_int, double fs);
223  void round64_according_to_fcsr(float toRound, float& rounded,
224  int64_t& rounded_int, float fs);
225  // Special case of set_register and get_register to access the raw PC value.
226  void set_pc(int32_t value);
227  int32_t get_pc() const;
228 
229  Address get_sp() const { return static_cast<Address>(get_register(sp)); }
230 
231  // Accessor to the internal simulator stack area.
232  uintptr_t StackLimit(uintptr_t c_limit) const;
233 
234  // Executes MIPS instructions until the PC reaches end_sim_pc.
235  void Execute();
236 
237  template <typename Return, typename... Args>
238  Return Call(Address entry, Args... args) {
239  return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
240  }
241 
242  // Alternative: call a 2-argument double function.
243  double CallFP(Address entry, double d0, double d1);
244 
245  // Push an address onto the JS stack.
246  uintptr_t PushAddress(uintptr_t address);
247 
248  // Pop an address from the JS stack.
249  uintptr_t PopAddress();
250 
251  // Debugger input.
252  void set_last_debugger_input(char* input);
253  char* last_debugger_input() { return last_debugger_input_; }
254 
255  // Redirection support.
256  static void SetRedirectInstruction(Instruction* instruction);
257 
258  // ICache checking.
259  static bool ICacheMatch(void* one, void* two);
260  static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
261  size_t size);
262 
263  // Returns true if pc register contains one of the 'special_values' defined
264  // below (bad_ra, end_sim_pc).
265  bool has_bad_pc() const;
266 
267  private:
268  enum special_values {
269  // Known bad pc value to ensure that the simulator does not execute
270  // without being properly setup.
271  bad_ra = -1,
272  // A pc value used to signal the simulator to stop execution. Generally
273  // the ra is set to this value on transition from native C code to
274  // simulated execution, so that the simulator can "return" to the native
275  // C code.
276  end_sim_pc = -2,
277  // Unpredictable value.
278  Unpredictable = 0xbadbeaf
279  };
280 
281  V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
282  const intptr_t* arguments);
283 
284  // Unsupported instructions use Format to print an error and stop execution.
285  void Format(Instruction* instr, const char* format);
286 
287  // Helpers for data value tracing.
288  enum TraceType { BYTE, HALF, WORD, DWORD, FLOAT, DOUBLE, FLOAT_DOUBLE };
289 
290  // MSA Data Format
291  enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
292  typedef union {
293  int8_t b[kMSALanesByte];
294  uint8_t ub[kMSALanesByte];
295  int16_t h[kMSALanesHalf];
296  uint16_t uh[kMSALanesHalf];
297  int32_t w[kMSALanesWord];
298  uint32_t uw[kMSALanesWord];
299  int64_t d[kMSALanesDword];
300  uint64_t ud[kMSALanesDword];
301  } msa_reg_t;
302 
303  // Read and write memory.
304  inline uint32_t ReadBU(int32_t addr);
305  inline int32_t ReadB(int32_t addr);
306  inline void WriteB(int32_t addr, uint8_t value);
307  inline void WriteB(int32_t addr, int8_t value);
308 
309  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
310  inline int16_t ReadH(int32_t addr, Instruction* instr);
311  // Note: Overloaded on the sign of the value.
312  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
313  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
314 
315  inline int ReadW(int32_t addr, Instruction* instr, TraceType t = WORD);
316  inline void WriteW(int32_t addr, int value, Instruction* instr);
317 
318  inline double ReadD(int32_t addr, Instruction* instr);
319  inline void WriteD(int32_t addr, double value, Instruction* instr);
320 
321  template <typename T>
322  T ReadMem(int32_t addr, Instruction* instr);
323 
324  template <typename T>
325  void WriteMem(int32_t addr, T value, Instruction* instr);
326 
327  void TraceRegWr(int32_t value, TraceType t = WORD);
328  void TraceRegWr(int64_t value, TraceType t = DWORD);
329  template <typename T>
330  void TraceMSARegWr(T* value, TraceType t);
331  template <typename T>
332  void TraceMSARegWr(T* value);
333  void TraceMemWr(int32_t addr, int32_t value, TraceType t = WORD);
334  void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD);
335  void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD);
336  void TraceMemRd(int32_t addr, int64_t value, TraceType t = DWORD);
337  template <typename T>
338  void TraceMemRd(int32_t addr, T value);
339  template <typename T>
340  void TraceMemWr(int32_t addr, T value);
341  EmbeddedVector<char, 128> trace_buf_;
342 
343  // Operations depending on endianness.
344  // Get Double Higher / Lower word.
345  inline int32_t GetDoubleHIW(double* addr);
346  inline int32_t GetDoubleLOW(double* addr);
347  // Set Double Higher / Lower word.
348  inline int32_t SetDoubleHIW(double* addr);
349  inline int32_t SetDoubleLOW(double* addr);
350 
351  SimInstruction instr_;
352 
353  // Executing is handled based on the instruction type.
354  void DecodeTypeRegister();
355 
356  // Functions called from DecodeTypeRegister.
357  void DecodeTypeRegisterCOP1();
358 
359  void DecodeTypeRegisterCOP1X();
360 
361  void DecodeTypeRegisterSPECIAL();
362 
363  void DecodeTypeRegisterSPECIAL2();
364 
365  void DecodeTypeRegisterSPECIAL3();
366 
367  // Called from DecodeTypeRegisterCOP1.
368  void DecodeTypeRegisterSRsType();
369 
370  void DecodeTypeRegisterDRsType();
371 
372  void DecodeTypeRegisterWRsType();
373 
374  void DecodeTypeRegisterLRsType();
375 
376  int DecodeMsaDataFormat();
377  void DecodeTypeMsaI8();
378  void DecodeTypeMsaI5();
379  void DecodeTypeMsaI10();
380  void DecodeTypeMsaELM();
381  void DecodeTypeMsaBIT();
382  void DecodeTypeMsaMI10();
383  void DecodeTypeMsa3R();
384  void DecodeTypeMsa3RF();
385  void DecodeTypeMsaVec();
386  void DecodeTypeMsa2R();
387  void DecodeTypeMsa2RF();
388  template <typename T>
389  T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
390  template <typename T>
391  T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
392  template <typename T>
393  T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt);
394 
395  inline int32_t rs_reg() const { return instr_.RsValue(); }
396  inline int32_t rs() const { return get_register(rs_reg()); }
397  inline uint32_t rs_u() const {
398  return static_cast<uint32_t>(get_register(rs_reg()));
399  }
400  inline int32_t rt_reg() const { return instr_.RtValue(); }
401  inline int32_t rt() const { return get_register(rt_reg()); }
402  inline uint32_t rt_u() const {
403  return static_cast<uint32_t>(get_register(rt_reg()));
404  }
405  inline int32_t rd_reg() const { return instr_.RdValue(); }
406  inline int32_t fr_reg() const { return instr_.FrValue(); }
407  inline int32_t fs_reg() const { return instr_.FsValue(); }
408  inline int32_t ft_reg() const { return instr_.FtValue(); }
409  inline int32_t fd_reg() const { return instr_.FdValue(); }
410  inline int32_t sa() const { return instr_.SaValue(); }
411  inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
412  inline int32_t ws_reg() const { return instr_.WsValue(); }
413  inline int32_t wt_reg() const { return instr_.WtValue(); }
414  inline int32_t wd_reg() const { return instr_.WdValue(); }
415 
416  inline void SetResult(int32_t rd_reg, int32_t alu_out) {
417  set_register(rd_reg, alu_out);
418  TraceRegWr(alu_out);
419  }
420 
421  inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) {
422  set_fpu_register_word(fd_reg, alu_out);
423  TraceRegWr(get_fpu_register_word(fd_reg));
424  }
425 
426  inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) {
427  set_fpu_register(fd_reg, alu_out);
428  TraceRegWr(get_fpu_register(fd_reg));
429  }
430 
431  inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) {
432  set_fpu_register_float(fd_reg, alu_out);
433  TraceRegWr(get_fpu_register_word(fd_reg), FLOAT);
434  }
435 
436  inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) {
437  set_fpu_register_double(fd_reg, alu_out);
438  TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
439  }
440 
441  void DecodeTypeImmediate();
442  void DecodeTypeJump();
443 
444  // Used for breakpoints and traps.
445  void SoftwareInterrupt();
446 
447  // Compact branch guard.
448  void CheckForbiddenSlot(int32_t current_pc) {
449  Instruction* instr_after_compact_branch =
450  reinterpret_cast<Instruction*>(current_pc + kInstrSize);
451  if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
452  FATAL(
453  "Error: Unexpected instruction 0x%08x immediately after a "
454  "compact branch instruction.",
455  *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
456  }
457  }
458 
459  // Stop helper functions.
460  bool IsWatchpoint(uint32_t code);
461  void PrintWatchpoint(uint32_t code);
462  void HandleStop(uint32_t code, Instruction* instr);
463  bool IsStopInstruction(Instruction* instr);
464  bool IsEnabledStop(uint32_t code);
465  void EnableStop(uint32_t code);
466  void DisableStop(uint32_t code);
467  void IncreaseStopCounter(uint32_t code);
468  void PrintStopInfo(uint32_t code);
469 
470 
471  // Executes one instruction.
472  void InstructionDecode(Instruction* instr);
473  // Execute one instruction placed in a branch delay slot.
474  void BranchDelayInstructionDecode(Instruction* instr) {
475  if (instr->InstructionBits() == nopInstr) {
476  // Short-cut generic nop instructions. They are always valid and they
477  // never change the simulator state.
478  return;
479  }
480 
481  if (instr->IsForbiddenInBranchDelay()) {
482  FATAL("Eror:Unexpected %i opcode in a branch delay slot.",
483  instr->OpcodeValue());
484  }
485  InstructionDecode(instr);
486  SNPrintF(trace_buf_, " ");
487  }
488 
489  // ICache.
490  static void CheckICache(base::CustomMatcherHashMap* i_cache,
491  Instruction* instr);
492  static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
493  int size);
494  static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
495  void* page);
496 
497  enum Exception {
498  none,
499  kIntegerOverflow,
500  kIntegerUnderflow,
501  kDivideByZero,
502  kNumExceptions
503  };
504 
505  // Exceptions.
506  void SignalException(Exception e);
507 
508  // Handle arguments and return value for runtime FP functions.
509  void GetFpArgs(double* x, double* y, int32_t* z);
510  void SetFpResult(const double& result);
511 
512  void CallInternal(Address entry);
513 
514  // Architecture state.
515  // Registers.
516  int32_t registers_[kNumSimuRegisters];
517  // Coprocessor Registers.
518  // Note: FP32 mode uses only the lower 32-bit part of each element,
519  // the upper 32-bit is unpredictable.
520  // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
521  // order to support MSA registers
522  int64_t FPUregisters_[kNumFPURegisters * 2];
523  // FPU control register.
524  uint32_t FCSR_;
525  // MSA control register.
526  uint32_t MSACSR_;
527 
528  // Simulator support.
529  // Allocate 1MB for stack.
530  static const size_t stack_size_ = 1 * 1024*1024;
531  char* stack_;
532  bool pc_modified_;
533  uint64_t icount_;
534  int break_count_;
535 
536  // Debugger input.
537  char* last_debugger_input_;
538 
539  v8::internal::Isolate* isolate_;
540 
541  // Registered breakpoints.
542  Instruction* break_pc_;
543  Instr break_instr_;
544 
545  // Stop is disabled if bit 31 is set.
546  static const uint32_t kStopDisabledBit = 1 << 31;
547 
548  // A stop is enabled, meaning the simulator will stop when meeting the
549  // instruction, if bit 31 of watched_stops_[code].count is unset.
550  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
551  // the breakpoint was hit or gone through.
552  struct StopCountAndDesc {
553  uint32_t count;
554  char* desc;
555  };
556  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
557 };
558 
559 } // namespace internal
560 } // namespace v8
561 
562 #endif // defined(USE_SIMULATOR)
563 #endif // V8_MIPS_SIMULATOR_MIPS_H_
Definition: libplatform.h:13