V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
simulator-mips64.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_MIPS64_SIMULATOR_MIPS64_H_
13 #define V8_MIPS64_SIMULATOR_MIPS64_H_
14 
15 #include "src/allocation.h"
16 #include "src/mips64/constants-mips64.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, a4, a5, a6, a7,
105  t0, t1, t2, t3,
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, int64_t value);
180  void set_register_word(int reg, int32_t value);
181  void set_dw_register(int dreg, const int* dbl);
182  int64_t get_register(int reg) const;
183  double get_double_from_register_pair(int reg);
184  // Same for FPURegisters.
185  void set_fpu_register(int fpureg, int64_t value);
186  void set_fpu_register_word(int fpureg, int32_t value);
187  void set_fpu_register_hi_word(int fpureg, int32_t value);
188  void set_fpu_register_float(int fpureg, float value);
189  void set_fpu_register_double(int fpureg, double value);
190  void set_fpu_register_invalid_result64(float original, float rounded);
191  void set_fpu_register_invalid_result(float original, float rounded);
192  void set_fpu_register_word_invalid_result(float original, float rounded);
193  void set_fpu_register_invalid_result64(double original, double rounded);
194  void set_fpu_register_invalid_result(double original, double rounded);
195  void set_fpu_register_word_invalid_result(double original, double rounded);
196  int64_t get_fpu_register(int fpureg) const;
197  int32_t get_fpu_register_word(int fpureg) const;
198  int32_t get_fpu_register_signed_word(int fpureg) const;
199  int32_t get_fpu_register_hi_word(int fpureg) const;
200  float get_fpu_register_float(int fpureg) const;
201  double get_fpu_register_double(int fpureg) const;
202  template <typename T>
203  void get_msa_register(int wreg, T* value);
204  template <typename T>
205  void set_msa_register(int wreg, const T* value);
206  void set_fcsr_bit(uint32_t cc, bool value);
207  bool test_fcsr_bit(uint32_t cc);
208  bool set_fcsr_round_error(double original, double rounded);
209  bool set_fcsr_round64_error(double original, double rounded);
210  bool set_fcsr_round_error(float original, float rounded);
211  bool set_fcsr_round64_error(float original, float rounded);
212  void round_according_to_fcsr(double toRound, double& rounded,
213  int32_t& rounded_int, double fs);
214  void round64_according_to_fcsr(double toRound, double& rounded,
215  int64_t& rounded_int, double fs);
216  void round_according_to_fcsr(float toRound, float& rounded,
217  int32_t& rounded_int, float fs);
218  void round64_according_to_fcsr(float toRound, float& rounded,
219  int64_t& rounded_int, float fs);
220  template <typename T_fp, typename T_int>
221  void round_according_to_msacsr(T_fp toRound, T_fp& rounded,
222  T_int& rounded_int);
223  void set_fcsr_rounding_mode(FPURoundingMode mode);
224  void set_msacsr_rounding_mode(FPURoundingMode mode);
225  unsigned int get_fcsr_rounding_mode();
226  unsigned int get_msacsr_rounding_mode();
227  // Special case of set_register and get_register to access the raw PC value.
228  void set_pc(int64_t value);
229  int64_t get_pc() const;
230 
231  Address get_sp() const { return static_cast<Address>(get_register(sp)); }
232 
233  // Accessor to the internal simulator stack area.
234  uintptr_t StackLimit(uintptr_t c_limit) const;
235 
236  // Executes MIPS instructions until the PC reaches end_sim_pc.
237  void Execute();
238 
239  template <typename Return, typename... Args>
240  Return Call(Address entry, Args... args) {
241  return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
242  }
243 
244  // Alternative: call a 2-argument double function.
245  double CallFP(Address entry, double d0, double d1);
246 
247  // Push an address onto the JS stack.
248  uintptr_t PushAddress(uintptr_t address);
249 
250  // Pop an address from the JS stack.
251  uintptr_t PopAddress();
252 
253  // Debugger input.
254  void set_last_debugger_input(char* input);
255  char* last_debugger_input() { return last_debugger_input_; }
256 
257  // Redirection support.
258  static void SetRedirectInstruction(Instruction* instruction);
259 
260  // ICache checking.
261  static bool ICacheMatch(void* one, void* two);
262  static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
263  size_t size);
264 
265  // Returns true if pc register contains one of the 'special_values' defined
266  // below (bad_ra, end_sim_pc).
267  bool has_bad_pc() const;
268 
269  private:
270  enum special_values {
271  // Known bad pc value to ensure that the simulator does not execute
272  // without being properly setup.
273  bad_ra = -1,
274  // A pc value used to signal the simulator to stop execution. Generally
275  // the ra is set to this value on transition from native C code to
276  // simulated execution, so that the simulator can "return" to the native
277  // C code.
278  end_sim_pc = -2,
279  // Unpredictable value.
280  Unpredictable = 0xbadbeaf
281  };
282 
283  V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
284  const intptr_t* arguments);
285 
286  // Unsupported instructions use Format to print an error and stop execution.
287  void Format(Instruction* instr, const char* format);
288 
289  // Helpers for data value tracing.
290  enum TraceType {
291  BYTE,
292  HALF,
293  WORD,
294  DWORD,
295  FLOAT,
296  DOUBLE,
297  FLOAT_DOUBLE,
298  WORD_DWORD
299  };
300 
301  // MSA Data Format
302  enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
303  typedef union {
304  int8_t b[kMSALanesByte];
305  uint8_t ub[kMSALanesByte];
306  int16_t h[kMSALanesHalf];
307  uint16_t uh[kMSALanesHalf];
308  int32_t w[kMSALanesWord];
309  uint32_t uw[kMSALanesWord];
310  int64_t d[kMSALanesDword];
311  uint64_t ud[kMSALanesDword];
312  } msa_reg_t;
313 
314  // Read and write memory.
315  inline uint32_t ReadBU(int64_t addr);
316  inline int32_t ReadB(int64_t addr);
317  inline void WriteB(int64_t addr, uint8_t value);
318  inline void WriteB(int64_t addr, int8_t value);
319 
320  inline uint16_t ReadHU(int64_t addr, Instruction* instr);
321  inline int16_t ReadH(int64_t addr, Instruction* instr);
322  // Note: Overloaded on the sign of the value.
323  inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
324  inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
325 
326  inline uint32_t ReadWU(int64_t addr, Instruction* instr);
327  inline int32_t ReadW(int64_t addr, Instruction* instr, TraceType t = WORD);
328  inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
329  inline int64_t Read2W(int64_t addr, Instruction* instr);
330  inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
331 
332  inline double ReadD(int64_t addr, Instruction* instr);
333  inline void WriteD(int64_t addr, double value, Instruction* instr);
334 
335  template <typename T>
336  T ReadMem(int64_t addr, Instruction* instr);
337  template <typename T>
338  void WriteMem(int64_t addr, T value, Instruction* instr);
339 
340  // Helper for debugging memory access.
341  inline void DieOrDebug();
342 
343  void TraceRegWr(int64_t value, TraceType t = DWORD);
344  template <typename T>
345  void TraceMSARegWr(T* value, TraceType t);
346  template <typename T>
347  void TraceMSARegWr(T* value);
348  void TraceMemWr(int64_t addr, int64_t value, TraceType t);
349  void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD);
350  template <typename T>
351  void TraceMemRd(int64_t addr, T value);
352  template <typename T>
353  void TraceMemWr(int64_t addr, T value);
354 
355  // Operations depending on endianness.
356  // Get Double Higher / Lower word.
357  inline int32_t GetDoubleHIW(double* addr);
358  inline int32_t GetDoubleLOW(double* addr);
359  // Set Double Higher / Lower word.
360  inline int32_t SetDoubleHIW(double* addr);
361  inline int32_t SetDoubleLOW(double* addr);
362 
363  SimInstruction instr_;
364 
365  // functions called from DecodeTypeRegister.
366  void DecodeTypeRegisterCOP1();
367 
368  void DecodeTypeRegisterCOP1X();
369 
370  void DecodeTypeRegisterSPECIAL();
371 
372 
373  void DecodeTypeRegisterSPECIAL2();
374 
375  void DecodeTypeRegisterSPECIAL3();
376 
377  void DecodeTypeRegisterSRsType();
378 
379  void DecodeTypeRegisterDRsType();
380 
381  void DecodeTypeRegisterWRsType();
382 
383  void DecodeTypeRegisterLRsType();
384 
385  int DecodeMsaDataFormat();
386  void DecodeTypeMsaI8();
387  void DecodeTypeMsaI5();
388  void DecodeTypeMsaI10();
389  void DecodeTypeMsaELM();
390  void DecodeTypeMsaBIT();
391  void DecodeTypeMsaMI10();
392  void DecodeTypeMsa3R();
393  void DecodeTypeMsa3RF();
394  void DecodeTypeMsaVec();
395  void DecodeTypeMsa2R();
396  void DecodeTypeMsa2RF();
397  template <typename T>
398  T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
399  template <typename T>
400  T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
401  template <typename T>
402  T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt);
403 
404  // Executing is handled based on the instruction type.
405  void DecodeTypeRegister();
406 
407  inline int32_t rs_reg() const { return instr_.RsValue(); }
408  inline int64_t rs() const { return get_register(rs_reg()); }
409  inline uint64_t rs_u() const {
410  return static_cast<uint64_t>(get_register(rs_reg()));
411  }
412  inline int32_t rt_reg() const { return instr_.RtValue(); }
413  inline int64_t rt() const { return get_register(rt_reg()); }
414  inline uint64_t rt_u() const {
415  return static_cast<uint64_t>(get_register(rt_reg()));
416  }
417  inline int32_t rd_reg() const { return instr_.RdValue(); }
418  inline int32_t fr_reg() const { return instr_.FrValue(); }
419  inline int32_t fs_reg() const { return instr_.FsValue(); }
420  inline int32_t ft_reg() const { return instr_.FtValue(); }
421  inline int32_t fd_reg() const { return instr_.FdValue(); }
422  inline int32_t sa() const { return instr_.SaValue(); }
423  inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
424  inline int32_t ws_reg() const { return instr_.WsValue(); }
425  inline int32_t wt_reg() const { return instr_.WtValue(); }
426  inline int32_t wd_reg() const { return instr_.WdValue(); }
427 
428  inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
429  set_register(rd_reg, alu_out);
430  TraceRegWr(alu_out);
431  }
432 
433  inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) {
434  set_fpu_register_word(fd_reg, alu_out);
435  TraceRegWr(get_fpu_register(fd_reg), WORD);
436  }
437 
438  inline void SetFPUWordResult2(int32_t fd_reg, int32_t alu_out) {
439  set_fpu_register_word(fd_reg, alu_out);
440  TraceRegWr(get_fpu_register(fd_reg));
441  }
442 
443  inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) {
444  set_fpu_register(fd_reg, alu_out);
445  TraceRegWr(get_fpu_register(fd_reg));
446  }
447 
448  inline void SetFPUResult2(int32_t fd_reg, int64_t alu_out) {
449  set_fpu_register(fd_reg, alu_out);
450  TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
451  }
452 
453  inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) {
454  set_fpu_register_float(fd_reg, alu_out);
455  TraceRegWr(get_fpu_register(fd_reg), FLOAT);
456  }
457 
458  inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) {
459  set_fpu_register_double(fd_reg, alu_out);
460  TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
461  }
462 
463  void DecodeTypeImmediate();
464  void DecodeTypeJump();
465 
466  // Used for breakpoints and traps.
467  void SoftwareInterrupt();
468 
469  // Compact branch guard.
470  void CheckForbiddenSlot(int64_t current_pc) {
471  Instruction* instr_after_compact_branch =
472  reinterpret_cast<Instruction*>(current_pc + kInstrSize);
473  if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
474  FATAL(
475  "Error: Unexpected instruction 0x%08x immediately after a "
476  "compact branch instruction.",
477  *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
478  }
479  }
480 
481  // Stop helper functions.
482  bool IsWatchpoint(uint64_t code);
483  void PrintWatchpoint(uint64_t code);
484  void HandleStop(uint64_t code, Instruction* instr);
485  bool IsStopInstruction(Instruction* instr);
486  bool IsEnabledStop(uint64_t code);
487  void EnableStop(uint64_t code);
488  void DisableStop(uint64_t code);
489  void IncreaseStopCounter(uint64_t code);
490  void PrintStopInfo(uint64_t code);
491 
492 
493  // Executes one instruction.
494  void InstructionDecode(Instruction* instr);
495  // Execute one instruction placed in a branch delay slot.
496  void BranchDelayInstructionDecode(Instruction* instr) {
497  if (instr->InstructionBits() == nopInstr) {
498  // Short-cut generic nop instructions. They are always valid and they
499  // never change the simulator state.
500  return;
501  }
502 
503  if (instr->IsForbiddenAfterBranch()) {
504  FATAL("Eror:Unexpected %i opcode in a branch delay slot.",
505  instr->OpcodeValue());
506  }
507  InstructionDecode(instr);
508  SNPrintF(trace_buf_, " ");
509  }
510 
511  // ICache.
512  static void CheckICache(base::CustomMatcherHashMap* i_cache,
513  Instruction* instr);
514  static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
515  size_t size);
516  static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
517  void* page);
518 
519  enum Exception {
520  none,
521  kIntegerOverflow,
522  kIntegerUnderflow,
523  kDivideByZero,
524  kNumExceptions
525  };
526 
527  // Exceptions.
528  void SignalException(Exception e);
529 
530  // Handle arguments and return value for runtime FP functions.
531  void GetFpArgs(double* x, double* y, int32_t* z);
532  void SetFpResult(const double& result);
533 
534  void CallInternal(Address entry);
535 
536  // Architecture state.
537  // Registers.
538  int64_t registers_[kNumSimuRegisters];
539  // Coprocessor Registers.
540  // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
541  // order to support MSA registers
542  int64_t FPUregisters_[kNumFPURegisters * 2];
543  // FPU control register.
544  uint32_t FCSR_;
545  // MSA control register.
546  uint32_t MSACSR_;
547 
548  // Simulator support.
549  // Allocate 1MB for stack.
550  size_t stack_size_;
551  char* stack_;
552  bool pc_modified_;
553  int64_t icount_;
554  int break_count_;
555  EmbeddedVector<char, 128> trace_buf_;
556 
557  // Debugger input.
558  char* last_debugger_input_;
559 
560  v8::internal::Isolate* isolate_;
561 
562  // Registered breakpoints.
563  Instruction* break_pc_;
564  Instr break_instr_;
565 
566  // Stop is disabled if bit 31 is set.
567  static const uint32_t kStopDisabledBit = 1 << 31;
568 
569  // A stop is enabled, meaning the simulator will stop when meeting the
570  // instruction, if bit 31 of watched_stops_[code].count is unset.
571  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
572  // the breakpoint was hit or gone through.
573  struct StopCountAndDesc {
574  uint32_t count;
575  char* desc;
576  };
577  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
578 };
579 
580 } // namespace internal
581 } // namespace v8
582 
583 #endif // defined(USE_SIMULATOR)
584 #endif // V8_MIPS64_SIMULATOR_MIPS64_H_
Definition: libplatform.h:13