1257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
43100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
53100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
63100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Declares a Simulator for MIPS instructions if we are not generating a native
73100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// MIPS binary. This Simulator allows us to run and debug MIPS code generation
83100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// on regular desktop machines.
93100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// which will start execution in the Simulator or forwards to the real entry
113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// on a MIPS HW platform.
123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#ifndef V8_MIPS_SIMULATOR_MIPS_H_
143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define V8_MIPS_SIMULATOR_MIPS_H_
153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/allocation.h"
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/mips/constants-mips.h"
183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1944f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if !defined(USE_SIMULATOR)
2044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Running without a simulator on a native mips platform.
2144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2244f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace v8 {
2344f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace internal {
243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// When running without a simulator we call the entry directly.
263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
2744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  entry(p0, p1, p2, p3, p4)
2844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2944f0eee88ff00398ff7f715fab053374d808c90dSteve Blocktypedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                   void*, int*, int, Address, int, Isolate*);
31257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Call the generated regexp code directly. The code at the entry address
3444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// should act as a function matching the type arm_regexp_matcher.
3544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// The fifth argument is a dummy that reserves the space used for
3644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// the return address added by the ExitFrame in native calls.
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
38257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// The stack limit beyond which we will throw stack overflow errors in
423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// generated code. Because generated code on mips uses the C stack, we
433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// just use the C stack limit.
443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuclass SimulatorStack : public v8::internal::AllStatic {
453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu public:
46257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
47257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            uintptr_t c_limit) {
483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return c_limit;
493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return try_catch_address;
533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static inline void UnregisterCTryCatch() { }
563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu};
573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
5844f0eee88ff00398ff7f715fab053374d808c90dSteve Block} }  // namespace v8::internal
5944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Calculated the stack limit beyond which we will throw stack overflow errors.
613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// This macro must be called from a C++ method. It relies on being able to take
623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// the address of "this" to get a value on the current execution stack and then
633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// calculates the stack limit based on that value.
643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// NOTE: The check for overflow is not safe as there is no guarantee that the
653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// running thread has its stack in all memory up to address 0x00000000.
663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define GENERATED_CODE_STACK_LIMIT(limit) \
673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  (reinterpret_cast<uintptr_t>(this) >= limit ? \
683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      reinterpret_cast<uintptr_t>(this) - limit : 0)
693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#else  // !defined(USE_SIMULATOR)
7144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Running with a simulator.
723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/assembler.h"
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/hashmap.h"
753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7644f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace v8 {
7744f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace internal {
783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7944f0eee88ff00398ff7f715fab053374d808c90dSteve Block// -----------------------------------------------------------------------------
8044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Utility functions
813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
8244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass CachePage {
8344f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
8444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int LINE_VALID = 0;
8544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int LINE_INVALID = 1;
8644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kPageShift = 12;
8844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kPageSize = 1 << kPageShift;
8944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kPageMask = kPageSize - 1;
9044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kLineLength = 1 << kLineShift;
9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kLineMask = kLineLength - 1;
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
9444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CachePage() {
9544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
9644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* ValidityByte(int offset) {
9944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return &validity_map_[offset >> kLineShift];
10044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* CachedData(int offset) {
10344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return &data_[offset];
10444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10644f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
10744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char data_[kPageSize];   // The cached data.
10844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kValidityMapSize = kPageSize >> kLineShift;
10944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char validity_map_[kValidityMapSize];  // One byte per line.
11044f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
1113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuclass Simulator {
1133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu public:
11444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  friend class MipsDebugger;
1153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Registers are declared in order. See SMRL chapter 2.
1173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  enum Register {
1183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    no_reg = -1,
1193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    zero_reg = 0,
1203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    at,
1213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    v0, v1,
1223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    a0, a1, a2, a3,
1233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    t0, t1, t2, t3, t4, t5, t6, t7,
1243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    s0, s1, s2, s3, s4, s5, s6, s7,
1253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    t8, t9,
1263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    k0, k1,
1273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    gp,
1283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    sp,
1293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    s8,
1303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    ra,
131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // LO, HI, and pc.
1323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    LO,
1333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    HI,
1343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    pc,   // pc must be the last register.
1353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kNumSimuRegisters,
1363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // aliases
1373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    fp = s8
1383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
1393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Coprocessor registers.
1413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Generated code will always use doubles. So we will only use even registers.
1423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  enum FPURegister {
1433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
1453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
1463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    f26, f27, f28, f29, f30, f31,
1473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kNumFPURegisters
1483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
1493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  explicit Simulator(Isolate* isolate);
1513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ~Simulator();
1523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // The currently executing Simulator instance. Potentially there can be one
1543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // for each native thread.
15544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static Simulator* current(v8::internal::Isolate* isolate);
1563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Accessors for register state. Reading the pc value adheres to the MIPS
1583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // architecture specification and is off by a 8 from the currently executing
1593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // instruction.
1603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void set_register(int reg, int32_t value);
161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void set_dw_register(int dreg, const int* dbl);
1623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t get_register(int reg) const;
163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  double get_double_from_register_pair(int reg);
164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Same for FPURegisters.
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void set_fpu_register(int fpureg, int64_t value);
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void set_fpu_register_word(int fpureg, int32_t value);
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void set_fpu_register_hi_word(int fpureg, int32_t value);
16844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void set_fpu_register_float(int fpureg, float value);
1693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void set_fpu_register_double(int fpureg, double value);
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int64_t get_fpu_register(int fpureg) const;
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int32_t get_fpu_register_word(int fpureg) const;
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int32_t get_fpu_register_signed_word(int fpureg) const;
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int32_t get_fpu_register_hi_word(int fpureg) const;
17444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  float get_fpu_register_float(int fpureg) const;
1753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  double get_fpu_register_double(int fpureg) const;
17644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void set_fcsr_bit(uint32_t cc, bool value);
17744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool test_fcsr_bit(uint32_t cc);
17844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool set_fcsr_round_error(double original, double rounded);
1793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Special case of set_register and get_register to access the raw PC value.
1813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void set_pc(int32_t value);
1823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t get_pc() const;
1833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address get_sp() {
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Accessor to the internal simulator stack area.
1893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t StackLimit() const;
1903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Executes MIPS instructions until the PC reaches end_sim_pc.
1923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void Execute();
1933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Call on program start.
195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static void Initialize(Isolate* isolate);
1963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // V8 generally calls into generated JS code with 5 parameters and into
1983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // generated RegExp code with 7 parameters. This is a convenience function,
1993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // which sets up the simulator state and grabs the result on return.
20044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t Call(byte* entry, int argument_count, ...);
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Alternative: call a 2-argument double function.
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  double CallFP(byte* entry, double d0, double d1);
2033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Push an address onto the JS stack.
2053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t PushAddress(uintptr_t address);
2063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Pop an address from the JS stack.
2083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t PopAddress();
2093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Debugger input.
2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void set_last_debugger_input(char* input);
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  char* last_debugger_input() { return last_debugger_input_; }
2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
21444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // ICache checking.
21544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
21644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                          size_t size);
21744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
21844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Returns true if pc register contains one of the 'special_values' defined
21944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // below (bad_ra, end_sim_pc).
22044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool has_bad_pc() const;
22144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu private:
2233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  enum special_values {
2243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // Known bad pc value to ensure that the simulator does not execute
2253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // without being properly setup.
2263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    bad_ra = -1,
2273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // A pc value used to signal the simulator to stop execution.  Generally
2283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // the ra is set to this value on transition from native C code to
2293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // simulated execution, so that the simulator can "return" to the native
2303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // C code.
2313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    end_sim_pc = -2,
2323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // Unpredictable value.
2333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    Unpredictable = 0xbadbeaf
2343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
2353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Unsupported instructions use Format to print an error and stop execution.
2373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void Format(Instruction* instr, const char* format);
2383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Read and write memory.
2403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline uint32_t ReadBU(int32_t addr);
2413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int32_t ReadB(int32_t addr);
2423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteB(int32_t addr, uint8_t value);
2433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteB(int32_t addr, int8_t value);
2443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
2463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int16_t ReadH(int32_t addr, Instruction* instr);
2473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Note: Overloaded on the sign of the value.
2483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
2493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
2503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int ReadW(int32_t addr, Instruction* instr);
2523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteW(int32_t addr, int value, Instruction* instr);
2533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline double ReadD(int32_t addr, Instruction* instr);
2553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline void WriteD(int32_t addr, double value, Instruction* instr);
2563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Operations depending on endianness.
2583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Get Double Higher / Lower word.
2593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int32_t GetDoubleHIW(double* addr);
2603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int32_t GetDoubleLOW(double* addr);
2613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Set Double Higher / Lower word.
2623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int32_t SetDoubleHIW(double* addr);
2633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  inline int32_t SetDoubleLOW(double* addr);
2643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Executing is handled based on the instruction type.
2663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void DecodeTypeRegister(Instruction* instr);
26744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
26844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Helper function for DecodeTypeRegister.
26944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void ConfigureTypeRegister(Instruction* instr,
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             int32_t* alu_out,
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             int64_t* i64hilo,
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             uint64_t* u64hilo,
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             int32_t* next_pc,
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             int32_t* return_addr_reg,
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             bool* do_interrupt);
27644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void DecodeTypeImmediate(Instruction* instr);
2783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void DecodeTypeJump(Instruction* instr);
2793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Used for breakpoints and traps.
2813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void SoftwareInterrupt(Instruction* instr);
2823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Stop helper functions.
2843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool IsWatchpoint(uint32_t code);
2853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void PrintWatchpoint(uint32_t code);
2863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void HandleStop(uint32_t code, Instruction* instr);
2873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool IsStopInstruction(Instruction* instr);
2883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool IsEnabledStop(uint32_t code);
2893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void EnableStop(uint32_t code);
2903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void DisableStop(uint32_t code);
2913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void IncreaseStopCounter(uint32_t code);
2923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void PrintStopInfo(uint32_t code);
2933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Executes one instruction.
2963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void InstructionDecode(Instruction* instr);
2973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Execute one instruction placed in a branch delay slot.
2983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void BranchDelayInstructionDecode(Instruction* instr) {
2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (instr->InstructionBits() == nopInstr) {
3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Short-cut generic nop instructions. They are always valid and they
3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // never change the simulator state.
3023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return;
3033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (instr->IsForbiddenInBranchDelay()) {
3063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      V8_Fatal(__FILE__, __LINE__,
3073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu               "Eror:Unexpected %i opcode in a branch delay slot.",
30844f0eee88ff00398ff7f715fab053374d808c90dSteve Block               instr->OpcodeValue());
3093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
3103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    InstructionDecode(instr);
3113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
3123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // ICache.
31444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
31544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
31644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                           int size);
31744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
31844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  enum Exception {
3203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    none,
3213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kIntegerOverflow,
3223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kIntegerUnderflow,
3233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kDivideByZero,
3243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    kNumExceptions
3253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
3263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int16_t exceptions[kNumExceptions];
3273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Exceptions.
3293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void SignalExceptions();
3303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Runtime call support.
3323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static void* RedirectExternalReference(void* external_function,
33344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                         ExternalReference::Type type);
3343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Handle arguments and return value for runtime FP functions.
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void GetFpArgs(double* x, double* y, int32_t* z);
337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  void SetFpResult(const double& result);
338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void CallInternal(byte* entry);
3403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Architecture state.
3423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Registers.
3433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t registers_[kNumSimuRegisters];
3443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Coprocessor Registers.
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Note: FP32 mode uses only the lower 32-bit part of each element,
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the upper 32-bit is unpredictable.
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int64_t FPUregisters_[kNumFPURegisters];
34844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // FPU control register.
34944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  uint32_t FCSR_;
3503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Simulator support.
352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocate 1MB for stack.
353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static const size_t stack_size_ = 1 * 1024*1024;
3543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  char* stack_;
3553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool pc_modified_;
3563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int icount_;
35744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int break_count_;
35844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Debugger input.
3603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  char* last_debugger_input_;
3613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Icache simulation.
36344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::internal::HashMap* i_cache_;
3643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  v8::internal::Isolate* isolate_;
366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Registered breakpoints.
3683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Instruction* break_pc_;
3693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Instr break_instr_;
3703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Stop is disabled if bit 31 is set.
3723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static const uint32_t kStopDisabledBit = 1 << 31;
3733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // A stop is enabled, meaning the simulator will stop when meeting the
375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // instruction, if bit 31 of watched_stops_[code].count is unset.
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
3773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // the breakpoint was hit or gone through.
3783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  struct StopCountAndDesc {
3793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    uint32_t count;
3803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    char* desc;
3813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  };
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
3833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu};
3843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
38544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
38644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// When running with the simulator transition into simulated execution at this
38744f0eee88ff00398ff7f715fab053374d808c90dSteve Block// point.
38844f0eee88ff00398ff7f715fab053374d808c90dSteve Block#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
39044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
39144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Simulator::current(Isolate::Current())->Call( \
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
3953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// The simulator has its own stack. Thus it has a different stack limit from
3983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// the C-based native code.  Setting the c_limit to indicate a very small
3993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// stack cause stack overflow errors, since the simulator ignores the input.
4003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// This is unlikely to be an issue in practice, though it might cause testing
4013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// trouble down the line.
4023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuclass SimulatorStack : public v8::internal::AllStatic {
4033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu public:
404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            uintptr_t c_limit) {
406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return Simulator::current(isolate)->StackLimit();
4073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
4083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
4093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
41044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Simulator* sim = Simulator::current(Isolate::Current());
4113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return sim->PushAddress(try_catch_address);
4123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
4133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
4143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static inline void UnregisterCTryCatch() {
41544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Simulator::current(Isolate::Current())->PopAddress();
4163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
4173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu};
4183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
41944f0eee88ff00398ff7f715fab053374d808c90dSteve Block} }  // namespace v8::internal
4203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
42144f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif  // !defined(USE_SIMULATOR)
4223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#endif  // V8_MIPS_SIMULATOR_MIPS_H_
423