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