1257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
23100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Redistribution and use in source and binary forms, with or without
33100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// modification, are permitted provided that the following conditions are
43100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// met:
53100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//
63100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//     * Redistributions of source code must retain the above copyright
73100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       notice, this list of conditions and the following disclaimer.
83100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//     * Redistributions in binary form must reproduce the above
93100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       copyright notice, this list of conditions and the following
103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       disclaimer in the documentation and/or other materials provided
113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       with the distribution.
123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//     * Neither the name of Google Inc. nor the names of its
133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       contributors may be used to endorse or promote products derived
143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//       from this software without specific prior written permission.
153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu//
163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include <stdlib.h>
2944f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include <math.h>
3044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include <limits.h>
313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include <cstdarg>
323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include "v8.h"
333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
34f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_MIPS)
35f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
36589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch#include "cpu.h"
373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include "disasm.h"
383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include "assembler.h"
39257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "globals.h"    // Need the BitCast.
403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include "mips/constants-mips.h"
413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#include "mips/simulator-mips.h"
423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Only build the simulator if not compiling for real MIPS hardware.
4544f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if defined(USE_SIMULATOR)
463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
4744f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace v8 {
4844f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace internal {
493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
50257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Utils functions.
513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescubool HaveSameSign(int32_t a, int32_t b) {
5244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return ((a ^ b) >= 0);
5344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
5444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
5544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
5644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockuint32_t get_fcsr_condition_bit(uint32_t cc) {
5744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (cc == 0) {
5844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return 23;
5944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
6044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return 24 + cc;
6144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// This macro provides a platform independent use of sscanf. The reason for
663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// SScanF not being implemented in a platform independent was through
673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Library does not provide vsscanf.
693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define SScanF sscanf  // NOLINT
703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// The MipsDebugger class is used by the simulator while debugging simulated
723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// code.
7344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass MipsDebugger {
743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu public:
753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
7644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ~MipsDebugger();
773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void Stop(Instruction* instr);
793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void Debug();
8044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Print all registers with a nice formatting.
8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void PrintAllRegs();
8244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void PrintAllRegsIncludingFPU();
833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu private:
853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // We set the breakpoint code to 0xfffff to easily recognize it.
863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static const Instr kNopInstr =  0x0;
883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Simulator* sim_;
903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t GetRegisterValue(int regnum);
9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t GetFPURegisterValueInt(int regnum);
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int64_t GetFPURegisterValueLong(int regnum);
9444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  float GetFPURegisterValueFloat(int regnum);
9544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  double GetFPURegisterValueDouble(int regnum);
963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool GetValue(const char* desc, int32_t* value);
973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Set or delete a breakpoint. Returns true if successful.
993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool SetBreakpoint(Instruction* breakpc);
1003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool DeleteBreakpoint(Instruction* breakpc);
1013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Undo and redo all breakpoints. This is needed to bracket disassembly and
1033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // execution to skip past breakpoints when run from the debugger.
1043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void UndoBreakpoints();
1053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void RedoBreakpoints();
1063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu};
1073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
10944f0eee88ff00398ff7f715fab053374d808c90dSteve BlockMipsDebugger::~MipsDebugger() {
1103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
1113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
11244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#ifdef GENERATED_CODE_COVERAGE
1143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescustatic FILE* coverage_log = NULL;
1153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescustatic void InitializeCoverage() {
1183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
1193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (file_name != NULL) {
1203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    coverage_log = fopen(file_name, "aw+");
1213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
1233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::Stop(Instruction* instr) {
1263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the stop code.
1273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  uint32_t code = instr->Bits(25, 6);
1283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Retrieve the encoded address, which comes just after this stop.
1293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  char** msg_address =
1303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
1313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  char* msg = *msg_address;
1323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(msg != NULL);
1333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Update this stop description.
1353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!watched_stops[code].desc) {
1363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    watched_stops[code].desc = msg;
1373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
1383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strlen(msg) > 0) {
1403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (coverage_log != NULL) {
1413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      fprintf(coverage_log, "%s\n", str);
1423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      fflush(coverage_log);
1433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
1443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Overwrite the instruction and address with nops.
1453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    instr->SetInstructionBits(kNopInstr);
1463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
1473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
1493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
1503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
15144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#else  // GENERATED_CODE_COVERAGE
1533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define UNSUPPORTED() printf("Unsupported instruction.\n");
1553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescustatic void InitializeCoverage() {}
1573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
15944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::Stop(Instruction* instr) {
1603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the stop code.
1613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  uint32_t code = instr->Bits(25, 6);
1623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Retrieve the encoded address, which comes just after this stop.
1633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
1643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Instruction::kInstrSize);
1653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Update this stop description.
1663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!sim_->watched_stops[code].desc) {
1673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    sim_->watched_stops[code].desc = msg;
1683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
1693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  PrintF("Simulator hit %s (%u)\n", msg, code);
1703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
1713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Debug();
1723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
1736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#endif  // GENERATED_CODE_COVERAGE
1743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
17644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint32_t MipsDebugger::GetRegisterValue(int regnum) {
1773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (regnum == kNumSimuRegisters) {
1783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return sim_->get_pc();
1793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  } else {
1803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return sim_->get_register(regnum);
1813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
1833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
18544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
18644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (regnum == kNumFPURegisters) {
18744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_pc();
18844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
18944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_fpu_register(regnum);
19044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
19144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
19244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
19344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
19444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
19544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (regnum == kNumFPURegisters) {
19644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_pc();
19744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
19844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_fpu_register_long(regnum);
19944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
20044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
20144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
20244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
20344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockfloat MipsDebugger::GetFPURegisterValueFloat(int regnum) {
20444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (regnum == kNumFPURegisters) {
20544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_pc();
20644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
20744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_fpu_register_float(regnum);
20844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
20944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
21044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
21144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
21244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockdouble MipsDebugger::GetFPURegisterValueDouble(int regnum) {
21344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (regnum == kNumFPURegisters) {
21444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_pc();
21544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
21644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return sim_->get_fpu_register_double(regnum);
21744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
21844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
21944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
22044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
22144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool MipsDebugger::GetValue(const char* desc, int32_t* value) {
2223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int regnum = Registers::Number(desc);
22344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int fpuregnum = FPURegisters::Number(desc);
22444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (regnum != kInvalidRegister) {
2263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    *value = GetRegisterValue(regnum);
2273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return true;
22844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else if (fpuregnum != kInvalidFPURegister) {
22944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    *value = GetFPURegisterValueInt(fpuregnum);
23044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return true;
23144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else if (strncmp(desc, "0x", 2) == 0) {
23244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
2333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  } else {
2343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return SScanF(desc, "%i", value) == 1;
2353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
2363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return false;
2373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
2383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
24044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
2413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Check if a breakpoint can be set. If not return without any side-effects.
2423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (sim_->break_pc_ != NULL) {
2433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return false;
2443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
2453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Set the breakpoint.
2473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  sim_->break_pc_ = breakpc;
2483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  sim_->break_instr_ = breakpc->InstructionBits();
2493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Not setting the breakpoint instruction in the code itself. It will be set
2503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // when the debugger shell continues.
2513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return true;
2523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
2533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
25544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
2563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (sim_->break_pc_ != NULL) {
2573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
2583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
2593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  sim_->break_pc_ = NULL;
2613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  sim_->break_instr_ = 0;
2623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return true;
2633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
2643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::UndoBreakpoints() {
2673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (sim_->break_pc_ != NULL) {
2683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
2693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
2703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
2713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::RedoBreakpoints() {
2743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (sim_->break_pc_ != NULL) {
2753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
2763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
2773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
2783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
28044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::PrintAllRegs() {
2813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
2823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("\n");
284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // at, v0, a0.
2853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
2863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         REG_INFO(1), REG_INFO(2), REG_INFO(4));
287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v1, a1.
2883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
2893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         "", REG_INFO(3), REG_INFO(5));
290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2.
2913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3.
2933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
2943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("\n");
2953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // t0-t7, s0-s7
2963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  for (int i = 0; i < 8; i++) {
2973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
2983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu           REG_INFO(8+i), REG_INFO(16+i));
2993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
3003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("\n");
301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t8, k0, LO.
3023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
3033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         REG_INFO(24), REG_INFO(26), REG_INFO(32));
304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t9, k1, HI.
3053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
3063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         REG_INFO(25), REG_INFO(27), REG_INFO(33));
307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp, fp, gp.
3083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
3093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         REG_INFO(29), REG_INFO(30), REG_INFO(28));
310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // pc.
3113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
3123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu         REG_INFO(31), REG_INFO(34));
31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
31444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#undef REG_INFO
31544f0eee88ff00398ff7f715fab053374d808c90dSteve Block#undef FPU_REG_INFO
31644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
31744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
31844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
31944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::PrintAllRegsIncludingFPU() {
32044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
32144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        GetFPURegisterValueInt(n+1), \
32244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        GetFPURegisterValueInt(n), \
32344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        GetFPURegisterValueDouble(n)
32444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
32544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintAllRegs();
32644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
32744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("\n\n");
328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // f0, f1, f2, ... f31.
32944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
33044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
33144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
33244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
33344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
33444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
33544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
33644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
33744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
33844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
33944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
34044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
34144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
34244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
34344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
34444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
34544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef REG_INFO
34744f0eee88ff00398ff7f715fab053374d808c90dSteve Block#undef FPU_REG_INFO
3483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
3493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
35044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
35144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid MipsDebugger::Debug() {
3523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  intptr_t last_pc = -1;
3533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool done = false;
3543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define COMMAND_SIZE 63
3563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define ARG_SIZE 255
3573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define STR(a) #a
3593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#define XSTR(a) STR(a)
3603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  char cmd[COMMAND_SIZE + 1];
3623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  char arg1[ARG_SIZE + 1];
3633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  char arg2[ARG_SIZE + 1];
36444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* argv[3] = { cmd, arg1, arg2 };
3653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure to have a proper terminating character if reaching the limit.
3673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  cmd[COMMAND_SIZE] = 0;
3683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  arg1[ARG_SIZE] = 0;
3693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  arg2[ARG_SIZE] = 0;
3703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Undo all set breakpoints while running in the debugger shell. This will
3723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // make them invisible to all commands.
3733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  UndoBreakpoints();
3743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
3753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
3763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (last_pc != sim_->get_pc()) {
3773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      disasm::NameConverter converter;
3783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      disasm::Disassembler dasm(converter);
379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Use a reasonably large buffer.
3803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      v8::internal::EmbeddedVector<char, 256> buffer;
3813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      dasm.InstructionDecode(buffer,
382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             reinterpret_cast<byte*>(sim_->get_pc()));
3833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      PrintF("  0x%08x  %s\n", sim_->get_pc(), buffer.start());
3843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      last_pc = sim_->get_pc();
3853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
3863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    char* line = ReadLine("sim> ");
3873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (line == NULL) {
3883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
3893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    } else {
3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      char* last_input = sim_->last_debugger_input();
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (strcmp(line, "\n") == 0 && last_input != NULL) {
3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        line = last_input;
3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      } else {
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // Ownership is transferred to sim_;
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        sim_->set_last_debugger_input(line);
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      // Use sscanf to parse the individual parts of the command line. At the
3983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      // moment no command expects more than two parameters.
39944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      int argc = SScanF(line,
4003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                        "%" XSTR(COMMAND_SIZE) "s "
4013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                        "%" XSTR(ARG_SIZE) "s "
4023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                        "%" XSTR(ARG_SIZE) "s",
4033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                        cmd, arg1, arg2);
4043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
40544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
40644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!(instr->IsTrap()) ||
40744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            instr->InstructionBits() == rtCallRedirInstr) {
4083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          sim_->InstructionDecode(
40944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              reinterpret_cast<Instruction*>(sim_->get_pc()));
4103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
4113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          // Allow si to jump over generated breakpoints.
4123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          PrintF("/!\\ Jumping over generated breakpoint.\n");
41344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
4143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
4153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
4163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        // Execute the one instruction we broke at with breakpoints disabled.
4173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
4183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        // Leave the debugger shell.
4193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        done = true;
4203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
42144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == 2) {
4223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value;
42344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          float fvalue;
4243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (strcmp(arg1, "all") == 0) {
4253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            PrintAllRegs();
42644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else if (strcmp(arg1, "allf") == 0) {
42744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            PrintAllRegsIncludingFPU();
4283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          } else {
42944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            int regnum = Registers::Number(arg1);
43044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            int fpuregnum = FPURegisters::Number(arg1);
43144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
43244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            if (regnum != kInvalidRegister) {
43344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              value = GetRegisterValue(regnum);
4343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              PrintF("%s: 0x%08x %d \n", arg1, value, value);
43544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            } else if (fpuregnum != kInvalidFPURegister) {
43644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              if (fpuregnum % 2 == 1) {
43744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                value = GetFPURegisterValueInt(fpuregnum);
43844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                fvalue = GetFPURegisterValueFloat(fpuregnum);
43944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
44044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              } else {
44144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                double dfvalue;
44244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
44344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
44444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                dfvalue = GetFPURegisterValueDouble(fpuregnum);
44544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
44644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       FPURegisters::Name(fpuregnum+1),
44744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       FPURegisters::Name(fpuregnum),
44844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       lvalue1,
44944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       lvalue2,
45044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       dfvalue);
45144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
4523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            } else {
4533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              PrintF("%s unrecognized\n", arg1);
4543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            }
4553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
4563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
45744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (argc == 3) {
45844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            if (strcmp(arg2, "single") == 0) {
45944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              int32_t value;
46044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              float fvalue;
46144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              int fpuregnum = FPURegisters::Number(arg1);
46244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
46344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              if (fpuregnum != kInvalidFPURegister) {
46444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                value = GetFPURegisterValueInt(fpuregnum);
46544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                fvalue = GetFPURegisterValueFloat(fpuregnum);
46644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
46744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              } else {
46844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                PrintF("%s unrecognized\n", arg1);
46944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
47044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            } else {
47144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              PrintF("print <fpu register> single\n");
47244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            }
47344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else {
47444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            PrintF("print <register> or print <fpu register> single\n");
47544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
4763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
4773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if ((strcmp(cmd, "po") == 0)
4783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                 || (strcmp(cmd, "printobject") == 0)) {
47944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == 2) {
4803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value;
4813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (GetValue(arg1, &value)) {
4823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            Object* obj = reinterpret_cast<Object*>(value);
4833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            PrintF("%s: \n", arg1);
4843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#ifdef DEBUG
4853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            obj->PrintLn();
4863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#else
4873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            obj->ShortPrint();
4883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            PrintF("\n");
4893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#endif
4903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          } else {
4913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            PrintF("%s unrecognized\n", arg1);
4923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
4933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
4943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          PrintF("printobject <value>\n");
4953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
49644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
49744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        int32_t* cur = NULL;
49844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        int32_t* end = NULL;
49944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        int next_arg = 1;
50044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
50144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (strcmp(cmd, "stack") == 0) {
50244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {  // Command "mem".
50444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          int32_t value;
50544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!GetValue(arg1, &value)) {
50644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            PrintF("%s unrecognized\n", arg1);
50744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            continue;
50844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
50944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cur = reinterpret_cast<int32_t*>(value);
51044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          next_arg++;
51144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
51244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
51344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        int32_t words;
51444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == next_arg) {
51544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          words = 10;
51644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        } else if (argc == next_arg + 1) {
51744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!GetValue(argv[next_arg], &words)) {
51844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            words = 10;
51944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
52044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
52144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        end = cur + words;
52244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
52344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        while (cur < end) {
524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          PrintF("  0x%08x:  0x%08x %10d",
52544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          int value = *cur;
528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          Heap* current_heap = v8::internal::Isolate::Current()->heap();
529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (current_heap->Contains(obj) || ((value & 1) == 0)) {
530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            PrintF(" (");
531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            if ((value & 1) == 0) {
532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              PrintF("smi %d", value / 2);
533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            } else {
534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              obj->ShortPrint();
535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            }
536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            PrintF(")");
537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          PrintF("\n");
53944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cur++;
54044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
54144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else if ((strcmp(cmd, "disasm") == 0) ||
543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 (strcmp(cmd, "dpc") == 0) ||
544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 (strcmp(cmd, "di") == 0)) {
5453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        disasm::NameConverter converter;
5463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        disasm::Disassembler dasm(converter);
547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Use a reasonably large buffer.
5483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        v8::internal::EmbeddedVector<char, 256> buffer;
5493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        byte* cur = NULL;
551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        byte* end = NULL;
5523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
55344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == 1) {
554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          cur = reinterpret_cast<byte*>(sim_->get_pc());
55544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          end = cur + (10 * Instruction::kInstrSize);
55644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        } else if (argc == 2) {
557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          int regnum = Registers::Number(arg1);
558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // The argument is an address or a register name.
560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            int32_t value;
561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            if (GetValue(arg1, &value)) {
562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              cur = reinterpret_cast<byte*>(value);
563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              // Disassemble 10 instructions at <arg1>.
564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              end = cur + (10 * Instruction::kInstrSize);
565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            }
566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // The argument is the number of instructions.
568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            int32_t value;
569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            if (GetValue(arg1, &value)) {
570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              cur = reinterpret_cast<byte*>(sim_->get_pc());
571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              // Disassemble <arg1> instructions.
572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              end = cur + (value * Instruction::kInstrSize);
573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            }
5743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
5753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
5763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value1;
5773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value2;
5783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            cur = reinterpret_cast<byte*>(value1);
58044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            end = cur + (value2 * Instruction::kInstrSize);
5813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
5823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
5833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
5843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        while (cur < end) {
5853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          dasm.InstructionDecode(buffer, cur);
58644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          PrintF("  0x%08x  %s\n",
58744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              reinterpret_cast<intptr_t>(cur), buffer.start());
58844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cur += Instruction::kInstrSize;
5893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
5903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if (strcmp(cmd, "gdb") == 0) {
5913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("relinquishing control to gdb\n");
5923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        v8::internal::OS::DebugBreak();
5933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("regaining control from gdb\n");
5943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if (strcmp(cmd, "break") == 0) {
59544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == 2) {
5963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value;
5973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (GetValue(arg1, &value)) {
5983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
5993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              PrintF("setting breakpoint failed\n");
6003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            }
6013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          } else {
6023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            PrintF("%s unrecognized\n", arg1);
6033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
6043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
6053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          PrintF("break <address>\n");
6063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
6073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if (strcmp(cmd, "del") == 0) {
6083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        if (!DeleteBreakpoint(NULL)) {
6093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          PrintF("deleting breakpoint failed\n");
6103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
6113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if (strcmp(cmd, "flags") == 0) {
6123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("No flags on MIPS !\n");
6133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      } else if (strcmp(cmd, "stop") == 0) {
6143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        int32_t value;
6153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        intptr_t stop_pc = sim_->get_pc() -
6163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            2 * Instruction::kInstrSize;
6173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
6183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Instruction* msg_address =
6193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          reinterpret_cast<Instruction*>(stop_pc +
6203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              Instruction::kInstrSize);
6213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
6223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          // Remove the current stop.
6233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          if (sim_->IsStopInstruction(stop_instr)) {
6243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            stop_instr->SetInstructionBits(kNopInstr);
6253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            msg_address->SetInstructionBits(kNopInstr);
6263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          } else {
6273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            PrintF("Not at debugger stop.\n");
6283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          }
6293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        } else if (argc == 3) {
6303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          // Print information about all/the specified breakpoint(s).
6313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          if (strcmp(arg1, "info") == 0) {
6323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            if (strcmp(arg2, "all") == 0) {
6333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              PrintF("Stop information:\n");
6343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              for (uint32_t i = kMaxWatchpointCode + 1;
6353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i <= kMaxStopCode;
6363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i++) {
6373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                sim_->PrintStopInfo(i);
6383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              }
6393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else if (GetValue(arg2, &value)) {
6403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              sim_->PrintStopInfo(value);
6413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else {
6423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              PrintF("Unrecognized argument.\n");
6433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            }
6443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          } else if (strcmp(arg1, "enable") == 0) {
6453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            // Enable all/the specified breakpoint(s).
6463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            if (strcmp(arg2, "all") == 0) {
6473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              for (uint32_t i = kMaxWatchpointCode + 1;
6483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i <= kMaxStopCode;
6493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i++) {
6503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                sim_->EnableStop(i);
6513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              }
6523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else if (GetValue(arg2, &value)) {
6533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              sim_->EnableStop(value);
6543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else {
6553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              PrintF("Unrecognized argument.\n");
6563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            }
6573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          } else if (strcmp(arg1, "disable") == 0) {
6583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            // Disable all/the specified breakpoint(s).
6593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            if (strcmp(arg2, "all") == 0) {
6603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              for (uint32_t i = kMaxWatchpointCode + 1;
6613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i <= kMaxStopCode;
6623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                   i++) {
6633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                sim_->DisableStop(i);
6643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              }
6653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else if (GetValue(arg2, &value)) {
6663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              sim_->DisableStop(value);
6673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            } else {
6683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              PrintF("Unrecognized argument.\n");
6693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            }
6703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          }
6713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        } else {
6723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          PrintF("Wrong usage. Use help command for more information.\n");
6733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        }
6743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Print registers and disassemble.
6763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintAllRegs();
6773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("\n");
6783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
6793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        disasm::NameConverter converter;
6803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        disasm::Disassembler dasm(converter);
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Use a reasonably large buffer.
6823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        v8::internal::EmbeddedVector<char, 256> buffer;
6833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        byte* cur = NULL;
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        byte* end = NULL;
6863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
68744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (argc == 1) {
688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          cur = reinterpret_cast<byte*>(sim_->get_pc());
68944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          end = cur + (10 * Instruction::kInstrSize);
69044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        } else if (argc == 2) {
6913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value;
6923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (GetValue(arg1, &value)) {
693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            cur = reinterpret_cast<byte*>(value);
6943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            // no length parameter passed, assume 10 instructions
69544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            end = cur + (10 * Instruction::kInstrSize);
6963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
6973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else {
6983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value1;
6993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          int32_t value2;
7003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            cur = reinterpret_cast<byte*>(value1);
70244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            end = cur + (value2 * Instruction::kInstrSize);
7033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
7043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
7053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        while (cur < end) {
7073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          dasm.InstructionDecode(buffer, cur);
70844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          PrintF("  0x%08x  %s\n",
70944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 reinterpret_cast<intptr_t>(cur), buffer.start());
71044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cur += Instruction::kInstrSize;
7113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
7123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
7133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("cont\n");
7143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  continue execution (alias 'c')\n");
7153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("stepi\n");
7163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  step one instruction (alias 'si')\n");
7173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("print <register>\n");
7183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  print register content (alias 'p')\n");
7193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  use register name 'all' to print all registers\n");
7203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("printobject <register>\n");
7213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  print an object from a register (alias 'po')\n");
72244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        PrintF("stack [<words>]\n");
72344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        PrintF("  dump stack content, default dump 10 words)\n");
72444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        PrintF("mem <address> [<words>]\n");
72544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        PrintF("  dump memory content, default dump 10 words)\n");
7263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("flags\n");
7273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  print flags\n");
7283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("disasm [<instructions>]\n");
729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("disasm [<address/register>]\n");
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("disasm [[<address/register>] <instructions>]\n");
731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("  disassemble code, default is 10 instructions\n");
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("  from pc (alias 'di')\n");
7333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("gdb\n");
7343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  enter gdb\n");
7353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("break <address>\n");
7363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  set a break point on the address\n");
7373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("del\n");
7383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("  delete the breakpoint\n");
7393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("stop feature:\n");
7403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("  Description:\n");
7413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    Stops are debug instructions inserted by\n");
7423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    the Assembler::stop() function.\n");
7433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    When hitting a stop, the Simulator will\n");
7443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    stop and and give control to the Debugger.\n");
7453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    All stop codes are watched:\n");
7463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    - They can be enabled / disabled: the Simulator\n");
7473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("       will / won't stop when hitting them.\n");
7483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    - The Simulator keeps track of how many times they \n");
7493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      are met. (See the info command.) Going over a\n");
7503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      disabled stop still increases its counter. \n");
7513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("  Commands:\n");
7523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    stop info all/<code> : print infos about number <code>\n");
7533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      or all stop(s).\n");
7543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    stop enable/disable all/<code> : enables / disables\n");
7553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      all or number <code> stop(s)\n");
7563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("    stop unstop\n");
7573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      ignore the stop instruction at the current location\n");
7583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        PrintF("      from now on\n");
7593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else {
7603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF("Unknown command: %s\n", cmd);
7613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
7623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
7633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
7643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Add all the breakpoints back to stop execution and enter the debugger
7663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // shell when hit.
7673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  RedoBreakpoints();
7683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef COMMAND_SIZE
7703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef ARG_SIZE
7713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef STR
7733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef XSTR
7743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
7753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
7763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
77744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic bool ICacheMatch(void* one, void* two) {
77844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
77944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
78044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return one == two;
78144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
78244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
78444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic uint32_t ICacheHash(void* key) {
78544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
78644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
7873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
78944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic bool AllOnOnePage(uintptr_t start, int size) {
79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t start_page = (start & ~CachePage::kPageMask);
79144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
79244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return start_page == end_page;
79344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
79444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
79544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Simulator::set_last_debugger_input(char* input) {
7973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  DeleteArray(last_debugger_input_);
7983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  last_debugger_input_ = input;
7993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
8003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
8013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
80244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::FlushICache(v8::internal::HashMap* i_cache,
80344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            void* start_addr,
80444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            size_t size) {
80544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
80644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int intra_line = (start & CachePage::kLineMask);
80744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  start -= intra_line;
80844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  size += intra_line;
80944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  size = ((size - 1) | CachePage::kLineMask) + 1;
81044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int offset = (start & CachePage::kPageMask);
81144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  while (!AllOnOnePage(start, size - 1)) {
81244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int bytes_to_flush = CachePage::kPageSize - offset;
81344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FlushOnePage(i_cache, start, bytes_to_flush);
81444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    start += bytes_to_flush;
81544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    size -= bytes_to_flush;
81644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT_EQ(0, start & CachePage::kPageMask);
81744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    offset = 0;
81844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
81944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (size != 0) {
82044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FlushOnePage(i_cache, start, size);
82144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
82244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
82344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82544f0eee88ff00398ff7f715fab053374d808c90dSteve BlockCachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
82644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        ICacheHash(page),
828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        true);
82944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (entry->value == NULL) {
83044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CachePage* new_page = new CachePage();
83144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    entry->value = new_page;
83244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
83344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return reinterpret_cast<CachePage*>(entry->value);
83444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
83544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
83644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
83744f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Flush from start up to and not including start + size.
83844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
83944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                             intptr_t start,
84044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                             int size) {
84144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(size <= CachePage::kPageSize);
84244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(AllOnOnePage(start, size - 1));
84344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((start & CachePage::kLineMask) == 0);
84444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((size & CachePage::kLineMask) == 0);
84544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
84644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int offset = (start & CachePage::kPageMask);
84744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CachePage* cache_page = GetCachePage(i_cache, page);
84844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* valid_bytemap = cache_page->ValidityByte(offset);
84944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
85044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
85144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
85244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
85344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::CheckICache(v8::internal::HashMap* i_cache,
85444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            Instruction* instr) {
85544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t address = reinterpret_cast<intptr_t>(instr);
85644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
85744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
85844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int offset = (address & CachePage::kPageMask);
85944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CachePage* cache_page = GetCachePage(i_cache, page);
86044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* cache_valid_byte = cache_page->ValidityByte(offset);
86144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
86244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
86344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (cache_hit) {
86444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Check that the data in memory matches the contents of the I-cache.
86544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CHECK(memcmp(reinterpret_cast<void*>(instr),
86644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 cache_page->CachedData(offset),
86744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 Instruction::kInstrSize) == 0);
86844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
86944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Cache miss.  Load memory into the cache.
87044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    memcpy(cached_line, line, CachePage::kLineLength);
87144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    *cache_valid_byte = CachePage::LINE_VALID;
87244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
87344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
8743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
8753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid Simulator::Initialize(Isolate* isolate) {
877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (isolate->simulator_initialized()) return;
878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  isolate->set_simulator_initialized(true);
879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ::v8::internal::ExternalReference::set_redirector(isolate,
880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                    &RedirectExternalReference);
8813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
8823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
8833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochSimulator::Simulator(Isolate* isolate) : isolate_(isolate) {
88544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  i_cache_ = isolate_->simulator_i_cache();
88644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (i_cache_ == NULL) {
88744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    i_cache_ = new v8::internal::HashMap(&ICacheMatch);
88844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate_->set_simulator_i_cache(i_cache_);
88944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Initialize(isolate);
8913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up simulator support first. Some of this information is needed to
8923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // setup the architecture state.
89344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  stack_ = reinterpret_cast<char*>(malloc(stack_size_));
8943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  pc_modified_ = false;
8953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  icount_ = 0;
89644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  break_count_ = 0;
8973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  break_pc_ = NULL;
8983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  break_instr_ = 0;
8993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up architecture state.
9013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // All registers are initialized to zero to start with.
9023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  for (int i = 0; i < kNumSimuRegisters; i++) {
9033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    registers_[i] = 0;
9043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
90544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i = 0; i < kNumFPURegisters; i++) {
90644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FPUregisters_[i] = 0;
90744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
90844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  FCSR_ = 0;
9093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // The sp is initialized to point to the bottom (high address) of the
9113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // allocated stack area. To be safe in potential stack underflows we leave
9123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // some buffer below.
91344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
9143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // The ra and pc are initialized to a known bad value that will cause an
9153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // access violation if the simulator ever tries to execute it.
9163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  registers_[pc] = bad_ra;
9173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  registers_[ra] = bad_ra;
9183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  InitializeCoverage();
91944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i = 0; i < kNumExceptions; i++) {
92044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    exceptions[i] = 0;
92144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
9223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
9233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  last_debugger_input_ = NULL;
9243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
9253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// When the generated code calls an external reference we need to catch that in
9283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// the simulator.  The external reference will be a function compiled for the
9293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// host architecture.  We need to call that function instead of trying to
9303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// execute it with the simulator.  We do that by redirecting the external
9313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// reference to a swi (software-interrupt) instruction that is handled by
9323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// the simulator.  We write the original destination of the jump just at a known
9333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// offset from the swi instruction so the simulator knows what to call.
9343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuclass Redirection {
9353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu public:
93644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Redirection(void* external_function, ExternalReference::Type type)
9373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      : external_function_(external_function),
9383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        swi_instruction_(rtCallRedirInstr),
93944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        type_(type),
94044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        next_(NULL) {
94144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Isolate* isolate = Isolate::Current();
94244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    next_ = isolate->simulator_redirection();
94344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Simulator::current(isolate)->
94444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        FlushICache(isolate->simulator_i_cache(),
94544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                    reinterpret_cast<void*>(&swi_instruction_),
94644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                    Instruction::kInstrSize);
94744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate->set_simulator_redirection(this);
9483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
9493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void* address_of_swi_instruction() {
9513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return reinterpret_cast<void*>(&swi_instruction_);
9523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
9533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void* external_function() { return external_function_; }
95544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference::Type type() { return type_; }
9563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
95744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static Redirection* Get(void* external_function,
95844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                          ExternalReference::Type type) {
95944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Isolate* isolate = Isolate::Current();
96044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Redirection* current = isolate->simulator_redirection();
96144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    for (; current != NULL; current = current->next_) {
9623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if (current->external_function_ == external_function) return current;
9633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
96444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return new Redirection(external_function, type);
9653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
9663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
9683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
9693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    char* addr_of_redirection =
9703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
9713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return reinterpret_cast<Redirection*>(addr_of_redirection);
9723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
9733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu private:
9753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  void* external_function_;
9763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uint32_t swi_instruction_;
97744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference::Type type_;
9783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Redirection* next_;
9793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu};
9803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid* Simulator::RedirectExternalReference(void* external_function,
98344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                           ExternalReference::Type type) {
98444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Redirection* redirection = Redirection::Get(external_function, type);
9853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return redirection->address_of_swi_instruction();
9863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
9873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
9893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Get the active Simulator for the current thread.
99044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSimulator* Simulator::current(Isolate* isolate) {
99144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch       isolate->FindOrAllocatePerThreadDataForThisThread();
993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(isolate_data != NULL);
99444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(isolate_data != NULL);
99544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
99644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Simulator* sim = isolate_data->simulator();
9973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (sim == NULL) {
99844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // TODO(146): delete the simulator object when a thread/isolate goes away.
999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    sim = new Simulator(isolate);
100044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate_data->set_simulator(sim);
10013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
10023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return sim;
10033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Sets the register in the architecture state. It will also deal with updating
10073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Simulator internal state for special registers such as PC.
10083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::set_register(int reg, int32_t value) {
10093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
10103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (reg == pc) {
10113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    pc_modified_ = true;
10123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
10133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Zero register always holds 0.
10153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  registers_[reg] = (reg == 0) ? 0 : value;
10163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
101844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
10193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::set_fpu_register(int fpureg, int32_t value) {
10203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
10213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  FPUregisters_[fpureg] = value;
10223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
102444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
102544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::set_fpu_register_float(int fpureg, float value) {
102644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
102744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  *BitCast<float*>(&FPUregisters_[fpureg]) = value;
102844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
102944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
103044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
10313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::set_fpu_register_double(int fpureg, double value) {
10323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
103344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  *BitCast<double*>(&FPUregisters_[fpureg]) = value;
10343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
10373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Get the register from the architecture state. This function does handle
10383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// the special case of accessing the PC register.
10393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint32_t Simulator::get_register(int reg) const {
10403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
10413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (reg == 0)
10423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return 0;
10433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  else
10443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
10453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
104744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
10483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint32_t Simulator::get_fpu_register(int fpureg) const {
10493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
10503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return FPUregisters_[fpureg];
10513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
10523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
105344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
105444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint64_t Simulator::get_fpu_register_long(int fpureg) const {
105544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
105644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return *BitCast<int64_t*>(
105744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      const_cast<int32_t*>(&FPUregisters_[fpureg]));
105844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
105944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
106044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
106144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockfloat Simulator::get_fpu_register_float(int fpureg) const {
106244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
106344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return *BitCast<float*>(
106444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      const_cast<int32_t*>(&FPUregisters_[fpureg]));
106544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
106644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
106744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
10683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescudouble Simulator::get_fpu_register_double(int fpureg) const {
10693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
107044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
107144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
107244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
107344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// For use in calls that take two double values, constructed either
1075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// from a0-a3 or f12 and f14.
1076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid Simulator::GetFpArgs(double* x, double* y) {
1077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    *x = get_fpu_register_double(12);
1079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    *y = get_fpu_register_double(14);
1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We use a char buffer to get around the strict-aliasing rules which
1082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // otherwise allow the compiler to optimize away the copy.
1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    char buffer[sizeof(*x)];
1084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Registers a0 and a1 -> x.
1087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[0] = get_register(a0);
1088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[1] = get_register(a1);
1089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(x, buffer, sizeof(buffer));
1090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Registers a2 and a3 -> y.
1092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[0] = get_register(a2);
1093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[1] = get_register(a3);
1094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(y, buffer, sizeof(buffer));
1095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// For use in calls that take one double value, constructed either
1100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// from a0 and a1 or f12.
1101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid Simulator::GetFpArgs(double* x) {
1102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
1103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    *x = get_fpu_register_double(12);
1104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We use a char buffer to get around the strict-aliasing rules which
1106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // otherwise allow the compiler to optimize away the copy.
1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    char buffer[sizeof(*x)];
1108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Registers a0 and a1 -> x.
1110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[0] = get_register(a0);
1111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[1] = get_register(a1);
1112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(x, buffer, sizeof(buffer));
1113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// For use in calls that take one double value constructed either
1118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// from a0 and a1 or f12 and one integer value.
1119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid Simulator::GetFpArgs(double* x, int32_t* y) {
1120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
1121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    *x = get_fpu_register_double(12);
1122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    *y = get_register(a2);
1123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We use a char buffer to get around the strict-aliasing rules which
1125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // otherwise allow the compiler to optimize away the copy.
1126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    char buffer[sizeof(*x)];
1127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Registers 0 and 1 -> x.
1129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[0] = get_register(a0);
1130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[1] = get_register(a1);
1131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(x, buffer, sizeof(buffer));
1132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Register 2 -> y.
1134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    reg_buffer[0] = get_register(a2);
1135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(y, buffer, sizeof(*y));
1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// The return value is either in v0/v1 or f0.
1141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid Simulator::SetFpResult(const double& result) {
1142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
1143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    set_fpu_register_double(0, result);
1144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    char buffer[2 * sizeof(registers_[0])];
1146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    memcpy(buffer, &result, sizeof(buffer));
1148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Copy result to v0 and v1.
1149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    set_register(v0, reg_buffer[0]);
1150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    set_register(v1, reg_buffer[1]);
1151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
115544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Helper functions for setting and testing the FCSR register's bits.
115644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::set_fcsr_bit(uint32_t cc, bool value) {
115744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (value) {
115844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FCSR_ |= (1 << cc);
115944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
116044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FCSR_ &= ~(1 << cc);
116144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
116244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
116344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
116444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
116544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool Simulator::test_fcsr_bit(uint32_t cc) {
116644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return FCSR_ & (1 << cc);
11673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
11683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
116944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
117044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Sets the rounding error codes in FCSR based on the result of the rounding.
117144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Returns true if the operation was invalid.
117244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool Simulator::set_fcsr_round_error(double original, double rounded) {
11733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool ret = false;
11743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
11753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!isfinite(original) || !isfinite(rounded)) {
11763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
11773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    ret = true;
117844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
11793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
11803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (original != rounded) {
11813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_fcsr_bit(kFCSRInexactFlagBit, true);
11823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
11833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
11843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
11853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
11863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    ret = true;
11873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
11883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
11893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (rounded > INT_MAX || rounded < INT_MIN) {
11903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_fcsr_bit(kFCSROverflowFlagBit, true);
11913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // The reference is not really clear but it seems this is required:
11923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
11933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    ret = true;
11943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
11953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
11963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  return ret;
119744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
119844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
12003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Raw access to the PC register.
12013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::set_pc(int32_t value) {
12023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  pc_modified_ = true;
12033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  registers_[pc] = value;
12043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
120644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
120744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool Simulator::has_bad_pc() const {
120844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
120944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
121044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
121144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
12123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Raw access to the PC register without the special adjustment when reading.
12133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint32_t Simulator::get_pc() const {
12143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return registers_[pc];
12153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// The MIPS cannot do unaligned reads and writes.  On some MIPS platforms an
12193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// interrupt is caused.  On others it does a funky rotation thing.  For now we
12203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// simply disallow unaligned reads, but at some point we may want to move to
12213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// emulating the rotate behaviour.  Note that simulator runs have the runtime
12223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// system running directly on the host system and only generated code is
12233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// executed in the simulator.  Since the host is typically IA32 we will not
12243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// get the correct MIPS-like behaviour on unaligned accesses.
12253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint Simulator::ReadW(int32_t addr, Instruction* instr) {
122744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (addr >=0 && addr < 0x400) {
1228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This has to be a NULL-dereference, drop into debugger.
1229589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1230589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch           addr, reinterpret_cast<intptr_t>(instr));
123144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MipsDebugger dbg(this);
123244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    dbg.Debug();
123344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
123444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if ((addr & kPointerAlignmentMask) == 0) {
12353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
12363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return *ptr;
12373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
124144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MipsDebugger dbg(this);
124244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  dbg.Debug();
12433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return 0;
12443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
124844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (addr >= 0 && addr < 0x400) {
1249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This has to be a NULL-dereference, drop into debugger.
1250589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1251589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch           addr, reinterpret_cast<intptr_t>(instr));
125244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MipsDebugger dbg(this);
125344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    dbg.Debug();
125444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
125544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if ((addr & kPointerAlignmentMask) == 0) {
12563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
12573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    *ptr = value;
12583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return;
12593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
126344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MipsDebugger dbg(this);
126444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  dbg.Debug();
12653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescudouble Simulator::ReadD(int32_t addr, Instruction* instr) {
12693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & kDoubleAlignmentMask) == 0) {
12703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    double* ptr = reinterpret_cast<double*>(addr);
12713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return *ptr;
12723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
12763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
12773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return 0;
12783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
12823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & kDoubleAlignmentMask) == 0) {
12833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    double* ptr = reinterpret_cast<double*>(addr);
12843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    *ptr = value;
12853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return;
12863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
12903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
12913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
12923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
12943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuuint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
12953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & 1) == 0) {
12963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
12973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return *ptr;
12983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
13023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
13033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return 0;
13043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
13083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & 1) == 0) {
13093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
13103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return *ptr;
13113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
13153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
13163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return 0;
13173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
13213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & 1) == 0) {
13223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
13233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    *ptr = value;
13243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return;
13253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
13293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
13303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
13343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if ((addr & 1) == 0) {
13353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
13363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    *ptr = value;
13373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    return;
13383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
1339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         addr,
1341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         reinterpret_cast<intptr_t>(instr));
13423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  OS::Abort();
13433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuuint32_t Simulator::ReadBU(int32_t addr) {
13473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
13483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return *ptr & 0xff;
13493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuint32_t Simulator::ReadB(int32_t addr) {
13533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
135444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return *ptr;
13553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteB(int32_t addr, uint8_t value) {
13593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
13603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  *ptr = value;
13613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::WriteB(int32_t addr, int8_t value) {
13653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
13663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  *ptr = value;
13673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Returns the limit of the stack area to enable checking for stack overflows.
13713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuuintptr_t Simulator::StackLimit() const {
13723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
13733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // pushing values.
13743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return reinterpret_cast<uintptr_t>(stack_) + 1024;
13753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Unsupported instructions use Format to print an error and stop execution.
13793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::Format(Instruction* instr, const char* format) {
13803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
138144f0eee88ff00398ff7f715fab053374d808c90dSteve Block         reinterpret_cast<intptr_t>(instr), format);
13823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  UNIMPLEMENTED_MIPS();
13833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
13843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
13863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Calls into the V8 runtime are based on this very simple interface.
13873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Note: To be able to return two values from some calls the code in runtime.cc
13883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// uses the ObjectPair which is essentially two 32-bit values stuffed into a
13893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// 64-bit value. With the code below we assume that all runtime calls return
139044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// 64 bits of result. If they don't, the v1 result register contains a bogus
13913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// value, which is fine because it is caller-saved.
13923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescutypedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
13933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                                        int32_t arg1,
13943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu                                        int32_t arg2,
139544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                        int32_t arg3,
139644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                        int32_t arg4,
139744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                        int32_t arg5);
139844f0eee88ff00398ff7f715fab053374d808c90dSteve Blocktypedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
139944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                         int32_t arg1,
140044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                         int32_t arg2,
140144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                         int32_t arg3);
14023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This signature supports direct call in to API function native callback
1404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// (refer to InvocationCallback in v8.h).
1405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochtypedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This signature supports direct call to accessor getter callback.
1408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochtypedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
1409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                                  int32_t arg1);
1410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
14113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Software interrupt instructions are used by the simulator to call into the
141244f0eee88ff00398ff7f715fab053374d808c90dSteve Block// C-based V8 runtime. They are also used for debugging with simulator.
14133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::SoftwareInterrupt(Instruction* instr) {
141444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // There are several instructions that could get us here,
141544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // the break_ instruction, or several variants of traps. All
141644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Are "SPECIAL" class opcode, and are distinuished by function.
141744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t func = instr->FunctionFieldRaw();
14183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
141944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
14203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // We first check if we met a call_rt_redirected.
14213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (instr->InstructionBits() == rtCallRedirInstr) {
14223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    Redirection* redirection = Redirection::FromSwiInstruction(instr);
14233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int32_t arg0 = get_register(a0);
14243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int32_t arg1 = get_register(a1);
14253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int32_t arg2 = get_register(a2);
14263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int32_t arg3 = get_register(a3);
142744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
142844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
142969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Args 4 and 5 are on the stack after the reserved space for args 0..3.
143069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    int32_t arg4 = stack_pointer[4];
143169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    int32_t arg5 = stack_pointer[5];
1432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    bool fp_call =
1434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (!IsMipsSoftFloatABI) {
1440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // With the hard floating point calling convention, double
1441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // arguments are passed in FPU registers. Fetch the arguments
1442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // from there and call the builtin using soft floating point
1443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // convention.
1444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      switch (redirection->type()) {
1445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case ExternalReference::BUILTIN_FP_FP_CALL:
1446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case ExternalReference::BUILTIN_COMPARE_CALL:
1447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg0 = get_fpu_register(f12);
1448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg1 = get_fpu_register(f13);
1449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg2 = get_fpu_register(f14);
1450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg3 = get_fpu_register(f15);
1451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case ExternalReference::BUILTIN_FP_CALL:
1453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg0 = get_fpu_register(f12);
1454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg1 = get_fpu_register(f13);
1455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case ExternalReference::BUILTIN_FP_INT_CALL:
1457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg0 = get_fpu_register(f12);
1458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg1 = get_fpu_register(f13);
1459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        arg2 = get_register(a2);
1460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      default:
1462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
146444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
1465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
14663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // This is dodgy but it works because the C entry stubs are never moved.
14673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // See comment in codegen-arm.cc and bug 1242173.
14683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    int32_t saved_ra = get_register(ra);
146944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
147044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    intptr_t external =
1471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          reinterpret_cast<intptr_t>(redirection->external_function());
147244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
147344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
147444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
147544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // simulator. Soft-float has additional abstraction of ExternalReference,
1476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // to support serialization.
1477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (fp_call) {
14783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      SimulatorRuntimeFPCall target =
1479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  reinterpret_cast<SimulatorRuntimeFPCall>(external);
1480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (::v8::internal::FLAG_trace_sim) {
1481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        double dval0, dval1;
1482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        int32_t ival;
1483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        switch (redirection->type()) {
1484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case ExternalReference::BUILTIN_FP_FP_CALL:
1485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case ExternalReference::BUILTIN_COMPARE_CALL:
1486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            GetFpArgs(&dval0, &dval1);
1487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            PrintF("Call to host function at %p with args %f, %f",
1488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                FUNCTION_ADDR(target), dval0, dval1);
1489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
1490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case ExternalReference::BUILTIN_FP_CALL:
1491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            GetFpArgs(&dval0);
1492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            PrintF("Call to host function at %p with arg %f",
14933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                FUNCTION_ADDR(target), dval0);
1494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
1495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case ExternalReference::BUILTIN_FP_INT_CALL:
1496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            GetFpArgs(&dval0, &ival);
1497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            PrintF("Call to host function at %p with args %f, %d",
1498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                FUNCTION_ADDR(target), dval0, ival);
1499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
1500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          default:
1501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            UNREACHABLE();
1502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
150344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
15043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
150544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      double result = target(arg0, arg1, arg2, arg3);
1506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
1507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          SetFpResult(result);
1508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
1509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        int32_t gpreg_pair[2];
1510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
1511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        set_register(v0, gpreg_pair[0]);
1512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        set_register(v1, gpreg_pair[1]);
1513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
151444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // See DirectCEntryStub::GenerateCall for explanation of register usage.
1516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      SimulatorRuntimeDirectApiCall target =
1517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (::v8::internal::FLAG_trace_sim) {
1519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("Call to host function at %p args %08x\n",
1520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               FUNCTION_ADDR(target), arg1);
1521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
1522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      v8::Handle<v8::Value> result = target(arg1);
1523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      set_register(v0, arg0);
152544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // See DirectCEntryStub::GenerateCall for explanation of register usage.
1527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      SimulatorRuntimeDirectGetterCall target =
1528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (::v8::internal::FLAG_trace_sim) {
1530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        PrintF("Call to host function at %p args %08x %08x\n",
1531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               FUNCTION_ADDR(target), arg1, arg2);
1532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
1533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      v8::Handle<v8::Value> result = target(arg1, arg2);
1534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      set_register(v0, arg0);
15363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    } else {
15373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      SimulatorRuntimeCall target =
1538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  reinterpret_cast<SimulatorRuntimeCall>(external);
1539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (::v8::internal::FLAG_trace_sim) {
15403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        PrintF(
1541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            "Call to host function at %p "
1542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            "args %08x, %08x, %08x, %08x, %08x, %08x\n",
15433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            FUNCTION_ADDR(target),
15443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            arg0,
15453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            arg1,
15463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            arg2,
154744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            arg3,
154844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            arg4,
154944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            arg5);
15503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
155144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
155244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      set_register(v0, static_cast<int32_t>(result));
155344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      set_register(v1, static_cast<int32_t>(result >> 32));
155444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
155544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (::v8::internal::FLAG_trace_sim) {
155644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
15573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
15583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    set_register(ra, saved_ra);
15593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    set_pc(get_register(ra));
156044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
15613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  } else if (func == BREAK && code <= kMaxStopCode) {
15623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (IsWatchpoint(code)) {
15633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      PrintWatchpoint(code);
15643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    } else {
15653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      IncreaseStopCounter(code);
15663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      HandleStop(code, instr);
15673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
15683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  } else {
156944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // All remaining break_ codes, and all traps are handled here.
157044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MipsDebugger dbg(this);
15713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    dbg.Debug();
15723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
15733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
15743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
157544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
15763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch// Stop helper functions.
15773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochbool Simulator::IsWatchpoint(uint32_t code) {
15783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  return (code <= kMaxWatchpointCode);
15793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
15803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
15813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
15823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::PrintWatchpoint(uint32_t code) {
15833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  MipsDebugger dbg(this);
15843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ++break_count_;
15853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  PrintF("\n---- break %d marker: %3d  (instr count: %8d) ----------"
15863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         "----------------------------------",
15873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         code, break_count_, icount_);
15883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  dbg.PrintAllRegs();  // Print registers and continue running.
15893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
15903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
15913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
15923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::HandleStop(uint32_t code, Instruction* instr) {
15933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Stop if it is enabled, otherwise go on jumping over the stop
15943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // and the message address.
15953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (IsEnabledStop(code)) {
15963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    MipsDebugger dbg(this);
15973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    dbg.Stop(instr);
15983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  } else {
15993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    set_pc(get_pc() + 2 * Instruction::kInstrSize);
16003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochbool Simulator::IsStopInstruction(Instruction* instr) {
16053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  int32_t func = instr->FunctionFieldRaw();
16063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
16073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
16083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochbool Simulator::IsEnabledStop(uint32_t code) {
16123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(code <= kMaxStopCode);
16133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(code > kMaxWatchpointCode);
16143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  return !(watched_stops[code].count & kStopDisabledBit);
16153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::EnableStop(uint32_t code) {
16193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!IsEnabledStop(code)) {
16203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    watched_stops[code].count &= ~kStopDisabledBit;
16213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::DisableStop(uint32_t code) {
16263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (IsEnabledStop(code)) {
16273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    watched_stops[code].count |= kStopDisabledBit;
16283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::IncreaseStopCounter(uint32_t code) {
16333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(code <= kMaxStopCode);
16343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
16353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    PrintF("Stop counter for code %i has overflowed.\n"
16363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch           "Enabling this code and reseting the counter to 0.\n", code);
16373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    watched_stops[code].count = 0;
16383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    EnableStop(code);
16393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  } else {
16403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    watched_stops[code].count++;
16413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch// Print a stop status.
16463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Simulator::PrintStopInfo(uint32_t code) {
16473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (code <= kMaxWatchpointCode) {
16483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    PrintF("That is a watchpoint, not a stop.\n");
16493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return;
16503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  } else if (code > kMaxStopCode) {
16513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
16523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return;
16533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
16553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  int32_t count = watched_stops[code].count & ~kStopDisabledBit;
16563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Don't print the state of unused breakpoints.
16573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (count != 0) {
16583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (watched_stops[code].desc) {
16593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
16603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch             code, code, state, count, watched_stops[code].desc);
16613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    } else {
16623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
16633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch             code, code, state, count);
16643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
16653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
16663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
16673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
16693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::SignalExceptions() {
16703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  for (int i = 1; i < kNumExceptions; i++) {
16713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (exceptions[i] != 0) {
16723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
16733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
16743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
16753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
16763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
16773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
167844f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Handle execution based on instruction types.
16793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
168044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::ConfigureTypeRegister(Instruction* instr,
168144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      int32_t& alu_out,
168244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      int64_t& i64hilo,
168344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      uint64_t& u64hilo,
168444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      int32_t& next_pc,
168544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      bool& do_interrupt) {
168644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Every local variable declared here needs to be const.
168744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // This is to make sure that changed values are sent back to
168844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // DecodeTypeRegister correctly.
168944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
169044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Instruction fields.
169144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const Opcode   op     = instr->OpcodeFieldRaw();
169244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rs_reg = instr->RsValue();
169344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rs     = get_register(rs_reg);
169444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const uint32_t rs_u   = static_cast<uint32_t>(rs);
169544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rt_reg = instr->RtValue();
169644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rt     = get_register(rt_reg);
169744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const uint32_t rt_u   = static_cast<uint32_t>(rt);
169844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rd_reg = instr->RdValue();
169944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const uint32_t sa     = instr->SaValue();
170044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
170144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  fs_reg = instr->FsValue();
17023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
17033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ---------- Configuration.
17053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  switch (op) {
1706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case COP1:    // Coprocessor instructions.
17073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->RsFieldRaw()) {
170844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case BC1:   // Handled in DecodeTypeImmed, should never come here.
17093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
17103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
171144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case CFC1:
171244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // At the moment only FCSR is supported.
171344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ASSERT(fs_reg == kFCSRRegister);
171444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          alu_out = FCSR_;
171544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
17163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MFC1:
17173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = get_fpu_register(fs_reg);
17183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MFHC1:
172044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          UNIMPLEMENTED_MIPS();
17213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
172244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case CTC1:
17233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MTC1:
17243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MTHC1:
17253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          // Do the store in the execution step.
17263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case S:
17283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case D:
17293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case W:
17303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case L:
17313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case PS:
17323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          // Do everything in the execution step.
17333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
17353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNIMPLEMENTED_MIPS();
17363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
17373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
17383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SPECIAL:
17393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->FunctionFieldRaw()) {
17403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case JR:
17413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case JALR:
174244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          next_pc = get_register(instr->RsValue());
17433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SLL:
17453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rt << sa;
17463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SRL:
174844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (rs_reg == 0) {
174944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // Regular logical right shift of a word by a fixed number of
175044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // bits instruction. RS field is always equal to 0.
175144f0eee88ff00398ff7f715fab053374d808c90dSteve Block            alu_out = rt_u >> sa;
175244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else {
175344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // Logical right-rotate of a word by a fixed number of bits. This
175444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // is special case of SRL instruction, added in MIPS32 Release 2.
1755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // RS field is equal to 00001.
175644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
175744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
17583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SRA:
17603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rt >> sa;
17613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SLLV:
17633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rt << rs;
17643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SRLV:
176644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (sa == 0) {
176744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // Regular logical right-shift of a word by a variable number of
176844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // bits instruction. SA field is always equal to 0.
176944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            alu_out = rt_u >> rs;
177044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else {
177144f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // Logical right-rotate of a word by a variable number of bits.
177244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // This is special case od SRLV instruction, added in MIPS32
1773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // Release 2. SA field is equal to 00001.
177444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
177544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
17763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SRAV:
17783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rt >> rs;
17793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MFHI:
17813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = get_register(HI);
17823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MFLO:
17843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = get_register(LO);
17853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MULT:
178744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
17883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MULTU:
179044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
17913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
17923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case ADD:
17933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (HaveSameSign(rs, rt)) {
17943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            if (rs > 0) {
17953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
17963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            } else if (rs < 0) {
17973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
17983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            }
17993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
18003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs + rt;
18013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case ADDU:
18033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs + rt;
18043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SUB:
18063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (!HaveSameSign(rs, rt)) {
18073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            if (rs > 0) {
18083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
18093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            } else if (rs < 0) {
18103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
18113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            }
18123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
18133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs - rt;
18143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SUBU:
18163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs - rt;
18173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case AND:
18193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs & rt;
18203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case OR:
18223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs | rt;
18233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case XOR:
18253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs ^ rt;
18263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case NOR:
18283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = ~(rs | rt);
18293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SLT:
18313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs < rt ? 1 : 0;
18323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case SLTU:
18343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs_u < rt_u ? 1 : 0;
18353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
1836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Break and trap instructions.
18373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BREAK:
183844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
18393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = true;
18403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TGE:
18423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs >= rt;
18433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TGEU:
18453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs_u >= rt_u;
18463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TLT:
18483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs < rt;
18493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TLTU:
18513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs_u < rt_u;
18523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TEQ:
18543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs == rt;
18553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
18563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TNE:
18573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_interrupt = rs != rt;
18583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
185944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVN:
186044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVZ:
186144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVCI:
186244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // No action taken on decode.
186344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
1864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case DIV:
1865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case DIVU:
1866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // div and divu never raise exceptions.
1867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
18683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
18693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
18703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
18713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
18723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SPECIAL2:
18733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->FunctionFieldRaw()) {
18743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MUL:
18753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          alu_out = rs_u * rt_u;  // Only the lower 32 bits are kept.
18763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
187744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case CLZ:
187844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          alu_out = __builtin_clz(rs_u);
187944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
18803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
18813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
188244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      };
188344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
188444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SPECIAL3:
188544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      switch (instr->FunctionFieldRaw()) {
188644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case INS: {   // Mips32r2 instruction.
1887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Interpret rd field as 5-bit msb of insert.
188844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t msb = rd_reg;
188944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // Interpret sa field as 5-bit lsb of insert.
189044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t lsb = sa;
189144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t size = msb - lsb + 1;
189244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint32_t mask = (1 << size) - 1;
189344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
189444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
189544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
189644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case EXT: {   // Mips32r2 instruction.
1897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Interpret rd field as 5-bit msb of extract.
189844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t msb = rd_reg;
189944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // Interpret sa field as 5-bit lsb of extract.
190044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t lsb = sa;
190144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint16_t size = msb + 1;
190244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint32_t mask = (1 << size) - 1;
190344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          alu_out = (rs_u & (mask << lsb)) >> lsb;
190444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
190544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
190644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        default:
190744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          UNREACHABLE();
190844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      };
19093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
19103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    default:
19113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      UNREACHABLE();
19123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
191344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
191444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
191544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
191644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Simulator::DecodeTypeRegister(Instruction* instr) {
191744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Instruction fields.
191844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const Opcode   op     = instr->OpcodeFieldRaw();
191944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rs_reg = instr->RsValue();
192044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rs     = get_register(rs_reg);
192144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const uint32_t rs_u   = static_cast<uint32_t>(rs);
192244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rt_reg = instr->RtValue();
192344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rt     = get_register(rt_reg);
192444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const uint32_t rt_u   = static_cast<uint32_t>(rt);
192544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  rd_reg = instr->RdValue();
192644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
192744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  fs_reg = instr->FsValue();
192844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  ft_reg = instr->FtValue();
192944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int32_t  fd_reg = instr->FdValue();
193044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int64_t  i64hilo = 0;
193144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  uint64_t u64hilo = 0;
193244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ALU output.
193444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // It should not be used as is. Instructions using it should always
193544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // initialize it first.
193644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t alu_out = 0x12345678;
193744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
193844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // For break and trap instructions.
193944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool do_interrupt = false;
194044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // For jr and jalr.
194244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Get current pc.
194344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t current_pc = get_pc();
194444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Next pc
194544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t next_pc = 0;
194644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
19473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the variables if needed before executing the instruction.
194844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ConfigureTypeRegister(instr,
194944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        alu_out,
195044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        i64hilo,
195144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        u64hilo,
195244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        next_pc,
195344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        do_interrupt);
19543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
19553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // ---------- Raise exceptions triggered.
19563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  SignalExceptions();
19573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
1958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ---------- Execution.
19593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  switch (op) {
19603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case COP1:
19613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->RsFieldRaw()) {
1962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case BC1:   // Branch on coprocessor condition.
19633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
19643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
196544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case CFC1:
196644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(rt_reg, alu_out);
19673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MFC1:
19683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_register(rt_reg, alu_out);
19693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
197044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MFHC1:
197144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          UNIMPLEMENTED_MIPS();
197244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
197344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case CTC1:
197444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // At the moment only FCSR is supported.
197544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ASSERT(fs_reg == kFCSRRegister);
197644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          FCSR_ = registers_[rt_reg];
197744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
19783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MTC1:
19793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          FPUregisters_[fs_reg] = registers_[rt_reg];
19803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
19813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MTHC1:
198244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          UNIMPLEMENTED_MIPS();
19833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
19843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case S:
198544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          float f;
19863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          switch (instr->FunctionFieldRaw()) {
19873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_D_S:
198844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              f = get_fpu_register_float(fs_reg);
198944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, static_cast<double>(f));
199044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
19913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_W_S:
19923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_L_S:
199344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case TRUNC_W_S:
199444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case TRUNC_L_S:
199544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ROUND_W_S:
199644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ROUND_L_S:
199744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case FLOOR_W_S:
199844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case FLOOR_L_S:
199944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CEIL_W_S:
200044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CEIL_L_S:
20013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_PS_S:
20023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNIMPLEMENTED_MIPS();
20033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              break;
20043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            default:
20053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNREACHABLE();
20063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
20073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
20083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case D:
200944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          double ft, fs;
201044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint32_t cc, fcsr_cc;
201144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          int64_t  i64;
201244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          fs = get_fpu_register_double(fs_reg);
201344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ft = get_fpu_register_double(ft_reg);
201444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cc = instr->FCccValue();
201544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          fcsr_cc = get_fcsr_condition_bit(cc);
20163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          switch (instr->FunctionFieldRaw()) {
201744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ADD_D:
201844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs + ft);
201944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
202044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case SUB_D:
202144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs - ft);
202244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
202344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case MUL_D:
202444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs * ft);
202544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
202644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case DIV_D:
202744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs / ft);
202844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
202944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ABS_D:
203044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs);
203144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
203244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case MOV_D:
203344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, fs);
203444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
203544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case NEG_D:
203644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, -fs);
203744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
203844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case SQRT_D:
203944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, sqrt(fs));
204044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
204144f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_UN_D:
204244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft));
204344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
204444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_EQ_D:
204544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs == ft));
204644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
204744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_UEQ_D:
204844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft)));
204944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
205044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_OLT_D:
205144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs < ft));
205244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
205344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_ULT_D:
205444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft)));
205544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
205644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_OLE_D:
205744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs <= ft));
205844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
205944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_ULE_D:
206044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft)));
206144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
206244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CVT_W_D:   // Convert double to word.
206344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              // Rounding modes are not yet supported.
206444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              ASSERT((FCSR_ & 3) == 0);
206544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              // In rounding mode 0 it should behave like ROUND.
206644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ROUND_W_D:  // Round double to word.
206744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              {
206844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
206944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                int32_t result = static_cast<int32_t>(rounded);
207044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                set_fpu_register(fd_reg, result);
207144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                if (set_fcsr_round_error(fs, rounded)) {
207244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                  set_fpu_register(fd_reg, kFPUInvalidResult);
207344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                }
207444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
207544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
207644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case TRUNC_W_D:  // Truncate double to word (round towards 0).
207744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              {
20783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                double rounded = trunc(fs);
20793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                int32_t result = static_cast<int32_t>(rounded);
208044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                set_fpu_register(fd_reg, result);
20813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                if (set_fcsr_round_error(fs, rounded)) {
208244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                  set_fpu_register(fd_reg, kFPUInvalidResult);
208344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                }
208444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
208544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
208644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case FLOOR_W_D:  // Round double to word towards negative infinity.
208744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              {
208844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                double rounded = floor(fs);
208944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                int32_t result = static_cast<int32_t>(rounded);
209044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                set_fpu_register(fd_reg, result);
209144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                if (set_fcsr_round_error(fs, rounded)) {
209244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                  set_fpu_register(fd_reg, kFPUInvalidResult);
209344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                }
209444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
209544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
209644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CEIL_W_D:  // Round double to word towards positive infinity.
209744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              {
209844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                double rounded = ceil(fs);
209944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                int32_t result = static_cast<int32_t>(rounded);
210044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                set_fpu_register(fd_reg, result);
210144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                if (set_fcsr_round_error(fs, rounded)) {
210244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                  set_fpu_register(fd_reg, kFPUInvalidResult);
210344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                }
210444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              }
210544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
210644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CVT_S_D:  // Convert double to float (single).
210744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_float(fd_reg, static_cast<float>(fs));
210844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
21093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
21103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              double rounded = trunc(fs);
21113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              i64 = static_cast<int64_t>(rounded);
211244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg, i64 & 0xffffffff);
211344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg + 1, i64 >> 32);
211444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
21153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            }
21163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            case TRUNC_L_D: {  // Mips32r2 instruction.
21173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              double rounded = trunc(fs);
21183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              i64 = static_cast<int64_t>(rounded);
211944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg, i64 & 0xffffffff);
212044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg + 1, i64 >> 32);
212144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
21223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            }
212344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case ROUND_L_D: {  // Mips32r2 instruction.
212444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
212544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              i64 = static_cast<int64_t>(rounded);
212644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg, i64 & 0xffffffff);
212744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg + 1, i64 >> 32);
212844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
212944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            }
213044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case FLOOR_L_D:  // Mips32r2 instruction.
213144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              i64 = static_cast<int64_t>(floor(fs));
213244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg, i64 & 0xffffffff);
213344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg + 1, i64 >> 32);
213444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
213544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CEIL_L_D:  // Mips32r2 instruction.
213644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              i64 = static_cast<int64_t>(ceil(fs));
213744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg, i64 & 0xffffffff);
213844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register(fd_reg + 1, i64 >> 32);
213944f0eee88ff00398ff7f715fab053374d808c90dSteve Block              break;
214044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case C_F_D:
21413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNIMPLEMENTED_MIPS();
21423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              break;
21433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            default:
21443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNREACHABLE();
21453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
21463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
21473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case W:
21483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          switch (instr->FunctionFieldRaw()) {
214944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            case CVT_S_W:   // Convert word to float (single).
215044f0eee88ff00398ff7f715fab053374d808c90dSteve Block              alu_out = get_fpu_register(fs_reg);
215144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
21523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              break;
21533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_D_W:   // Convert word to double.
215444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              alu_out = get_fpu_register(fs_reg);
215544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
21563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              break;
21573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            default:
21583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNREACHABLE();
21593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          };
21603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
21613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case L:
21623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          switch (instr->FunctionFieldRaw()) {
216344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          case CVT_D_L:  // Mips32r2 instruction.
216444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // Watch the signs here, we want 2 32-bit vals
216544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            // to make a sign-64.
216644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            i64 = (uint32_t) get_fpu_register(fs_reg);
216744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32);
216844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            set_fpu_register_double(fd_reg, static_cast<double>(i64));
216944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            break;
21703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            case CVT_S_L:
21713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNIMPLEMENTED_MIPS();
21723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              break;
21733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            default:
21743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              UNREACHABLE();
21753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
21763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
21773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case PS:
21783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
21793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
21803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
21813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
21823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
21833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SPECIAL:
21843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->FunctionFieldRaw()) {
21853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case JR: {
21863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
218744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              current_pc+Instruction::kInstrSize);
21883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          BranchDelayInstructionDecode(branch_delay_instr);
21893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_pc(next_pc);
21903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          pc_modified_ = true;
21913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
21923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
21933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case JALR: {
21943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
219544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              current_pc+Instruction::kInstrSize);
21963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          BranchDelayInstructionDecode(branch_delay_instr);
2197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          set_register(31, current_pc + 2 * Instruction::kInstrSize);
21983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_pc(next_pc);
21993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          pc_modified_ = true;
22003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
22013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
22023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        // Instructions using HI and LO registers.
22033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MULT:
220444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
220544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(HI, static_cast<int32_t>(i64hilo >> 32));
220644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
22073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MULTU:
220844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
220944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(HI, static_cast<int32_t>(u64hilo >> 32));
22103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
22113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case DIV:
2212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Divide by zero was not checked in the configuration step - div and
2213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // divu do not raise exceptions. On division by 0, the result will
2214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // be UNPREDICTABLE.
2215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (rt != 0) {
2216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            set_register(LO, rs / rt);
2217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            set_register(HI, rs % rt);
2218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
22193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
22203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case DIVU:
2221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (rt_u != 0) {
2222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            set_register(LO, rs_u / rt_u);
2223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            set_register(HI, rs_u % rt_u);
2224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
22253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
222644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        // Break and trap instructions.
22273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BREAK:
22283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TGE:
22293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TGEU:
22303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TLT:
22313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TLTU:
22323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TEQ:
22333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case TNE:
22343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (do_interrupt) {
22353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            SoftwareInterrupt(instr);
22363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
22373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
223844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        // Conditional moves.
223944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVN:
224044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (rt) set_register(rd_reg, rs);
224144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
224244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVCI: {
2243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          uint32_t cc = instr->FBccValue();
224444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
2245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (instr->Bit(16)) {  // Read Tf bit.
224644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
224744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else {
224844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
224944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
225044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
225144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
225244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case MOVZ:
225344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!rt) set_register(rd_reg, rs);
225444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
22553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:  // For other special opcodes we do the default operation.
22563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_register(rd_reg, alu_out);
22573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
22583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
22593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SPECIAL2:
22603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->FunctionFieldRaw()) {
22613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case MUL:
22623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_register(rd_reg, alu_out);
22633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          // HI and LO are UNPREDICTABLE after the operation.
22643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_register(LO, Unpredictable);
22653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          set_register(HI, Unpredictable);
22663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
226744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        default:  // For other special2 opcodes we do the default operation.
226844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(rd_reg, alu_out);
226944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
227044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
227144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SPECIAL3:
227244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      switch (instr->FunctionFieldRaw()) {
227344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case INS:
227444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // Ins instr leaves result in Rt, rather than Rd.
227544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(rt_reg, alu_out);
227644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
227744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case EXT:
227844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // Ext instr leaves result in Rt, rather than Rd.
227944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(rt_reg, alu_out);
228044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
22813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
22823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
228344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      };
22843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
22853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // Unimplemented opcodes raised an error in the configuration step before,
22863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // so we can use the default here to set the destination register in common
22873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // cases.
22883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    default:
22893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      set_register(rd_reg, alu_out);
22903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
22913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
22923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
229344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
22943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
22953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::DecodeTypeImmediate(Instruction* instr) {
229644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Instruction fields.
22973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Opcode   op     = instr->OpcodeFieldRaw();
229844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t  rs     = get_register(instr->RsValue());
22993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uint32_t rs_u   = static_cast<uint32_t>(rs);
2300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  int32_t  rt_reg = instr->RtValue();  // Destination register.
23013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t  rt     = get_register(rt_reg);
230244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int16_t  imm16  = instr->Imm16Value();
23033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  int32_t  ft_reg = instr->FtValue();  // Destination register.
23053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
230644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Zero extended immediate.
23073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uint32_t  oe_imm16 = 0xffff & imm16;
230844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Sign extended immediate.
23093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t   se_imm16 = imm16;
23103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
23113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Get current pc.
23123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t current_pc = get_pc();
23133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Next pc.
23143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t next_pc = bad_ra;
23153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
231644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Used for conditional branch instructions.
23173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool do_branch = false;
23183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  bool execute_branch_delay_instruction = false;
23193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
232044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Used for arithmetic instructions.
23213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t alu_out = 0;
232244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Floating point.
23233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  double fp_out = 0.0;
232444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  uint32_t cc, cc_value, fcsr_cc;
23253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
232644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Used for memory instructions.
23273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t addr = 0x0;
2328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Value to be written in memory.
232944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  uint32_t mem_value = 0x0;
23303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ---------- Configuration (and execution for REGIMM).
23323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  switch (op) {
233344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // ------------- COP1. Coprocessor instructions.
23343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case COP1:
23353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->RsFieldRaw()) {
233644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case BC1:   // Branch on coprocessor condition.
233744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cc = instr->FBccValue();
233844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          fcsr_cc = get_fcsr_condition_bit(cc);
233944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          cc_value = test_fcsr_bit(fcsr_cc);
234044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
234144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          execute_branch_delay_instruction = true;
2342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Set next_pc.
234344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (do_branch) {
234444f0eee88ff00398ff7f715fab053374d808c90dSteve Block            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
234544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          } else {
234644f0eee88ff00398ff7f715fab053374d808c90dSteve Block            next_pc = current_pc + kBranchReturnOffset;
234744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
23483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
23503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
23513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
23523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
2353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- REGIMM class.
23543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case REGIMM:
23553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->RtFieldRaw()) {
23563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BLTZ:
23573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_branch = (rs  < 0);
23583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BLTZAL:
23603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_branch = rs  < 0;
23613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BGEZ:
23633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_branch = rs >= 0;
23643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BGEZAL:
23663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          do_branch = rs >= 0;
23673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
23693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          UNREACHABLE();
23703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      };
23713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      switch (instr->RtFieldRaw()) {
23723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BLTZ:
23733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BLTZAL:
23743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BGEZ:
23753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        case BGEZAL:
23763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          // Branch instructions common part.
23773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          execute_branch_delay_instruction = true;
2378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Set next_pc.
23793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          if (do_branch) {
238044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
23813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            if (instr->IsLinkingInstruction()) {
23823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              set_register(31, current_pc + kBranchReturnOffset);
23833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            }
23843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          } else {
23853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            next_pc = current_pc + kBranchReturnOffset;
23863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          }
23873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        default:
23883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          break;
23893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        };
2390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    break;  // case REGIMM.
2391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Branch instructions.
23923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // When comparing to zero, the encoding of rt field is always 0, so we don't
23933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // need to replace rt with zero.
23943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BEQ:
23953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      do_branch = (rs == rt);
23963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
23973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BNE:
23983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      do_branch = rs != rt;
23993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BLEZ:
24013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      do_branch = rs <= 0;
24023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BGTZ:
24043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      do_branch = rs  > 0;
24053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
2406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Arithmetic instructions.
24073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ADDI:
24083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if (HaveSameSign(rs, se_imm16)) {
24093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        if (rs > 0) {
24103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
24113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        } else if (rs < 0) {
24123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          exceptions[kIntegerUnderflow] =
24133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu              rs < (Registers::kMinValue - se_imm16);
24143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
24153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
24163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = rs + se_imm16;
24173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ADDIU:
24193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = rs + se_imm16;
24203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SLTI:
24223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = (rs < se_imm16) ? 1 : 0;
24233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SLTIU:
24253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
24263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ANDI:
24283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        alu_out = rs & oe_imm16;
24293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ORI:
24313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        alu_out = rs | oe_imm16;
24323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case XORI:
24343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        alu_out = rs ^ oe_imm16;
24353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LUI:
24373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        alu_out = (oe_imm16 << 16);
24383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
2439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Memory instructions.
24403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LB:
24413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
24423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = ReadB(addr);
24433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
244444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LH:
244544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16;
244644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out = ReadH(addr, instr);
244744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
244844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LWL: {
2449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // al_offset is offset of the effective address within an aligned word.
245044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
245144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
245244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint32_t mask = (1 << byte_shift * 8) - 1;
245344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16 - al_offset;
245444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out = ReadW(addr, instr);
245544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out <<= byte_shift * 8;
245644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out |= rt & mask;
245744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
245844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
24593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LW:
24603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
24613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = ReadW(addr, instr);
24623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
24633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LBU:
24643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
24653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = ReadBU(addr);
24663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
246744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LHU:
246844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16;
246944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out = ReadHU(addr, instr);
247044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
247144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LWR: {
2472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // al_offset is offset of the effective address within an aligned word.
247344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
247444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
247544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
247644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16 - al_offset;
247744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out = ReadW(addr, instr);
247844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
247944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      alu_out |= rt & mask;
248044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
248144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
24823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SB:
24833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
24843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
248544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SH:
248644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16;
248744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
248844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SWL: {
248944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
249044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
249144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
249244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16 - al_offset;
249344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      mem_value = ReadW(addr, instr) & mask;
249444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
249544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
249644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
24973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SW:
24983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
24993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
250044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SWR: {
250144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
250244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint32_t mask = (1 << al_offset * 8) - 1;
250344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      addr = rs + se_imm16 - al_offset;
250444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      mem_value = ReadW(addr, instr);
250544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      mem_value = (rt << al_offset * 8) | (mem_value & mask);
250644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
250744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
25083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LWC1:
25093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
25103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      alu_out = ReadW(addr, instr);
25113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LDC1:
25133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
25143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      fp_out = ReadD(addr, instr);
25153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SWC1:
25173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SDC1:
25183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
25193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    default:
25213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      UNREACHABLE();
25223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
25233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
25243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // ---------- Raise exceptions triggered.
25253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  SignalExceptions();
25263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ---------- Execution.
25283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  switch (op) {
2529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Branch instructions.
25303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BEQ:
25313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BNE:
25323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BLEZ:
25333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case BGTZ:
25343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      // Branch instructions common part.
25353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      execute_branch_delay_instruction = true;
2536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Set next_pc.
25373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if (do_branch) {
253844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
25393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        if (instr->IsLinkingInstruction()) {
254044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          set_register(31, current_pc + 2* Instruction::kInstrSize);
25413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        }
25423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else {
254344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        next_pc = current_pc + 2 * Instruction::kInstrSize;
25443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
25453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
2546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Arithmetic instructions.
25473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ADDI:
25483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ADDIU:
25493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SLTI:
25503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SLTIU:
25513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ANDI:
25523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case ORI:
25533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case XORI:
25543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LUI:
25553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      set_register(rt_reg, alu_out);
25563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
2557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ------------- Memory instructions.
25583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LB:
255944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LH:
256044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LWL:
25613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LW:
25623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LBU:
256344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LHU:
256444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case LWR:
25653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      set_register(rt_reg, alu_out);
25663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SB:
25683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      WriteB(addr, static_cast<int8_t>(rt));
25693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
257044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SH:
257144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      WriteH(addr, static_cast<uint16_t>(rt), instr);
257244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
257344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SWL:
257444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      WriteW(addr, mem_value, instr);
257544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
25763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SW:
25773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      WriteW(addr, rt, instr);
25783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
257944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case SWR:
258044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      WriteW(addr, mem_value, instr);
258144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
25823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LWC1:
25833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      set_fpu_register(ft_reg, alu_out);
25843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case LDC1:
25863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      set_fpu_register_double(ft_reg, fp_out);
25873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SWC1:
25893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
25903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      WriteW(addr, get_fpu_register(ft_reg), instr);
25913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case SDC1:
25933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      addr = rs + se_imm16;
259444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      WriteD(addr, get_fpu_register_double(ft_reg), instr);
25953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    default:
25973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
25983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  };
25993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (execute_branch_delay_instruction) {
26023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // Execute branch delay slot
26033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // We don't check for end_sim_pc. First it should not be met as the current
26043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // pc is valid. Secondly a jump should always execute its branch delay slot.
26053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    Instruction* branch_delay_instr =
260644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
26073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    BranchDelayInstructionDecode(branch_delay_instr);
26083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // If needed update pc after the branch delay execution.
26113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (next_pc != bad_ra) {
26123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    set_pc(next_pc);
26133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
26153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
261644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
26173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
26183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::DecodeTypeJump(Instruction* instr) {
26193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Get current pc.
26203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t current_pc = get_pc();
26213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Get unchanged bits of pc.
26223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t pc_high_bits = current_pc & 0xf0000000;
2623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Next pc.
262444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
26253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Execute branch delay slot.
26273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // We don't check for end_sim_pc. First it should not be met as the current pc
26283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // is valid. Secondly a jump should always execute its branch delay slot.
26293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Instruction* branch_delay_instr =
2630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
26313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  BranchDelayInstructionDecode(branch_delay_instr);
26323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Update pc and ra if necessary.
26343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Do this after the branch delay execution.
26353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (instr->IsLinkingInstruction()) {
2636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    set_register(31, current_pc + 2 * Instruction::kInstrSize);
26373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_pc(next_pc);
26393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  pc_modified_ = true;
26403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
26413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
264244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
26433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Executes the current instruction.
26443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::InstructionDecode(Instruction* instr) {
264544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (v8::internal::FLAG_check_icache) {
264644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CheckICache(isolate_->simulator_i_cache(), instr);
264744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
26483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  pc_modified_ = false;
26493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (::v8::internal::FLAG_trace_sim) {
26503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    disasm::NameConverter converter;
26513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    disasm::Disassembler dasm(converter);
2652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use a reasonably large buffer.
26533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    v8::internal::EmbeddedVector<char, 256> buffer;
2654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
265544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    PrintF("  0x%08x  %s\n", reinterpret_cast<intptr_t>(instr),
2656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        buffer.start());
26573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  switch (instr->InstructionType()) {
26603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case Instruction::kRegisterType:
26613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      DecodeTypeRegister(instr);
26623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
26633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case Instruction::kImmediateType:
26643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      DecodeTypeImmediate(instr);
26653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
26663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    case Instruction::kJumpType:
26673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      DecodeTypeJump(instr);
26683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      break;
26693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    default:
26703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      UNSUPPORTED();
26713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (!pc_modified_) {
26733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    set_register(pc, reinterpret_cast<int32_t>(instr) +
267444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 Instruction::kInstrSize);
26753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
26763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
26773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
26803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvoid Simulator::Execute() {
26813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Get the PC to simulate. Cannot use the accessor here as we need the
26823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // raw PC value and not the one used as input to arithmetic instructions.
26833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int program_counter = get_pc();
26843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (::v8::internal::FLAG_stop_sim_at == 0) {
26853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // Fast version of the dispatch loop without checking whether the simulator
26863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // should be stopping at a particular executed instruction.
26873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    while (program_counter != end_sim_pc) {
26883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
26893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      icount_++;
26903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      InstructionDecode(instr);
26913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      program_counter = get_pc();
26923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
26933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  } else {
26943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
26953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    // we reach the particular instuction count.
26963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    while (program_counter != end_sim_pc) {
26973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
26983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      icount_++;
26993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
270044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        MipsDebugger dbg(this);
27013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        dbg.Debug();
27023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      } else {
27033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        InstructionDecode(instr);
27043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      }
27053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      program_counter = get_pc();
27063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    }
27073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
27083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
27093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochint32_t Simulator::Call(byte* entry, int argument_count, ...) {
27123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  va_list parameters;
27133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  va_start(parameters, argument_count);
27143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up arguments.
27153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // First four arguments passed in registers.
27173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT(argument_count >= 4);
27183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(a0, va_arg(parameters, int32_t));
27193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(a1, va_arg(parameters, int32_t));
27203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(a2, va_arg(parameters, int32_t));
27213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(a3, va_arg(parameters, int32_t));
27223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Remaining arguments passed on stack.
27243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int original_stack = get_register(sp);
27253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Compute position of stack on entry to generated code.
27263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
272744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                    - kCArgsSlotsSize);
27283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (OS::ActivationFrameAlignment() != 0) {
27293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    entry_stack &= -OS::ActivationFrameAlignment();
27303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
27313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Store remaining arguments on stack, from low to high memory.
27323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
27333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  for (int i = 4; i < argument_count; i++) {
2734589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
27353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  }
27363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  va_end(parameters);
27373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(sp, entry_stack);
27383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Prepare to execute the code at entry.
27403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(pc, reinterpret_cast<int32_t>(entry));
27413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Put down marker for end of simulation. The simulator will stop simulation
27423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // when the PC reaches this value. By saving the "end simulation" value into
27433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // the LR the simulation stops when returning to this call point.
27443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(ra, end_sim_pc);
27453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Remember the values of callee-saved registers.
27473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // The code below assumes that r9 is not used as sb (static base) in
27483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // simulator code and therefore is regarded as a callee-saved register.
27493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s0_val = get_register(s0);
27503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s1_val = get_register(s1);
27513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s2_val = get_register(s2);
27523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s3_val = get_register(s3);
27533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s4_val = get_register(s4);
27543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s5_val = get_register(s5);
27553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s6_val = get_register(s6);
27563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t s7_val = get_register(s7);
27573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t gp_val = get_register(gp);
27583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t sp_val = get_register(sp);
27593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t fp_val = get_register(fp);
27603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the callee-saved registers with a known value. To be able to check
27623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // that they are preserved properly across JS execution.
27633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t callee_saved_value = icount_;
27643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s0, callee_saved_value);
27653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s1, callee_saved_value);
27663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s2, callee_saved_value);
27673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s3, callee_saved_value);
27683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s4, callee_saved_value);
27693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s5, callee_saved_value);
27703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s6, callee_saved_value);
27713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s7, callee_saved_value);
27723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(gp, callee_saved_value);
27733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(fp, callee_saved_value);
27743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Start the simulation.
27763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Execute();
27773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Check that the callee-saved registers have been preserved.
27793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s0));
27803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s1));
27813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s2));
27823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s3));
27833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s4));
27843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s5));
27853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s6));
27863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(s7));
27873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(gp));
27883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(callee_saved_value, get_register(fp));
27893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
27903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Restore callee-saved registers with the original value.
27913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s0, s0_val);
27923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s1, s1_val);
27933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s2, s2_val);
27943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s3, s3_val);
27953100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s4, s4_val);
27963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s5, s5_val);
27973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s6, s6_val);
27983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(s7, s7_val);
27993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(gp, gp_val);
28003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(sp, sp_val);
28013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(fp, fp_val);
28023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  // Pop stack passed arguments.
28043100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CHECK_EQ(entry_stack, get_register(sp));
28053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(sp, original_stack);
28063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int32_t result = get_register(v0);
28083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return result;
28093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
28103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuuintptr_t Simulator::PushAddress(uintptr_t address) {
28133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int new_sp = get_register(sp) - sizeof(uintptr_t);
28143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
28153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  *stack_slot = address;
28163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(sp, new_sp);
28173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return new_sp;
28183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
28193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuuintptr_t Simulator::PopAddress() {
28223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  int current_sp = get_register(sp);
28233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
28243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  uintptr_t address = *stack_slot;
28253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  set_register(sp, current_sp + sizeof(uintptr_t));
28263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return address;
28273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu}
28283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
28303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#undef UNSUPPORTED
28313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
283244f0eee88ff00398ff7f715fab053374d808c90dSteve Block} }  // namespace v8::internal
28333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
283444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif  // USE_SIMULATOR
28353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2836f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_MIPS
2837