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