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/mips/constants-mips.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(entry, p0, p1, p2, p3, p4) \
27  entry(p0, p1, p2, p3, p4)
28
29typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
30                                   void*, int*, int, Address, int, Isolate*);
31
32
33// Call the generated regexp code directly. The code at the entry address
34// should act as a function matching the type arm_regexp_matcher.
35// The fifth argument is a dummy that reserves the space used for
36// the return address added by the ExitFrame in native calls.
37#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
38  (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
39      p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
40
41// The stack limit beyond which we will throw stack overflow errors in
42// generated code. Because generated code on mips uses the C stack, we
43// just use the C stack limit.
44class SimulatorStack : public v8::internal::AllStatic {
45 public:
46  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
47                                            uintptr_t c_limit) {
48    return c_limit;
49  }
50
51  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
52    return try_catch_address;
53  }
54
55  static inline void UnregisterCTryCatch() { }
56};
57
58} }  // namespace v8::internal
59
60// Calculated the stack limit beyond which we will throw stack overflow errors.
61// This macro must be called from a C++ method. It relies on being able to take
62// the address of "this" to get a value on the current execution stack and then
63// calculates the stack limit based on that value.
64// NOTE: The check for overflow is not safe as there is no guarantee that the
65// running thread has its stack in all memory up to address 0x00000000.
66#define GENERATED_CODE_STACK_LIMIT(limit) \
67  (reinterpret_cast<uintptr_t>(this) >= limit ? \
68      reinterpret_cast<uintptr_t>(this) - limit : 0)
69
70#else  // !defined(USE_SIMULATOR)
71// Running with a simulator.
72
73#include "src/hashmap.h"
74#include "src/assembler.h"
75
76namespace v8 {
77namespace internal {
78
79// -----------------------------------------------------------------------------
80// Utility functions
81
82class CachePage {
83 public:
84  static const int LINE_VALID = 0;
85  static const int LINE_INVALID = 1;
86
87  static const int kPageShift = 12;
88  static const int kPageSize = 1 << kPageShift;
89  static const int kPageMask = kPageSize - 1;
90  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
91  static const int kLineLength = 1 << kLineShift;
92  static const int kLineMask = kLineLength - 1;
93
94  CachePage() {
95    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
96  }
97
98  char* ValidityByte(int offset) {
99    return &validity_map_[offset >> kLineShift];
100  }
101
102  char* CachedData(int offset) {
103    return &data_[offset];
104  }
105
106 private:
107  char data_[kPageSize];   // The cached data.
108  static const int kValidityMapSize = kPageSize >> kLineShift;
109  char validity_map_[kValidityMapSize];  // One byte per line.
110};
111
112class Simulator {
113 public:
114  friend class MipsDebugger;
115
116  // Registers are declared in order. See SMRL chapter 2.
117  enum Register {
118    no_reg = -1,
119    zero_reg = 0,
120    at,
121    v0, v1,
122    a0, a1, a2, a3,
123    t0, t1, t2, t3, t4, t5, t6, t7,
124    s0, s1, s2, s3, s4, s5, s6, s7,
125    t8, t9,
126    k0, k1,
127    gp,
128    sp,
129    s8,
130    ra,
131    // LO, HI, and pc.
132    LO,
133    HI,
134    pc,   // pc must be the last register.
135    kNumSimuRegisters,
136    // aliases
137    fp = s8
138  };
139
140  // Coprocessor registers.
141  // Generated code will always use doubles. So we will only use even registers.
142  enum FPURegister {
143    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
144    f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
145    f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
146    f26, f27, f28, f29, f30, f31,
147    kNumFPURegisters
148  };
149
150  explicit Simulator(Isolate* isolate);
151  ~Simulator();
152
153  // The currently executing Simulator instance. Potentially there can be one
154  // for each native thread.
155  static Simulator* current(v8::internal::Isolate* isolate);
156
157  // Accessors for register state. Reading the pc value adheres to the MIPS
158  // architecture specification and is off by a 8 from the currently executing
159  // instruction.
160  void set_register(int reg, int32_t value);
161  void set_dw_register(int dreg, const int* dbl);
162  int32_t get_register(int reg) const;
163  double get_double_from_register_pair(int reg);
164  // Same for FPURegisters.
165  void set_fpu_register(int fpureg, int32_t value);
166  void set_fpu_register_float(int fpureg, float value);
167  void set_fpu_register_double(int fpureg, double value);
168  int32_t get_fpu_register(int fpureg) const;
169  int64_t get_fpu_register_long(int fpureg) const;
170  float get_fpu_register_float(int fpureg) const;
171  double get_fpu_register_double(int fpureg) const;
172  void set_fcsr_bit(uint32_t cc, bool value);
173  bool test_fcsr_bit(uint32_t cc);
174  bool set_fcsr_round_error(double original, double rounded);
175
176  // Special case of set_register and get_register to access the raw PC value.
177  void set_pc(int32_t value);
178  int32_t get_pc() const;
179
180  Address get_sp() {
181    return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
182  }
183
184  // Accessor to the internal simulator stack area.
185  uintptr_t StackLimit() const;
186
187  // Executes MIPS instructions until the PC reaches end_sim_pc.
188  void Execute();
189
190  // Call on program start.
191  static void Initialize(Isolate* isolate);
192
193  // V8 generally calls into generated JS code with 5 parameters and into
194  // generated RegExp code with 7 parameters. This is a convenience function,
195  // which sets up the simulator state and grabs the result on return.
196  int32_t Call(byte* entry, int argument_count, ...);
197  // Alternative: call a 2-argument double function.
198  double CallFP(byte* entry, double d0, double d1);
199
200  // Push an address onto the JS stack.
201  uintptr_t PushAddress(uintptr_t address);
202
203  // Pop an address from the JS stack.
204  uintptr_t PopAddress();
205
206  // Debugger input.
207  void set_last_debugger_input(char* input);
208  char* last_debugger_input() { return last_debugger_input_; }
209
210  // ICache checking.
211  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
212                          size_t size);
213
214  // Returns true if pc register contains one of the 'special_values' defined
215  // below (bad_ra, end_sim_pc).
216  bool has_bad_pc() const;
217
218 private:
219  enum special_values {
220    // Known bad pc value to ensure that the simulator does not execute
221    // without being properly setup.
222    bad_ra = -1,
223    // A pc value used to signal the simulator to stop execution.  Generally
224    // the ra is set to this value on transition from native C code to
225    // simulated execution, so that the simulator can "return" to the native
226    // C code.
227    end_sim_pc = -2,
228    // Unpredictable value.
229    Unpredictable = 0xbadbeaf
230  };
231
232  // Unsupported instructions use Format to print an error and stop execution.
233  void Format(Instruction* instr, const char* format);
234
235  // Read and write memory.
236  inline uint32_t ReadBU(int32_t addr);
237  inline int32_t ReadB(int32_t addr);
238  inline void WriteB(int32_t addr, uint8_t value);
239  inline void WriteB(int32_t addr, int8_t value);
240
241  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
242  inline int16_t ReadH(int32_t addr, Instruction* instr);
243  // Note: Overloaded on the sign of the value.
244  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
245  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
246
247  inline int ReadW(int32_t addr, Instruction* instr);
248  inline void WriteW(int32_t addr, int value, Instruction* instr);
249
250  inline double ReadD(int32_t addr, Instruction* instr);
251  inline void WriteD(int32_t addr, double value, Instruction* instr);
252
253  // Operations depending on endianness.
254  // Get Double Higher / Lower word.
255  inline int32_t GetDoubleHIW(double* addr);
256  inline int32_t GetDoubleLOW(double* addr);
257  // Set Double Higher / Lower word.
258  inline int32_t SetDoubleHIW(double* addr);
259  inline int32_t SetDoubleLOW(double* addr);
260
261  // Executing is handled based on the instruction type.
262  void DecodeTypeRegister(Instruction* instr);
263
264  // Helper function for DecodeTypeRegister.
265  void ConfigureTypeRegister(Instruction* instr,
266                             int32_t* alu_out,
267                             int64_t* i64hilo,
268                             uint64_t* u64hilo,
269                             int32_t* next_pc,
270                             int32_t* return_addr_reg,
271                             bool* do_interrupt);
272
273  void DecodeTypeImmediate(Instruction* instr);
274  void DecodeTypeJump(Instruction* instr);
275
276  // Used for breakpoints and traps.
277  void SoftwareInterrupt(Instruction* instr);
278
279  // Stop helper functions.
280  bool IsWatchpoint(uint32_t code);
281  void PrintWatchpoint(uint32_t code);
282  void HandleStop(uint32_t code, Instruction* instr);
283  bool IsStopInstruction(Instruction* instr);
284  bool IsEnabledStop(uint32_t code);
285  void EnableStop(uint32_t code);
286  void DisableStop(uint32_t code);
287  void IncreaseStopCounter(uint32_t code);
288  void PrintStopInfo(uint32_t code);
289
290
291  // Executes one instruction.
292  void InstructionDecode(Instruction* instr);
293  // Execute one instruction placed in a branch delay slot.
294  void BranchDelayInstructionDecode(Instruction* instr) {
295    if (instr->InstructionBits() == nopInstr) {
296      // Short-cut generic nop instructions. They are always valid and they
297      // never change the simulator state.
298      return;
299    }
300
301    if (instr->IsForbiddenInBranchDelay()) {
302      V8_Fatal(__FILE__, __LINE__,
303               "Eror:Unexpected %i opcode in a branch delay slot.",
304               instr->OpcodeValue());
305    }
306    InstructionDecode(instr);
307  }
308
309  // ICache.
310  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
311  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
312                           int size);
313  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
314
315  enum Exception {
316    none,
317    kIntegerOverflow,
318    kIntegerUnderflow,
319    kDivideByZero,
320    kNumExceptions
321  };
322  int16_t exceptions[kNumExceptions];
323
324  // Exceptions.
325  void SignalExceptions();
326
327  // Runtime call support.
328  static void* RedirectExternalReference(void* external_function,
329                                         ExternalReference::Type type);
330
331  // Handle arguments and return value for runtime FP functions.
332  void GetFpArgs(double* x, double* y, int32_t* z);
333  void SetFpResult(const double& result);
334
335  void CallInternal(byte* entry);
336
337  // Architecture state.
338  // Registers.
339  int32_t registers_[kNumSimuRegisters];
340  // Coprocessor Registers.
341  int32_t FPUregisters_[kNumFPURegisters];
342  // FPU control register.
343  uint32_t FCSR_;
344
345  // Simulator support.
346  // Allocate 1MB for stack.
347  static const size_t stack_size_ = 1 * 1024*1024;
348  char* stack_;
349  bool pc_modified_;
350  int icount_;
351  int break_count_;
352
353  // Debugger input.
354  char* last_debugger_input_;
355
356  // Icache simulation.
357  v8::internal::HashMap* i_cache_;
358
359  v8::internal::Isolate* isolate_;
360
361  // Registered breakpoints.
362  Instruction* break_pc_;
363  Instr break_instr_;
364
365  // Stop is disabled if bit 31 is set.
366  static const uint32_t kStopDisabledBit = 1 << 31;
367
368  // A stop is enabled, meaning the simulator will stop when meeting the
369  // instruction, if bit 31 of watched_stops_[code].count is unset.
370  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
371  // the breakpoint was hit or gone through.
372  struct StopCountAndDesc {
373    uint32_t count;
374    char* desc;
375  };
376  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
377};
378
379
380// When running with the simulator transition into simulated execution at this
381// point.
382#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
383    reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
384      FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
385
386#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
387    Simulator::current(Isolate::Current())->Call( \
388        entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
389
390
391// The simulator has its own stack. Thus it has a different stack limit from
392// the C-based native code.  Setting the c_limit to indicate a very small
393// stack cause stack overflow errors, since the simulator ignores the input.
394// This is unlikely to be an issue in practice, though it might cause testing
395// trouble down the line.
396class SimulatorStack : public v8::internal::AllStatic {
397 public:
398  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
399                                            uintptr_t c_limit) {
400    return Simulator::current(isolate)->StackLimit();
401  }
402
403  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
404    Simulator* sim = Simulator::current(Isolate::Current());
405    return sim->PushAddress(try_catch_address);
406  }
407
408  static inline void UnregisterCTryCatch() {
409    Simulator::current(Isolate::Current())->PopAddress();
410  }
411};
412
413} }  // namespace v8::internal
414
415#endif  // !defined(USE_SIMULATOR)
416#endif  // V8_MIPS_SIMULATOR_MIPS_H_
417