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 
CachePage()43   CachePage() {
44     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
45   }
46 
ValidityByte(int offset)47   char* ValidityByte(int offset) {
48     return &validity_map_[offset >> kLineShift];
49   }
50 
CachedData(int offset)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:
InstructionType()63   Type InstructionType() const { return type_; }
instr()64   inline Instruction* instr() const { return instr_; }
operand()65   inline int32_t operand() const { return operand_; }
66 
67  protected:
SimInstructionBase()68   SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
SimInstructionBase(Instruction * instr)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:
SimInstruction()81   SimInstruction() {}
82 
SimInstruction(Instruction * instr)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 
get_sp()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>
Call(Address entry,Args...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);
last_debugger_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 
rs_reg()407   inline int32_t rs_reg() const { return instr_.RsValue(); }
rs()408   inline int64_t rs() const { return get_register(rs_reg()); }
rs_u()409   inline uint64_t rs_u() const {
410     return static_cast<uint64_t>(get_register(rs_reg()));
411   }
rt_reg()412   inline int32_t rt_reg() const { return instr_.RtValue(); }
rt()413   inline int64_t rt() const { return get_register(rt_reg()); }
rt_u()414   inline uint64_t rt_u() const {
415     return static_cast<uint64_t>(get_register(rt_reg()));
416   }
rd_reg()417   inline int32_t rd_reg() const { return instr_.RdValue(); }
fr_reg()418   inline int32_t fr_reg() const { return instr_.FrValue(); }
fs_reg()419   inline int32_t fs_reg() const { return instr_.FsValue(); }
ft_reg()420   inline int32_t ft_reg() const { return instr_.FtValue(); }
fd_reg()421   inline int32_t fd_reg() const { return instr_.FdValue(); }
sa()422   inline int32_t sa() const { return instr_.SaValue(); }
lsa_sa()423   inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
ws_reg()424   inline int32_t ws_reg() const { return instr_.WsValue(); }
wt_reg()425   inline int32_t wt_reg() const { return instr_.WtValue(); }
wd_reg()426   inline int32_t wd_reg() const { return instr_.WdValue(); }
427 
SetResult(const int32_t rd_reg,const int64_t alu_out)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 
SetFPUWordResult(int32_t fd_reg,int32_t alu_out)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 
SetFPUWordResult2(int32_t fd_reg,int32_t alu_out)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 
SetFPUResult(int32_t fd_reg,int64_t alu_out)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 
SetFPUResult2(int32_t fd_reg,int64_t alu_out)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 
SetFPUFloatResult(int32_t fd_reg,float alu_out)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 
SetFPUDoubleResult(int32_t fd_reg,double alu_out)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.
CheckForbiddenSlot(int64_t current_pc)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.
BranchDelayInstructionDecode(Instruction * instr)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_
585