simulator-mips.cc 106 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include <limits.h>
6 7
#include <stdarg.h>
#include <stdlib.h>
8
#include <cmath>
9

10
#include "src/v8.h"
11

12
#if V8_TARGET_ARCH_MIPS
13

14
#include "src/assembler.h"
15
#include "src/base/bits.h"
16 17 18
#include "src/disasm.h"
#include "src/mips/constants-mips.h"
#include "src/mips/simulator-mips.h"
19
#include "src/ostreams.h"
20 21 22


// Only build the simulator if not compiling for real MIPS hardware.
23
#if defined(USE_SIMULATOR)
24

25 26
namespace v8 {
namespace internal {
27

28
// Utils functions.
29
bool HaveSameSign(int32_t a, int32_t b) {
30 31 32 33 34 35 36 37 38 39
  return ((a ^ b) >= 0);
}


uint32_t get_fcsr_condition_bit(uint32_t cc) {
  if (cc == 0) {
    return 23;
  } else {
    return 24 + cc;
  }
40 41 42 43 44 45 46 47 48
}


// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent was through
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
// Library does not provide vsscanf.
#define SScanF sscanf  // NOLINT

49
// The MipsDebugger class is used by the simulator while debugging simulated
50
// code.
51
class MipsDebugger {
52
 public:
53
  explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
54
  ~MipsDebugger();
55 56 57

  void Stop(Instruction* instr);
  void Debug();
58 59 60
  // Print all registers with a nice formatting.
  void PrintAllRegs();
  void PrintAllRegsIncludingFPU();
61 62 63 64 65 66 67 68 69

 private:
  // We set the breakpoint code to 0xfffff to easily recognize it.
  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
  static const Instr kNopInstr =  0x0;

  Simulator* sim_;

  int32_t GetRegisterValue(int regnum);
70 71
  int32_t GetFPURegisterValue32(int regnum);
  int64_t GetFPURegisterValue64(int regnum);
72 73
  float GetFPURegisterValueFloat(int regnum);
  double GetFPURegisterValueDouble(int regnum);
74
  bool GetValue(const char* desc, int32_t* value);
75
  bool GetValue(const char* desc, int64_t* value);
76 77 78 79 80 81 82 83 84 85 86

  // Set or delete a breakpoint. Returns true if successful.
  bool SetBreakpoint(Instruction* breakpc);
  bool DeleteBreakpoint(Instruction* breakpc);

  // Undo and redo all breakpoints. This is needed to bracket disassembly and
  // execution to skip past breakpoints when run from the debugger.
  void UndoBreakpoints();
  void RedoBreakpoints();
};

87 88

MipsDebugger::~MipsDebugger() {
89 90
}

91

92 93 94 95 96 97 98 99 100 101 102 103
#ifdef GENERATED_CODE_COVERAGE
static FILE* coverage_log = NULL;


static void InitializeCoverage() {
  char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
  if (file_name != NULL) {
    coverage_log = fopen(file_name, "aw+");
  }
}


104
void MipsDebugger::Stop(Instruction* instr) {
105 106 107 108 109 110
  // Get the stop code.
  uint32_t code = instr->Bits(25, 6);
  // Retrieve the encoded address, which comes just after this stop.
  char** msg_address =
    reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
  char* msg = *msg_address;
111
  DCHECK(msg != NULL);
112 113

  // Update this stop description.
114 115
  if (!watched_stops_[code].desc) {
    watched_stops_[code].desc = msg;
116 117 118
  }

  if (strlen(msg) > 0) {
119 120 121 122
    if (coverage_log != NULL) {
      fprintf(coverage_log, "%s\n", str);
      fflush(coverage_log);
    }
123 124 125
    // Overwrite the instruction and address with nops.
    instr->SetInstructionBits(kNopInstr);
    reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
126
  }
127
  sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
128 129
}

130

131
#else  // GENERATED_CODE_COVERAGE
132 133 134 135 136 137

#define UNSUPPORTED() printf("Unsupported instruction.\n");

static void InitializeCoverage() {}


138
void MipsDebugger::Stop(Instruction* instr) {
139 140 141 142 143 144
  // Get the stop code.
  uint32_t code = instr->Bits(25, 6);
  // Retrieve the encoded address, which comes just after this stop.
  char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
      Instruction::kInstrSize);
  // Update this stop description.
145 146
  if (!sim_->watched_stops_[code].desc) {
    sim_->watched_stops_[code].desc = msg;
147 148 149
  }
  PrintF("Simulator hit %s (%u)\n", msg, code);
  sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
150 151
  Debug();
}
152
#endif  // GENERATED_CODE_COVERAGE
153 154


155
int32_t MipsDebugger::GetRegisterValue(int regnum) {
156 157 158 159 160 161 162 163
  if (regnum == kNumSimuRegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_register(regnum);
  }
}


164
int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
165 166 167
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
168
    return sim_->get_fpu_register_word(regnum);
169 170 171 172
  }
}


173
int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
174 175 176
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
177
    return sim_->get_fpu_register(regnum);
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  }
}


float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_fpu_register_float(regnum);
  }
}


double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_fpu_register_double(regnum);
  }
}


bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
201
  int regnum = Registers::Number(desc);
202 203
  int fpuregnum = FPURegisters::Number(desc);

204 205 206
  if (regnum != kInvalidRegister) {
    *value = GetRegisterValue(regnum);
    return true;
207
  } else if (fpuregnum != kInvalidFPURegister) {
208
    *value = GetFPURegisterValue32(fpuregnum);
209 210 211
    return true;
  } else if (strncmp(desc, "0x", 2) == 0) {
    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
212 213 214 215 216 217 218
  } else {
    return SScanF(desc, "%i", value) == 1;
  }
  return false;
}


219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
  int regnum = Registers::Number(desc);
  int fpuregnum = FPURegisters::Number(desc);

  if (regnum != kInvalidRegister) {
    *value = GetRegisterValue(regnum);
    return true;
  } else if (fpuregnum != kInvalidFPURegister) {
    *value = GetFPURegisterValue64(fpuregnum);
    return true;
  } else if (strncmp(desc, "0x", 2) == 0) {
    return SScanF(desc + 2, "%" SCNx64,
                  reinterpret_cast<uint64_t*>(value)) == 1;
  } else {
    return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
  }
  return false;
}


239
bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
240 241 242 243 244 245 246 247 248 249 250 251 252 253
  // Check if a breakpoint can be set. If not return without any side-effects.
  if (sim_->break_pc_ != NULL) {
    return false;
  }

  // Set the breakpoint.
  sim_->break_pc_ = breakpc;
  sim_->break_instr_ = breakpc->InstructionBits();
  // Not setting the breakpoint instruction in the code itself. It will be set
  // when the debugger shell continues.
  return true;
}


254
bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
255 256 257 258 259 260 261 262 263 264
  if (sim_->break_pc_ != NULL) {
    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
  }

  sim_->break_pc_ = NULL;
  sim_->break_instr_ = 0;
  return true;
}


265
void MipsDebugger::UndoBreakpoints() {
266 267 268 269 270 271
  if (sim_->break_pc_ != NULL) {
    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
  }
}


272
void MipsDebugger::RedoBreakpoints() {
273 274 275 276 277
  if (sim_->break_pc_ != NULL) {
    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
  }
}

278 279

void MipsDebugger::PrintAllRegs() {
280 281 282
#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)

  PrintF("\n");
283
  // at, v0, a0.
284 285
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(1), REG_INFO(2), REG_INFO(4));
286
  // v1, a1.
287 288
  PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         "", REG_INFO(3), REG_INFO(5));
289
  // a2.
290
  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
291
  // a3.
292 293 294 295 296 297 298 299
  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
  PrintF("\n");
  // t0-t7, s0-s7
  for (int i = 0; i < 8; i++) {
    PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
           REG_INFO(8+i), REG_INFO(16+i));
  }
  PrintF("\n");
300
  // t8, k0, LO.
301 302
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(24), REG_INFO(26), REG_INFO(32));
303
  // t9, k1, HI.
304 305
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(25), REG_INFO(27), REG_INFO(33));
306
  // sp, fp, gp.
307 308
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(29), REG_INFO(30), REG_INFO(28));
309
  // pc.
310 311
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(31), REG_INFO(34));
312 313 314 315 316 317 318

#undef REG_INFO
#undef FPU_REG_INFO
}


void MipsDebugger::PrintAllRegsIncludingFPU() {
319 320 321 322 323 324 325 326
#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
        GetFPURegisterValue32(n+1), \
        GetFPURegisterValue32(n), \
        GetFPURegisterValueDouble(n)

#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
        GetFPURegisterValue64(n), \
        GetFPURegisterValueDouble(n)
327 328 329 330

  PrintAllRegs();

  PrintF("\n\n");
331
  // f0, f1, f2, ... f31.
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
  // This must be a compile-time switch,
  // compiler will throw out warnings otherwise.
  if (kFpuMode == kFP64) {
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
  } else {
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
  }
385

386
#undef REG_INFO
387 388
#undef FPU_REG_INFO32
#undef FPU_REG_INFO64
389 390
}

391 392

void MipsDebugger::Debug() {
393 394 395 396 397 398 399 400 401 402 403 404
  intptr_t last_pc = -1;
  bool done = false;

#define COMMAND_SIZE 63
#define ARG_SIZE 255

#define STR(a) #a
#define XSTR(a) STR(a)

  char cmd[COMMAND_SIZE + 1];
  char arg1[ARG_SIZE + 1];
  char arg2[ARG_SIZE + 1];
405
  char* argv[3] = { cmd, arg1, arg2 };
406

407
  // Make sure to have a proper terminating character if reaching the limit.
408 409 410 411 412 413 414 415 416 417 418 419
  cmd[COMMAND_SIZE] = 0;
  arg1[ARG_SIZE] = 0;
  arg2[ARG_SIZE] = 0;

  // Undo all set breakpoints while running in the debugger shell. This will
  // make them invisible to all commands.
  UndoBreakpoints();

  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
    if (last_pc != sim_->get_pc()) {
      disasm::NameConverter converter;
      disasm::Disassembler dasm(converter);
420
      // Use a reasonably large buffer.
421 422
      v8::internal::EmbeddedVector<char, 256> buffer;
      dasm.InstructionDecode(buffer,
423
                             reinterpret_cast<byte*>(sim_->get_pc()));
424 425 426 427 428 429 430
      PrintF("  0x%08x  %s\n", sim_->get_pc(), buffer.start());
      last_pc = sim_->get_pc();
    }
    char* line = ReadLine("sim> ");
    if (line == NULL) {
      break;
    } else {
431 432 433 434 435 436 437
      char* last_input = sim_->last_debugger_input();
      if (strcmp(line, "\n") == 0 && last_input != NULL) {
        line = last_input;
      } else {
        // Ownership is transferred to sim_;
        sim_->set_last_debugger_input(line);
      }
438 439
      // Use sscanf to parse the individual parts of the command line. At the
      // moment no command expects more than two parameters.
440
      int argc = SScanF(line,
441 442 443 444 445
                        "%" XSTR(COMMAND_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s",
                        cmd, arg1, arg2);
      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
446 447 448
        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
        if (!(instr->IsTrap()) ||
            instr->InstructionBits() == rtCallRedirInstr) {
449
          sim_->InstructionDecode(
450
              reinterpret_cast<Instruction*>(sim_->get_pc()));
451 452 453
        } else {
          // Allow si to jump over generated breakpoints.
          PrintF("/!\\ Jumping over generated breakpoint.\n");
454
          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
455 456 457 458 459 460 461
        }
      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
        // Execute the one instruction we broke at with breakpoints disabled.
        sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
        // Leave the debugger shell.
        done = true;
      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
462
        if (argc == 2) {
463 464
          if (strcmp(arg1, "all") == 0) {
            PrintAllRegs();
465 466
          } else if (strcmp(arg1, "allf") == 0) {
            PrintAllRegsIncludingFPU();
467
          } else {
468 469 470 471
            int regnum = Registers::Number(arg1);
            int fpuregnum = FPURegisters::Number(arg1);

            if (regnum != kInvalidRegister) {
472
              int32_t value;
473
              value = GetRegisterValue(regnum);
474
              PrintF("%s: 0x%08x %d \n", arg1, value, value);
475
            } else if (fpuregnum != kInvalidFPURegister) {
476 477 478 479 480 481 482
              if (IsFp64Mode()) {
                int64_t value;
                double dvalue;
                value = GetFPURegisterValue64(fpuregnum);
                dvalue = GetFPURegisterValueDouble(fpuregnum);
                PrintF("%3s: 0x%016llx %16.4e\n",
                       FPURegisters::Name(fpuregnum), value, dvalue);
483
              } else {
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
                if (fpuregnum % 2 == 1) {
                  int32_t value;
                  float fvalue;
                  value = GetFPURegisterValue32(fpuregnum);
                  fvalue = GetFPURegisterValueFloat(fpuregnum);
                  PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
                } else {
                  double dfvalue;
                  int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
                  int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
                  dfvalue = GetFPURegisterValueDouble(fpuregnum);
                  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
                         FPURegisters::Name(fpuregnum+1),
                         FPURegisters::Name(fpuregnum),
                         lvalue1,
                         lvalue2,
                         dfvalue);
                }
502
              }
503 504 505 506 507
            } else {
              PrintF("%s unrecognized\n", arg1);
            }
          }
        } else {
508 509 510 511 512 513 514
          if (argc == 3) {
            if (strcmp(arg2, "single") == 0) {
              int32_t value;
              float fvalue;
              int fpuregnum = FPURegisters::Number(arg1);

              if (fpuregnum != kInvalidFPURegister) {
515
                value = GetFPURegisterValue32(fpuregnum);
516 517 518 519 520 521 522 523 524 525 526
                fvalue = GetFPURegisterValueFloat(fpuregnum);
                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
              } else {
                PrintF("%s unrecognized\n", arg1);
              }
            } else {
              PrintF("print <fpu register> single\n");
            }
          } else {
            PrintF("print <register> or print <fpu register> single\n");
          }
527 528 529
        }
      } else if ((strcmp(cmd, "po") == 0)
                 || (strcmp(cmd, "printobject") == 0)) {
530
        if (argc == 2) {
531
          int32_t value;
532
          OFStream os(stdout);
533 534
          if (GetValue(arg1, &value)) {
            Object* obj = reinterpret_cast<Object*>(value);
535
            os << arg1 << ": \n";
536
#ifdef DEBUG
537 538
            obj->Print(os);
            os << "\n";
539
#else
540
            os << Brief(obj) << "\n";
541 542
#endif
          } else {
543
            os << arg1 << " unrecognized\n";
544 545 546 547
          }
        } else {
          PrintF("printobject <value>\n");
        }
548 549 550 551 552 553 554
      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
        int32_t* cur = NULL;
        int32_t* end = NULL;
        int next_arg = 1;

        if (strcmp(cmd, "stack") == 0) {
          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
555
        } else {  // Command "mem".
556 557 558 559 560 561 562 563 564
          int32_t value;
          if (!GetValue(arg1, &value)) {
            PrintF("%s unrecognized\n", arg1);
            continue;
          }
          cur = reinterpret_cast<int32_t*>(value);
          next_arg++;
        }

565 566 567 568 569 570 571 572 573 574 575
        // TODO(palfia): optimize this.
        if (IsFp64Mode()) {
          int64_t words;
          if (argc == next_arg) {
            words = 10;
          } else {
            if (!GetValue(argv[next_arg], &words)) {
              words = 10;
            }
          }
          end = cur + words;
576
        } else {
577 578
          int32_t words;
          if (argc == next_arg) {
579
            words = 10;
580 581 582 583
          } else {
            if (!GetValue(argv[next_arg], &words)) {
              words = 10;
            }
584
          }
585
          end = cur + words;
586 587 588
        }

        while (cur < end) {
589
          PrintF("  0x%08x:  0x%08x %10d",
590
                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
591 592 593
          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
          int value = *cur;
          Heap* current_heap = v8::internal::Isolate::Current()->heap();
594
          if (((value & 1) == 0) || current_heap->Contains(obj)) {
595 596 597 598 599 600 601 602 603
            PrintF(" (");
            if ((value & 1) == 0) {
              PrintF("smi %d", value / 2);
            } else {
              obj->ShortPrint();
            }
            PrintF(")");
          }
          PrintF("\n");
604 605 606
          cur++;
        }

607 608 609
      } else if ((strcmp(cmd, "disasm") == 0) ||
                 (strcmp(cmd, "dpc") == 0) ||
                 (strcmp(cmd, "di") == 0)) {
610 611
        disasm::NameConverter converter;
        disasm::Disassembler dasm(converter);
612
        // Use a reasonably large buffer.
613 614
        v8::internal::EmbeddedVector<char, 256> buffer;

615 616
        byte* cur = NULL;
        byte* end = NULL;
617

618
        if (argc == 1) {
619
          cur = reinterpret_cast<byte*>(sim_->get_pc());
620 621
          end = cur + (10 * Instruction::kInstrSize);
        } else if (argc == 2) {
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
          int regnum = Registers::Number(arg1);
          if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
            // The argument is an address or a register name.
            int32_t value;
            if (GetValue(arg1, &value)) {
              cur = reinterpret_cast<byte*>(value);
              // Disassemble 10 instructions at <arg1>.
              end = cur + (10 * Instruction::kInstrSize);
            }
          } else {
            // The argument is the number of instructions.
            int32_t value;
            if (GetValue(arg1, &value)) {
              cur = reinterpret_cast<byte*>(sim_->get_pc());
              // Disassemble <arg1> instructions.
              end = cur + (value * Instruction::kInstrSize);
            }
639 640 641 642 643
          }
        } else {
          int32_t value1;
          int32_t value2;
          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
644
            cur = reinterpret_cast<byte*>(value1);
645
            end = cur + (value2 * Instruction::kInstrSize);
646 647 648 649 650
          }
        }

        while (cur < end) {
          dasm.InstructionDecode(buffer, cur);
651 652 653
          PrintF("  0x%08x  %s\n",
              reinterpret_cast<intptr_t>(cur), buffer.start());
          cur += Instruction::kInstrSize;
654 655 656
        }
      } else if (strcmp(cmd, "gdb") == 0) {
        PrintF("relinquishing control to gdb\n");
657
        v8::base::OS::DebugBreak();
658 659
        PrintF("regaining control from gdb\n");
      } else if (strcmp(cmd, "break") == 0) {
660
        if (argc == 2) {
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
          int32_t value;
          if (GetValue(arg1, &value)) {
            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
              PrintF("setting breakpoint failed\n");
            }
          } else {
            PrintF("%s unrecognized\n", arg1);
          }
        } else {
          PrintF("break <address>\n");
        }
      } else if (strcmp(cmd, "del") == 0) {
        if (!DeleteBreakpoint(NULL)) {
          PrintF("deleting breakpoint failed\n");
        }
      } else if (strcmp(cmd, "flags") == 0) {
        PrintF("No flags on MIPS !\n");
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
      } else if (strcmp(cmd, "stop") == 0) {
        int32_t value;
        intptr_t stop_pc = sim_->get_pc() -
            2 * Instruction::kInstrSize;
        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
        Instruction* msg_address =
          reinterpret_cast<Instruction*>(stop_pc +
              Instruction::kInstrSize);
        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
          // Remove the current stop.
          if (sim_->IsStopInstruction(stop_instr)) {
            stop_instr->SetInstructionBits(kNopInstr);
            msg_address->SetInstructionBits(kNopInstr);
          } else {
            PrintF("Not at debugger stop.\n");
          }
        } else if (argc == 3) {
          // Print information about all/the specified breakpoint(s).
          if (strcmp(arg1, "info") == 0) {
            if (strcmp(arg2, "all") == 0) {
              PrintF("Stop information:\n");
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->PrintStopInfo(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->PrintStopInfo(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          } else if (strcmp(arg1, "enable") == 0) {
            // Enable all/the specified breakpoint(s).
            if (strcmp(arg2, "all") == 0) {
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->EnableStop(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->EnableStop(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          } else if (strcmp(arg1, "disable") == 0) {
            // Disable all/the specified breakpoint(s).
            if (strcmp(arg2, "all") == 0) {
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->DisableStop(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->DisableStop(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          }
        } else {
          PrintF("Wrong usage. Use help command for more information.\n");
        }
739
      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
740
        // Print registers and disassemble.
741 742 743 744 745
        PrintAllRegs();
        PrintF("\n");

        disasm::NameConverter converter;
        disasm::Disassembler dasm(converter);
746
        // Use a reasonably large buffer.
747 748
        v8::internal::EmbeddedVector<char, 256> buffer;

749 750
        byte* cur = NULL;
        byte* end = NULL;
751

752
        if (argc == 1) {
753
          cur = reinterpret_cast<byte*>(sim_->get_pc());
754 755
          end = cur + (10 * Instruction::kInstrSize);
        } else if (argc == 2) {
756 757
          int32_t value;
          if (GetValue(arg1, &value)) {
758
            cur = reinterpret_cast<byte*>(value);
759
            // no length parameter passed, assume 10 instructions
760
            end = cur + (10 * Instruction::kInstrSize);
761 762 763 764 765
          }
        } else {
          int32_t value1;
          int32_t value2;
          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
766
            cur = reinterpret_cast<byte*>(value1);
767
            end = cur + (value2 * Instruction::kInstrSize);
768 769 770 771 772
          }
        }

        while (cur < end) {
          dasm.InstructionDecode(buffer, cur);
773 774 775
          PrintF("  0x%08x  %s\n",
                 reinterpret_cast<intptr_t>(cur), buffer.start());
          cur += Instruction::kInstrSize;
776 777 778 779 780 781 782 783 784 785 786
        }
      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
        PrintF("cont\n");
        PrintF("  continue execution (alias 'c')\n");
        PrintF("stepi\n");
        PrintF("  step one instruction (alias 'si')\n");
        PrintF("print <register>\n");
        PrintF("  print register content (alias 'p')\n");
        PrintF("  use register name 'all' to print all registers\n");
        PrintF("printobject <register>\n");
        PrintF("  print an object from a register (alias 'po')\n");
787 788 789 790
        PrintF("stack [<words>]\n");
        PrintF("  dump stack content, default dump 10 words)\n");
        PrintF("mem <address> [<words>]\n");
        PrintF("  dump memory content, default dump 10 words)\n");
791 792 793
        PrintF("flags\n");
        PrintF("  print flags\n");
        PrintF("disasm [<instructions>]\n");
794 795 796 797
        PrintF("disasm [<address/register>]\n");
        PrintF("disasm [[<address/register>] <instructions>]\n");
        PrintF("  disassemble code, default is 10 instructions\n");
        PrintF("  from pc (alias 'di')\n");
798 799 800 801 802 803
        PrintF("gdb\n");
        PrintF("  enter gdb\n");
        PrintF("break <address>\n");
        PrintF("  set a break point on the address\n");
        PrintF("del\n");
        PrintF("  delete the breakpoint\n");
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
        PrintF("stop feature:\n");
        PrintF("  Description:\n");
        PrintF("    Stops are debug instructions inserted by\n");
        PrintF("    the Assembler::stop() function.\n");
        PrintF("    When hitting a stop, the Simulator will\n");
        PrintF("    stop and and give control to the Debugger.\n");
        PrintF("    All stop codes are watched:\n");
        PrintF("    - They can be enabled / disabled: the Simulator\n");
        PrintF("       will / won't stop when hitting them.\n");
        PrintF("    - The Simulator keeps track of how many times they \n");
        PrintF("      are met. (See the info command.) Going over a\n");
        PrintF("      disabled stop still increases its counter. \n");
        PrintF("  Commands:\n");
        PrintF("    stop info all/<code> : print infos about number <code>\n");
        PrintF("      or all stop(s).\n");
        PrintF("    stop enable/disable all/<code> : enables / disables\n");
        PrintF("      all or number <code> stop(s)\n");
        PrintF("    stop unstop\n");
        PrintF("      ignore the stop instruction at the current location\n");
        PrintF("      from now on\n");
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
      } else {
        PrintF("Unknown command: %s\n", cmd);
      }
    }
  }

  // Add all the breakpoints back to stop execution and enter the debugger
  // shell when hit.
  RedoBreakpoints();

#undef COMMAND_SIZE
#undef ARG_SIZE

#undef STR
#undef XSTR
}


842
static bool ICacheMatch(void* one, void* two) {
843 844
  DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
  DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
845 846 847
  return one == two;
}

848

849 850 851
static uint32_t ICacheHash(void* key) {
  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
}
852

853 854 855 856 857 858 859 860

static bool AllOnOnePage(uintptr_t start, int size) {
  intptr_t start_page = (start & ~CachePage::kPageMask);
  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
  return start_page == end_page;
}


861 862 863 864 865 866
void Simulator::set_last_debugger_input(char* input) {
  DeleteArray(last_debugger_input_);
  last_debugger_input_ = input;
}


867 868 869 870 871 872 873 874 875 876 877 878 879 880
void Simulator::FlushICache(v8::internal::HashMap* i_cache,
                            void* start_addr,
                            size_t size) {
  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
  int intra_line = (start & CachePage::kLineMask);
  start -= intra_line;
  size += intra_line;
  size = ((size - 1) | CachePage::kLineMask) + 1;
  int offset = (start & CachePage::kPageMask);
  while (!AllOnOnePage(start, size - 1)) {
    int bytes_to_flush = CachePage::kPageSize - offset;
    FlushOnePage(i_cache, start, bytes_to_flush);
    start += bytes_to_flush;
    size -= bytes_to_flush;
881
    DCHECK_EQ(0, start & CachePage::kPageMask);
882 883 884 885 886 887 888 889 890 891
    offset = 0;
  }
  if (size != 0) {
    FlushOnePage(i_cache, start, size);
  }
}


CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
  v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
892 893
                                                        ICacheHash(page),
                                                        true);
894 895 896 897 898 899 900 901 902 903 904 905
  if (entry->value == NULL) {
    CachePage* new_page = new CachePage();
    entry->value = new_page;
  }
  return reinterpret_cast<CachePage*>(entry->value);
}


// Flush from start up to and not including start + size.
void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
                             intptr_t start,
                             int size) {
906 907 908 909
  DCHECK(size <= CachePage::kPageSize);
  DCHECK(AllOnOnePage(start, size - 1));
  DCHECK((start & CachePage::kLineMask) == 0);
  DCHECK((size & CachePage::kLineMask) == 0);
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
  int offset = (start & CachePage::kPageMask);
  CachePage* cache_page = GetCachePage(i_cache, page);
  char* valid_bytemap = cache_page->ValidityByte(offset);
  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
}


void Simulator::CheckICache(v8::internal::HashMap* i_cache,
                            Instruction* instr) {
  intptr_t address = reinterpret_cast<intptr_t>(instr);
  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
  int offset = (address & CachePage::kPageMask);
  CachePage* cache_page = GetCachePage(i_cache, page);
  char* cache_valid_byte = cache_page->ValidityByte(offset);
  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
  if (cache_hit) {
    // Check that the data in memory matches the contents of the I-cache.
930 931 932
    CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
                       cache_page->CachedData(offset),
                       Instruction::kInstrSize));
933 934
  } else {
    // Cache miss.  Load memory into the cache.
935
    memcpy(cached_line, line, CachePage::kLineLength);
936 937 938
    *cache_valid_byte = CachePage::LINE_VALID;
  }
}
939 940


941 942 943 944 945
void Simulator::Initialize(Isolate* isolate) {
  if (isolate->simulator_initialized()) return;
  isolate->set_simulator_initialized(true);
  ::v8::internal::ExternalReference::set_redirector(isolate,
                                                    &RedirectExternalReference);
946 947 948
}


949
Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
950 951 952 953 954
  i_cache_ = isolate_->simulator_i_cache();
  if (i_cache_ == NULL) {
    i_cache_ = new v8::internal::HashMap(&ICacheMatch);
    isolate_->set_simulator_i_cache(i_cache_);
  }
955
  Initialize(isolate);
956
  // Set up simulator support first. Some of this information is needed to
957
  // setup the architecture state.
958
  stack_ = reinterpret_cast<char*>(malloc(stack_size_));
959 960
  pc_modified_ = false;
  icount_ = 0;
961
  break_count_ = 0;
962 963 964
  break_pc_ = NULL;
  break_instr_ = 0;

965
  // Set up architecture state.
966 967 968 969
  // All registers are initialized to zero to start with.
  for (int i = 0; i < kNumSimuRegisters; i++) {
    registers_[i] = 0;
  }
970 971 972 973
  for (int i = 0; i < kNumFPURegisters; i++) {
    FPUregisters_[i] = 0;
  }
  FCSR_ = 0;
974 975 976 977

  // The sp is initialized to point to the bottom (high address) of the
  // allocated stack area. To be safe in potential stack underflows we leave
  // some buffer below.
978
  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
979 980 981 982 983
  // The ra and pc are initialized to a known bad value that will cause an
  // access violation if the simulator ever tries to execute it.
  registers_[pc] = bad_ra;
  registers_[ra] = bad_ra;
  InitializeCoverage();
984 985 986
  for (int i = 0; i < kNumExceptions; i++) {
    exceptions[i] = 0;
  }
987 988

  last_debugger_input_ = NULL;
989
}
990 991 992 993


Simulator::~Simulator() {
}
994 995 996 997 998 999 1000 1001 1002 1003 1004


// When the generated code calls an external reference we need to catch that in
// the simulator.  The external reference will be a function compiled for the
// host architecture.  We need to call that function instead of trying to
// execute it with the simulator.  We do that by redirecting the external
// reference to a swi (software-interrupt) instruction that is handled by
// the simulator.  We write the original destination of the jump just at a known
// offset from the swi instruction so the simulator knows what to call.
class Redirection {
 public:
1005
  Redirection(void* external_function, ExternalReference::Type type)
1006 1007
      : external_function_(external_function),
        swi_instruction_(rtCallRedirInstr),
1008 1009 1010 1011 1012 1013 1014 1015 1016
        type_(type),
        next_(NULL) {
    Isolate* isolate = Isolate::Current();
    next_ = isolate->simulator_redirection();
    Simulator::current(isolate)->
        FlushICache(isolate->simulator_i_cache(),
                    reinterpret_cast<void*>(&swi_instruction_),
                    Instruction::kInstrSize);
    isolate->set_simulator_redirection(this);
1017 1018 1019 1020 1021 1022 1023
  }

  void* address_of_swi_instruction() {
    return reinterpret_cast<void*>(&swi_instruction_);
  }

  void* external_function() { return external_function_; }
1024
  ExternalReference::Type type() { return type_; }
1025

1026 1027 1028 1029 1030
  static Redirection* Get(void* external_function,
                          ExternalReference::Type type) {
    Isolate* isolate = Isolate::Current();
    Redirection* current = isolate->simulator_redirection();
    for (; current != NULL; current = current->next_) {
1031 1032
      if (current->external_function_ == external_function) return current;
    }
1033
    return new Redirection(external_function, type);
1034 1035 1036 1037 1038 1039 1040 1041 1042
  }

  static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
    char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
    char* addr_of_redirection =
        addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
    return reinterpret_cast<Redirection*>(addr_of_redirection);
  }

1043 1044 1045 1046 1047 1048
  static void* ReverseRedirection(int32_t reg) {
    Redirection* redirection = FromSwiInstruction(
        reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
    return redirection->external_function();
  }

1049 1050 1051
 private:
  void* external_function_;
  uint32_t swi_instruction_;
1052
  ExternalReference::Type type_;
1053 1054 1055 1056 1057
  Redirection* next_;
};


void* Simulator::RedirectExternalReference(void* external_function,
1058 1059
                                           ExternalReference::Type type) {
  Redirection* redirection = Redirection::Get(external_function, type);
1060 1061 1062 1063 1064
  return redirection->address_of_swi_instruction();
}


// Get the active Simulator for the current thread.
1065 1066
Simulator* Simulator::current(Isolate* isolate) {
  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
1067
       isolate->FindOrAllocatePerThreadDataForThisThread();
1068 1069
  DCHECK(isolate_data != NULL);
  DCHECK(isolate_data != NULL);
1070 1071

  Simulator* sim = isolate_data->simulator();
1072
  if (sim == NULL) {
1073
    // TODO(146): delete the simulator object when a thread/isolate goes away.
1074
    sim = new Simulator(isolate);
1075
    isolate_data->set_simulator(sim);
1076 1077 1078 1079 1080 1081 1082 1083
  }
  return sim;
}


// Sets the register in the architecture state. It will also deal with updating
// Simulator internal state for special registers such as PC.
void Simulator::set_register(int reg, int32_t value) {
1084
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1085 1086 1087 1088
  if (reg == pc) {
    pc_modified_ = true;
  }

1089
  // Zero register always holds 0.
1090 1091 1092
  registers_[reg] = (reg == 0) ? 0 : value;
}

1093

1094
void Simulator::set_dw_register(int reg, const int* dbl) {
1095
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1096 1097 1098 1099 1100
  registers_[reg] = dbl[0];
  registers_[reg + 1] = dbl[1];
}


1101 1102
void Simulator::set_fpu_register(int fpureg, int64_t value) {
  DCHECK(IsFp64Mode());
1103
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1104 1105 1106
  FPUregisters_[fpureg] = value;
}

1107

1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
  // Set ONLY lower 32-bits, leaving upper bits untouched.
  // TODO(plind): big endian issue.
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
  int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
  *pword = value;
}


void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
  // Set ONLY upper 32-bits, leaving lower bits untouched.
  // TODO(plind): big endian issue.
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
  int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
  *phiword = value;
}


1126
void Simulator::set_fpu_register_float(int fpureg, float value) {
1127
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1128
  *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
1129 1130 1131
}


1132
void Simulator::set_fpu_register_double(int fpureg, double value) {
1133 1134
  if (IsFp64Mode()) {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1135
    *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1136 1137
  } else {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1138
    int64_t i64 = bit_cast<int64_t>(value);
1139 1140 1141
    set_fpu_register_word(fpureg, i64 & 0xffffffff);
    set_fpu_register_word(fpureg + 1, i64 >> 32);
  }
1142 1143 1144 1145 1146 1147
}


// Get the register from the architecture state. This function does handle
// the special case of accessing the PC register.
int32_t Simulator::get_register(int reg) const {
1148
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1149 1150 1151 1152 1153 1154
  if (reg == 0)
    return 0;
  else
    return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
}

1155

1156
double Simulator::get_double_from_register_pair(int reg) {
1157
  // TODO(plind): bad ABI stuff, refactor or remove.
1158
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1159 1160 1161 1162 1163

  double dm_val = 0.0;
  // Read the bits from the unsigned integer register_[] array
  // into the double precision floating point value and return it.
  char buffer[2 * sizeof(registers_[0])];
1164 1165
  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1166 1167 1168 1169
  return(dm_val);
}


1170 1171
int64_t Simulator::get_fpu_register(int fpureg) const {
  DCHECK(IsFp64Mode());
1172
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1173 1174 1175
  return FPUregisters_[fpureg];
}

1176

1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
int32_t Simulator::get_fpu_register_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
  return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
}


int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
  return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
}


int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
  return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
1192 1193 1194 1195
}


float Simulator::get_fpu_register_float(int fpureg) const {
1196
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1197
  return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
1198 1199 1200
}


1201
double Simulator::get_fpu_register_double(int fpureg) const {
1202 1203
  if (IsFp64Mode()) {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1204
    return *bit_cast<double*>(&FPUregisters_[fpureg]);
1205 1206 1207 1208 1209
  } else {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
    int64_t i64;
    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1210
    return bit_cast<double>(i64);
1211
  }
1212 1213 1214
}


1215 1216
// Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
1217
// from a0-a3 or f12 and f14.
1218
void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1219 1220 1221
  if (!IsMipsSoftFloatABI) {
    *x = get_fpu_register_double(12);
    *y = get_fpu_register_double(14);
1222
    *z = get_register(a2);
1223
  } else {
1224
    // TODO(plind): bad ABI stuff, refactor or remove.
1225 1226 1227 1228 1229 1230 1231 1232
    // We use a char buffer to get around the strict-aliasing rules which
    // otherwise allow the compiler to optimize away the copy.
    char buffer[sizeof(*x)];
    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);

    // Registers a0 and a1 -> x.
    reg_buffer[0] = get_register(a0);
    reg_buffer[1] = get_register(a1);
1233
    memcpy(x, buffer, sizeof(buffer));
1234 1235 1236
    // Registers a2 and a3 -> y.
    reg_buffer[0] = get_register(a2);
    reg_buffer[1] = get_register(a3);
1237
    memcpy(y, buffer, sizeof(buffer));
1238
    // Register 2 -> z.
1239
    reg_buffer[0] = get_register(a2);
1240
    memcpy(z, buffer, sizeof(*z));
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
  }
}


// The return value is either in v0/v1 or f0.
void Simulator::SetFpResult(const double& result) {
  if (!IsMipsSoftFloatABI) {
    set_fpu_register_double(0, result);
  } else {
    char buffer[2 * sizeof(registers_[0])];
    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1252
    memcpy(buffer, &result, sizeof(buffer));
1253 1254 1255 1256 1257 1258 1259
    // Copy result to v0 and v1.
    set_register(v0, reg_buffer[0]);
    set_register(v1, reg_buffer[1]);
  }
}


1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
// Helper functions for setting and testing the FCSR register's bits.
void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
  if (value) {
    FCSR_ |= (1 << cc);
  } else {
    FCSR_ &= ~(1 << cc);
  }
}


bool Simulator::test_fcsr_bit(uint32_t cc) {
  return FCSR_ & (1 << cc);
1272 1273
}

1274 1275 1276 1277

// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round_error(double original, double rounded) {
1278
  bool ret = false;
1279 1280
  double max_int32 = std::numeric_limits<int32_t>::max();
  double min_int32 = std::numeric_limits<int32_t>::min();
1281

1282
  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1283 1284
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
1285
  }
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295

  if (original != rounded) {
    set_fcsr_bit(kFCSRInexactFlagBit, true);
  }

  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
    ret = true;
  }

1296
  if (rounded > max_int32 || rounded < min_int32) {
1297 1298 1299 1300 1301 1302 1303
    set_fcsr_bit(kFCSROverflowFlagBit, true);
    // The reference is not really clear but it seems this is required:
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  return ret;
1304 1305 1306
}


1307 1308 1309 1310 1311 1312
// Raw access to the PC register.
void Simulator::set_pc(int32_t value) {
  pc_modified_ = true;
  registers_[pc] = value;
}

1313 1314 1315 1316 1317 1318

bool Simulator::has_bad_pc() const {
  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
}


1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
// Raw access to the PC register without the special adjustment when reading.
int32_t Simulator::get_pc() const {
  return registers_[pc];
}


// The MIPS cannot do unaligned reads and writes.  On some MIPS platforms an
// interrupt is caused.  On others it does a funky rotation thing.  For now we
// simply disallow unaligned reads, but at some point we may want to move to
// emulating the rotate behaviour.  Note that simulator runs have the runtime
// system running directly on the host system and only generated code is
// executed in the simulator.  Since the host is typically IA32 we will not
// get the correct MIPS-like behaviour on unaligned accesses.

int Simulator::ReadW(int32_t addr, Instruction* instr) {
1334
  if (addr >=0 && addr < 0x400) {
1335
    // This has to be a NULL-dereference, drop into debugger.
1336 1337
    PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
           addr, reinterpret_cast<intptr_t>(instr));
1338 1339 1340 1341
    MipsDebugger dbg(this);
    dbg.Debug();
  }
  if ((addr & kPointerAlignmentMask) == 0) {
1342 1343 1344
    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
    return *ptr;
  }
1345 1346 1347
  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1348 1349
  MipsDebugger dbg(this);
  dbg.Debug();
1350 1351 1352 1353 1354
  return 0;
}


void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1355
  if (addr >= 0 && addr < 0x400) {
1356
    // This has to be a NULL-dereference, drop into debugger.
1357 1358
    PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
           addr, reinterpret_cast<intptr_t>(instr));
1359 1360 1361 1362
    MipsDebugger dbg(this);
    dbg.Debug();
  }
  if ((addr & kPointerAlignmentMask) == 0) {
1363 1364 1365 1366
    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
    *ptr = value;
    return;
  }
1367 1368 1369
  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1370 1371
  MipsDebugger dbg(this);
  dbg.Debug();
1372 1373 1374 1375 1376 1377 1378 1379
}


double Simulator::ReadD(int32_t addr, Instruction* instr) {
  if ((addr & kDoubleAlignmentMask) == 0) {
    double* ptr = reinterpret_cast<double*>(addr);
    return *ptr;
  }
1380 1381 1382
  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1383
  base::OS::Abort();
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
  return 0;
}


void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
  if ((addr & kDoubleAlignmentMask) == 0) {
    double* ptr = reinterpret_cast<double*>(addr);
    *ptr = value;
    return;
  }
1394 1395 1396
  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1397
  base::OS::Abort();
1398 1399 1400 1401 1402 1403 1404 1405
}


uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
  if ((addr & 1) == 0) {
    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
    return *ptr;
  }
1406 1407 1408
  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1409
  base::OS::Abort();
1410 1411 1412 1413 1414 1415 1416 1417 1418
  return 0;
}


int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
  if ((addr & 1) == 0) {
    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
    return *ptr;
  }
1419 1420 1421
  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1422
  base::OS::Abort();
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
  return 0;
}


void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
  if ((addr & 1) == 0) {
    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
    *ptr = value;
    return;
  }
1433 1434 1435
  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1436
  base::OS::Abort();
1437 1438 1439 1440 1441 1442 1443 1444 1445
}


void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
  if ((addr & 1) == 0) {
    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
    *ptr = value;
    return;
  }
1446 1447 1448
  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1449
  base::OS::Abort();
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
}


uint32_t Simulator::ReadBU(int32_t addr) {
  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
  return *ptr & 0xff;
}


int32_t Simulator::ReadB(int32_t addr) {
  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1461
  return *ptr;
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
}


void Simulator::WriteB(int32_t addr, uint8_t value) {
  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
  *ptr = value;
}


void Simulator::WriteB(int32_t addr, int8_t value) {
  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
  *ptr = value;
}


// Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit() const {
1479
  // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
1480
  // pushing values.
1481
  return reinterpret_cast<uintptr_t>(stack_) + 1024;
1482 1483 1484 1485 1486 1487
}


// Unsupported instructions use Format to print an error and stop execution.
void Simulator::Format(Instruction* instr, const char* format) {
  PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
1488
         reinterpret_cast<intptr_t>(instr), format);
1489 1490 1491 1492 1493 1494 1495 1496
  UNIMPLEMENTED_MIPS();
}


// Calls into the V8 runtime are based on this very simple interface.
// Note: To be able to return two values from some calls the code in runtime.cc
// uses the ObjectPair which is essentially two 32-bit values stuffed into a
// 64-bit value. With the code below we assume that all runtime calls return
1497
// 64 bits of result. If they don't, the v1 result register contains a bogus
1498 1499 1500 1501
// value, which is fine because it is caller-saved.
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
                                        int32_t arg1,
                                        int32_t arg2,
1502 1503 1504
                                        int32_t arg3,
                                        int32_t arg4,
                                        int32_t arg5);
1505 1506 1507 1508 1509 1510

// These prototypes handle the four types of FP calls.
typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
typedef double (*SimulatorRuntimeFPCall)(double darg0);
typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1511

1512 1513
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
1514
typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1515
typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
1516 1517

// This signature supports direct call to accessor getter callback.
1518 1519
typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
typedef void (*SimulatorRuntimeProfilingGetterCall)(
1520
    int32_t arg0, int32_t arg1, void* arg2);
1521

1522
// Software interrupt instructions are used by the simulator to call into the
1523
// C-based V8 runtime. They are also used for debugging with simulator.
1524
void Simulator::SoftwareInterrupt(Instruction* instr) {
1525 1526 1527 1528
  // There are several instructions that could get us here,
  // the break_ instruction, or several variants of traps. All
  // Are "SPECIAL" class opcode, and are distinuished by function.
  int32_t func = instr->FunctionFieldRaw();
1529
  uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
1530

1531 1532 1533 1534 1535 1536 1537
  // We first check if we met a call_rt_redirected.
  if (instr->InstructionBits() == rtCallRedirInstr) {
    Redirection* redirection = Redirection::FromSwiInstruction(instr);
    int32_t arg0 = get_register(a0);
    int32_t arg1 = get_register(a1);
    int32_t arg2 = get_register(a2);
    int32_t arg3 = get_register(a3);
1538 1539

    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1540 1541 1542
    // Args 4 and 5 are on the stack after the reserved space for args 0..3.
    int32_t arg4 = stack_pointer[4];
    int32_t arg5 = stack_pointer[5];
1543 1544 1545 1546 1547 1548 1549

    bool fp_call =
         (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);

1550 1551 1552 1553 1554 1555 1556 1557
    if (!IsMipsSoftFloatABI) {
      // With the hard floating point calling convention, double
      // arguments are passed in FPU registers. Fetch the arguments
      // from there and call the builtin using soft floating point
      // convention.
      switch (redirection->type()) {
      case ExternalReference::BUILTIN_FP_FP_CALL:
      case ExternalReference::BUILTIN_COMPARE_CALL:
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
          arg2 = get_fpu_register_word(f14);
          arg3 = get_fpu_register_hi_word(f14);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
          arg2 = get_fpu_register_word(f14);
          arg3 = get_fpu_register_word(f15);
        }
1569 1570
        break;
      case ExternalReference::BUILTIN_FP_CALL:
1571 1572 1573 1574 1575 1576 1577
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
        }
1578 1579
        break;
      case ExternalReference::BUILTIN_FP_INT_CALL:
1580 1581 1582 1583 1584 1585 1586
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
        }
1587 1588 1589 1590 1591 1592 1593
        arg2 = get_register(a2);
        break;
      default:
        break;
      }
    }

1594 1595 1596
    // This is dodgy but it works because the C entry stubs are never moved.
    // See comment in codegen-arm.cc and bug 1242173.
    int32_t saved_ra = get_register(ra);
1597 1598

    intptr_t external =
1599
          reinterpret_cast<intptr_t>(redirection->external_function());
1600 1601 1602 1603

    // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
    // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
    // simulator. Soft-float has additional abstraction of ExternalReference,
1604
    // to support serialization.
1605
    if (fp_call) {
1606 1607 1608 1609 1610 1611 1612
      double dval0, dval1;  // one or two double parameters
      int32_t ival;         // zero or one integer parameters
      int64_t iresult = 0;  // integer return value
      double dresult = 0;   // double return value
      GetFpArgs(&dval0, &dval1, &ival);
      SimulatorRuntimeCall generic_target =
          reinterpret_cast<SimulatorRuntimeCall>(external);
1613
      if (::v8::internal::FLAG_trace_sim) {
1614 1615 1616 1617
        switch (redirection->type()) {
          case ExternalReference::BUILTIN_FP_FP_CALL:
          case ExternalReference::BUILTIN_COMPARE_CALL:
            PrintF("Call to host function at %p with args %f, %f",
1618
                   FUNCTION_ADDR(generic_target), dval0, dval1);
1619 1620 1621
            break;
          case ExternalReference::BUILTIN_FP_CALL:
            PrintF("Call to host function at %p with arg %f",
1622
                FUNCTION_ADDR(generic_target), dval0);
1623 1624 1625
            break;
          case ExternalReference::BUILTIN_FP_INT_CALL:
            PrintF("Call to host function at %p with args %f, %d",
1626
                   FUNCTION_ADDR(generic_target), dval0, ival);
1627 1628 1629 1630 1631 1632
            break;
          default:
            UNREACHABLE();
            break;
        }
      }
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
      switch (redirection->type()) {
      case ExternalReference::BUILTIN_COMPARE_CALL: {
        SimulatorRuntimeCompareCall target =
          reinterpret_cast<SimulatorRuntimeCompareCall>(external);
        iresult = target(dval0, dval1);
        set_register(v0, static_cast<int32_t>(iresult));
        set_register(v1, static_cast<int32_t>(iresult >> 32));
        break;
      }
      case ExternalReference::BUILTIN_FP_FP_CALL: {
        SimulatorRuntimeFPFPCall target =
          reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
        dresult = target(dval0, dval1);
        SetFpResult(dresult);
        break;
      }
      case ExternalReference::BUILTIN_FP_CALL: {
1650
        SimulatorRuntimeFPCall target =
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680
          reinterpret_cast<SimulatorRuntimeFPCall>(external);
        dresult = target(dval0);
        SetFpResult(dresult);
        break;
      }
      case ExternalReference::BUILTIN_FP_INT_CALL: {
        SimulatorRuntimeFPIntCall target =
          reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
        dresult = target(dval0, ival);
        SetFpResult(dresult);
        break;
      }
      default:
        UNREACHABLE();
        break;
      }
      if (::v8::internal::FLAG_trace_sim) {
        switch (redirection->type()) {
        case ExternalReference::BUILTIN_COMPARE_CALL:
          PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
          break;
        case ExternalReference::BUILTIN_FP_FP_CALL:
        case ExternalReference::BUILTIN_FP_CALL:
        case ExternalReference::BUILTIN_FP_INT_CALL:
          PrintF("Returned %f\n", dresult);
          break;
        default:
          UNREACHABLE();
          break;
        }
1681
      }
1682 1683 1684 1685
    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x\n",
            reinterpret_cast<void*>(external), arg0);
1686
      }
1687 1688 1689
      SimulatorRuntimeDirectApiCall target =
          reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
      target(arg0);
1690
    } else if (
1691 1692 1693 1694
        redirection->type() == ExternalReference::PROFILING_API_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1);
1695
      }
1696 1697
      SimulatorRuntimeProfilingApiCall target =
          reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1698
      target(arg0, Redirection::ReverseRedirection(arg1));
1699
    } else if (
1700 1701 1702 1703
        redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1);
1704
      }
1705 1706 1707
      SimulatorRuntimeDirectGetterCall target =
          reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
      target(arg0, arg1);
1708
    } else if (
1709 1710 1711 1712
        redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1, arg2);
1713
      }
1714 1715
      SimulatorRuntimeProfilingGetterCall target =
          reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
1716
      target(arg0, arg1, Redirection::ReverseRedirection(arg2));
1717 1718
    } else {
      SimulatorRuntimeCall target =
1719 1720
                  reinterpret_cast<SimulatorRuntimeCall>(external);
      if (::v8::internal::FLAG_trace_sim) {
1721
        PrintF(
1722 1723
            "Call to host function at %p "
            "args %08x, %08x, %08x, %08x, %08x, %08x\n",
1724 1725 1726 1727
            FUNCTION_ADDR(target),
            arg0,
            arg1,
            arg2,
1728 1729 1730
            arg3,
            arg4,
            arg5);
1731
      }
1732 1733 1734 1735 1736 1737
      int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
      set_register(v0, static_cast<int32_t>(result));
      set_register(v1, static_cast<int32_t>(result >> 32));
    }
    if (::v8::internal::FLAG_trace_sim) {
      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
1738 1739 1740
    }
    set_register(ra, saved_ra);
    set_pc(get_register(ra));
1741

1742 1743 1744 1745 1746 1747 1748
  } else if (func == BREAK && code <= kMaxStopCode) {
    if (IsWatchpoint(code)) {
      PrintWatchpoint(code);
    } else {
      IncreaseStopCounter(code);
      HandleStop(code, instr);
    }
1749
  } else {
1750 1751
    // All remaining break_ codes, and all traps are handled here.
    MipsDebugger dbg(this);
1752 1753 1754 1755
    dbg.Debug();
  }
}

1756

1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
// Stop helper functions.
bool Simulator::IsWatchpoint(uint32_t code) {
  return (code <= kMaxWatchpointCode);
}


void Simulator::PrintWatchpoint(uint32_t code) {
  MipsDebugger dbg(this);
  ++break_count_;
  PrintF("\n---- break %d marker: %3d  (instr count: %8d) ----------"
         "----------------------------------",
         code, break_count_, icount_);
  dbg.PrintAllRegs();  // Print registers and continue running.
}


void Simulator::HandleStop(uint32_t code, Instruction* instr) {
  // Stop if it is enabled, otherwise go on jumping over the stop
  // and the message address.
  if (IsEnabledStop(code)) {
    MipsDebugger dbg(this);
    dbg.Stop(instr);
  } else {
    set_pc(get_pc() + 2 * Instruction::kInstrSize);
  }
}


bool Simulator::IsStopInstruction(Instruction* instr) {
  int32_t func = instr->FunctionFieldRaw();
  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
}


bool Simulator::IsEnabledStop(uint32_t code) {
1793 1794
  DCHECK(code <= kMaxStopCode);
  DCHECK(code > kMaxWatchpointCode);
1795
  return !(watched_stops_[code].count & kStopDisabledBit);
1796 1797 1798 1799 1800
}


void Simulator::EnableStop(uint32_t code) {
  if (!IsEnabledStop(code)) {
1801
    watched_stops_[code].count &= ~kStopDisabledBit;
1802 1803 1804 1805 1806 1807
  }
}


void Simulator::DisableStop(uint32_t code) {
  if (IsEnabledStop(code)) {
1808
    watched_stops_[code].count |= kStopDisabledBit;
1809 1810 1811 1812 1813
  }
}


void Simulator::IncreaseStopCounter(uint32_t code) {
1814
  DCHECK(code <= kMaxStopCode);
1815
  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
1816 1817
    PrintF("Stop counter for code %i has overflowed.\n"
           "Enabling this code and reseting the counter to 0.\n", code);
1818
    watched_stops_[code].count = 0;
1819 1820
    EnableStop(code);
  } else {
1821
    watched_stops_[code].count++;
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
  }
}


// Print a stop status.
void Simulator::PrintStopInfo(uint32_t code) {
  if (code <= kMaxWatchpointCode) {
    PrintF("That is a watchpoint, not a stop.\n");
    return;
  } else if (code > kMaxStopCode) {
    PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
    return;
  }
  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
1836
  int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
1837 1838
  // Don't print the state of unused breakpoints.
  if (count != 0) {
1839
    if (watched_stops_[code].desc) {
1840
      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1841
             code, code, state, count, watched_stops_[code].desc);
1842 1843 1844 1845 1846 1847 1848 1849
    } else {
      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
             code, code, state, count);
    }
  }
}


1850 1851 1852 1853 1854 1855 1856 1857 1858
void Simulator::SignalExceptions() {
  for (int i = 1; i < kNumExceptions; i++) {
    if (exceptions[i] != 0) {
      V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
    }
  }
}


1859
// Handle execution based on instruction types.
1860

1861
void Simulator::ConfigureTypeRegister(Instruction* instr,
1862 1863 1864 1865 1866 1867
                                      int32_t* alu_out,
                                      int64_t* i64hilo,
                                      uint64_t* u64hilo,
                                      int32_t* next_pc,
                                      int32_t* return_addr_reg,
                                      bool* do_interrupt) {
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
  // Every local variable declared here needs to be const.
  // This is to make sure that changed values are sent back to
  // DecodeTypeRegister correctly.

  // Instruction fields.
  const Opcode   op     = instr->OpcodeFieldRaw();
  const int32_t  rs_reg = instr->RsValue();
  const int32_t  rs     = get_register(rs_reg);
  const uint32_t rs_u   = static_cast<uint32_t>(rs);
  const int32_t  rt_reg = instr->RtValue();
  const int32_t  rt     = get_register(rt_reg);
  const uint32_t rt_u   = static_cast<uint32_t>(rt);
  const int32_t  rd_reg = instr->RdValue();
  const uint32_t sa     = instr->SaValue();

  const int32_t  fs_reg = instr->FsValue();
1884 1885


1886
  // ---------- Configuration.
1887
  switch (op) {
1888
    case COP1:    // Coprocessor instructions.
1889
      switch (instr->RsFieldRaw()) {
1890 1891
        case CFC1:
          // At the moment only FCSR is supported.
1892
          DCHECK(fs_reg == kFCSRRegister);
1893
          *alu_out = FCSR_;
1894
          break;
1895
        case MFC1:
1896
          *alu_out = get_fpu_register_word(fs_reg);
1897 1898
          break;
        case MFHC1:
1899
          *alu_out = get_fpu_register_hi_word(fs_reg);
1900
          break;
1901
        case CTC1:
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
        case MTC1:
        case MTHC1:
        case S:
        case D:
        case W:
        case L:
        case PS:
          // Do everything in the execution step.
          break;
        default:
1912 1913
        // BC1 BC1EQZ BC1NEZ handled in DecodeTypeImmed, should never come here.
          UNREACHABLE();
1914
      }
1915
      break;
1916 1917
    case COP1X:
      break;
1918 1919 1920 1921
    case SPECIAL:
      switch (instr->FunctionFieldRaw()) {
        case JR:
        case JALR:
1922 1923
          *next_pc = get_register(instr->RsValue());
          *return_addr_reg = instr->RdValue();
1924 1925
          break;
        case SLL:
1926
          *alu_out = rt << sa;
1927 1928
          break;
        case SRL:
1929 1930 1931
          if (rs_reg == 0) {
            // Regular logical right shift of a word by a fixed number of
            // bits instruction. RS field is always equal to 0.
1932
            *alu_out = rt_u >> sa;
1933 1934 1935
          } else {
            // Logical right-rotate of a word by a fixed number of bits. This
            // is special case of SRL instruction, added in MIPS32 Release 2.
1936
            // RS field is equal to 00001.
1937
            *alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
1938
          }
1939 1940
          break;
        case SRA:
1941
          *alu_out = rt >> sa;
1942 1943
          break;
        case SLLV:
1944
          *alu_out = rt << rs;
1945 1946
          break;
        case SRLV:
1947 1948 1949
          if (sa == 0) {
            // Regular logical right-shift of a word by a variable number of
            // bits instruction. SA field is always equal to 0.
1950
            *alu_out = rt_u >> rs;
1951 1952 1953
          } else {
            // Logical right-rotate of a word by a variable number of bits.
            // This is special case od SRLV instruction, added in MIPS32
1954
            // Release 2. SA field is equal to 00001.
1955
            *alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
1956
          }
1957 1958
          break;
        case SRAV:
1959
          *alu_out = rt >> rs;
1960
          break;
1961 1962 1963 1964 1965 1966 1967 1968
        case MFHI:  // MFHI == CLZ on R6.
          if (!IsMipsArchVariant(kMips32r6)) {
            DCHECK(instr->SaValue() == 0);
            *alu_out = get_register(HI);
          } else {
            // MIPS spec: If no bits were set in GPR rs, the result written to
            // GPR rd is 32.
            DCHECK(instr->SaValue() == 1);
1969
            *alu_out = base::bits::CountLeadingZeros32(rs_u);
1970
          }
1971 1972
          break;
        case MFLO:
1973
          *alu_out = get_register(LO);
1974
          break;
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
        case MULT:  // MULT == MUL_MUH.
          if (!IsMipsArchVariant(kMips32r6)) {
            *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
          } else {
            switch (instr->SaValue()) {
              case MUL_OP:
              case MUH_OP:
                *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
            }
          }
1989
          break;
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
        case MULTU:  // MULTU == MUL_MUH_U.
          if (!IsMipsArchVariant(kMips32r6)) {
            *u64hilo = static_cast<uint64_t>(rs_u) *
                static_cast<uint64_t>(rt_u);
          } else {
            switch (instr->SaValue()) {
              case MUL_OP:
              case MUH_OP:
                *u64hilo = static_cast<uint64_t>(rs_u) *
                    static_cast<uint64_t>(rt_u);
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
            }
          }
2006 2007 2008 2009 2010 2011 2012 2013 2014
          break;
        case ADD:
          if (HaveSameSign(rs, rt)) {
            if (rs > 0) {
              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
            } else if (rs < 0) {
              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
            }
          }
2015
          *alu_out = rs + rt;
2016 2017
          break;
        case ADDU:
2018
          *alu_out = rs + rt;
2019 2020 2021 2022 2023 2024 2025 2026 2027
          break;
        case SUB:
          if (!HaveSameSign(rs, rt)) {
            if (rs > 0) {
              exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
            } else if (rs < 0) {
              exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
            }
          }
2028
          *alu_out = rs - rt;
2029 2030
          break;
        case SUBU:
2031
          *alu_out = rs - rt;
2032 2033
          break;
        case AND:
2034
          *alu_out = rs & rt;
2035 2036
          break;
        case OR:
2037
          *alu_out = rs | rt;
2038 2039
          break;
        case XOR:
2040
          *alu_out = rs ^ rt;
2041 2042
          break;
        case NOR:
2043
          *alu_out = ~(rs | rt);
2044 2045
          break;
        case SLT:
2046
          *alu_out = rs < rt ? 1 : 0;
2047 2048
          break;
        case SLTU:
2049
          *alu_out = rs_u < rt_u ? 1 : 0;
2050
          break;
2051
        // Break and trap instructions.
2052
        case BREAK:
2053
          *do_interrupt = true;
2054 2055
          break;
        case TGE:
2056
          *do_interrupt = rs >= rt;
2057 2058
          break;
        case TGEU:
2059
          *do_interrupt = rs_u >= rt_u;
2060 2061
          break;
        case TLT:
2062
          *do_interrupt = rs < rt;
2063 2064
          break;
        case TLTU:
2065
          *do_interrupt = rs_u < rt_u;
2066 2067
          break;
        case TEQ:
2068
          *do_interrupt = rs == rt;
2069 2070
          break;
        case TNE:
2071
          *do_interrupt = rs != rt;
2072
          break;
2073 2074 2075 2076 2077
        case MOVN:
        case MOVZ:
        case MOVCI:
          // No action taken on decode.
          break;
2078 2079 2080 2081
        case DIV:
        case DIVU:
          // div and divu never raise exceptions.
          break;
2082 2083
        default:
          UNREACHABLE();
2084
      }
2085 2086 2087 2088
      break;
    case SPECIAL2:
      switch (instr->FunctionFieldRaw()) {
        case MUL:
2089
          *alu_out = rs_u * rt_u;  // Only the lower 32 bits are kept.
2090
          break;
2091
        case CLZ:
2092 2093
          // MIPS32 spec: If no bits were set in GPR rs, the result written to
          // GPR rd is 32.
2094
          *alu_out = base::bits::CountLeadingZeros32(rs_u);
2095
          break;
2096 2097
        default:
          UNREACHABLE();
2098
      }
2099 2100 2101 2102
      break;
    case SPECIAL3:
      switch (instr->FunctionFieldRaw()) {
        case INS: {   // Mips32r2 instruction.
2103
          // Interpret rd field as 5-bit msb of insert.
2104 2105 2106 2107 2108
          uint16_t msb = rd_reg;
          // Interpret sa field as 5-bit lsb of insert.
          uint16_t lsb = sa;
          uint16_t size = msb - lsb + 1;
          uint32_t mask = (1 << size) - 1;
2109
          *alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
2110 2111 2112
          break;
        }
        case EXT: {   // Mips32r2 instruction.
2113
          // Interpret rd field as 5-bit msb of extract.
2114 2115 2116 2117 2118
          uint16_t msb = rd_reg;
          // Interpret sa field as 5-bit lsb of extract.
          uint16_t lsb = sa;
          uint16_t size = msb + 1;
          uint32_t mask = (1 << size) - 1;
2119
          *alu_out = (rs_u & (mask << lsb)) >> lsb;
2120 2121 2122 2123
          break;
        }
        default:
          UNREACHABLE();
2124
      }
2125 2126 2127
      break;
    default:
      UNREACHABLE();
2128
  }
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
}


void Simulator::DecodeTypeRegister(Instruction* instr) {
  // Instruction fields.
  const Opcode   op     = instr->OpcodeFieldRaw();
  const int32_t  rs_reg = instr->RsValue();
  const int32_t  rs     = get_register(rs_reg);
  const uint32_t rs_u   = static_cast<uint32_t>(rs);
  const int32_t  rt_reg = instr->RtValue();
  const int32_t  rt     = get_register(rt_reg);
  const uint32_t rt_u   = static_cast<uint32_t>(rt);
  const int32_t  rd_reg = instr->RdValue();

2143
  const int32_t  fr_reg = instr->FrValue();
2144 2145 2146 2147 2148 2149
  const int32_t  fs_reg = instr->FsValue();
  const int32_t  ft_reg = instr->FtValue();
  const int32_t  fd_reg = instr->FdValue();
  int64_t  i64hilo = 0;
  uint64_t u64hilo = 0;

2150
  // ALU output.
2151 2152 2153 2154 2155 2156 2157
  // It should not be used as is. Instructions using it should always
  // initialize it first.
  int32_t alu_out = 0x12345678;

  // For break and trap instructions.
  bool do_interrupt = false;

2158
  // For jr and jalr.
2159 2160 2161 2162
  // Get current pc.
  int32_t current_pc = get_pc();
  // Next pc
  int32_t next_pc = 0;
2163
  int32_t return_addr_reg = 31;
2164

2165
  // Set up the variables if needed before executing the instruction.
2166
  ConfigureTypeRegister(instr,
2167 2168 2169 2170 2171 2172
                        &alu_out,
                        &i64hilo,
                        &u64hilo,
                        &next_pc,
                        &return_addr_reg,
                        &do_interrupt);
2173 2174 2175 2176

  // ---------- Raise exceptions triggered.
  SignalExceptions();

2177
  // ---------- Execution.
2178 2179 2180
  switch (op) {
    case COP1:
      switch (instr->RsFieldRaw()) {
2181 2182
        case CFC1:
          set_register(rt_reg, alu_out);
2183
          break;
2184 2185 2186
        case MFC1:
          set_register(rt_reg, alu_out);
          break;
2187
        case MFHC1:
2188
          set_register(rt_reg, alu_out);
2189 2190 2191
          break;
        case CTC1:
          // At the moment only FCSR is supported.
2192
          DCHECK(fs_reg == kFCSRRegister);
2193 2194
          FCSR_ = registers_[rt_reg];
          break;
2195
        case MTC1:
2196 2197 2198
          // Hardware writes upper 32-bits to zero on mtc1.
          set_fpu_register_hi_word(fs_reg, 0);
          set_fpu_register_word(fs_reg, registers_[rt_reg]);
2199 2200
          break;
        case MTHC1:
2201
          set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
2202 2203
          break;
        case S:
2204
          float f;
2205 2206
          switch (instr->FunctionFieldRaw()) {
            case CVT_D_S:
2207 2208 2209
              f = get_fpu_register_float(fs_reg);
              set_fpu_register_double(fd_reg, static_cast<double>(f));
              break;
2210
            default:
2211 2212
            // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
            // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
2213 2214 2215 2216
              UNREACHABLE();
          }
          break;
        case D:
2217 2218 2219 2220 2221 2222 2223
          double ft, fs;
          uint32_t cc, fcsr_cc;
          int64_t  i64;
          fs = get_fpu_register_double(fs_reg);
          ft = get_fpu_register_double(ft_reg);
          cc = instr->FCccValue();
          fcsr_cc = get_fcsr_condition_bit(cc);
2224
          switch (instr->FunctionFieldRaw()) {
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
            case ADD_D:
              set_fpu_register_double(fd_reg, fs + ft);
              break;
            case SUB_D:
              set_fpu_register_double(fd_reg, fs - ft);
              break;
            case MUL_D:
              set_fpu_register_double(fd_reg, fs * ft);
              break;
            case DIV_D:
              set_fpu_register_double(fd_reg, fs / ft);
              break;
            case ABS_D:
2238
              set_fpu_register_double(fd_reg, fabs(fs));
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
              break;
            case MOV_D:
              set_fpu_register_double(fd_reg, fs);
              break;
            case NEG_D:
              set_fpu_register_double(fd_reg, -fs);
              break;
            case SQRT_D:
              set_fpu_register_double(fd_reg, sqrt(fs));
              break;
            case C_UN_D:
2250
              set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2251 2252 2253 2254 2255
              break;
            case C_EQ_D:
              set_fcsr_bit(fcsr_cc, (fs == ft));
              break;
            case C_UEQ_D:
2256 2257
              set_fcsr_bit(fcsr_cc,
                           (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2258 2259 2260 2261 2262
              break;
            case C_OLT_D:
              set_fcsr_bit(fcsr_cc, (fs < ft));
              break;
            case C_ULT_D:
2263 2264
              set_fcsr_bit(fcsr_cc,
                           (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2265 2266 2267 2268 2269
              break;
            case C_OLE_D:
              set_fcsr_bit(fcsr_cc, (fs <= ft));
              break;
            case C_ULE_D:
2270 2271
              set_fcsr_bit(fcsr_cc,
                           (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2272 2273 2274
              break;
            case CVT_W_D:   // Convert double to word.
              // Rounding modes are not yet supported.
2275
              DCHECK((FCSR_ & 3) == 0);
2276
              // In rounding mode 0 it should behave like ROUND.
2277
            case ROUND_W_D:  // Round double to word (round half to even).
2278
              {
2279
                double rounded = std::floor(fs + 0.5);
2280
                int32_t result = static_cast<int32_t>(rounded);
2281 2282 2283 2284 2285
                if ((result & 1) != 0 && result - fs == 0.5) {
                  // If the number is halfway between two integers,
                  // round to the even one.
                  result--;
                }
2286
                set_fpu_register_word(fd_reg, result);
2287
                if (set_fcsr_round_error(fs, rounded)) {
2288
                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
2289 2290 2291 2292 2293
                }
              }
              break;
            case TRUNC_W_D:  // Truncate double to word (round towards 0).
              {
2294 2295
                double rounded = trunc(fs);
                int32_t result = static_cast<int32_t>(rounded);
2296
                set_fpu_register_word(fd_reg, result);
2297
                if (set_fcsr_round_error(fs, rounded)) {
2298
                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
2299 2300 2301 2302 2303
                }
              }
              break;
            case FLOOR_W_D:  // Round double to word towards negative infinity.
              {
2304
                double rounded = std::floor(fs);
2305
                int32_t result = static_cast<int32_t>(rounded);
2306
                set_fpu_register_word(fd_reg, result);
2307
                if (set_fcsr_round_error(fs, rounded)) {
2308
                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
2309 2310 2311
                }
              }
              break;
2312
            case CEIL_W_D:  // Round double to word towards positive infinity.
2313
              {
2314
                double rounded = std::ceil(fs);
2315
                int32_t result = static_cast<int32_t>(rounded);
2316
                set_fpu_register_word(fd_reg, result);
2317
                if (set_fcsr_round_error(fs, rounded)) {
2318
                  set_fpu_register_word(fd_reg, kFPUInvalidResult);
2319 2320 2321 2322 2323 2324
                }
              }
              break;
            case CVT_S_D:  // Convert double to float (single).
              set_fpu_register_float(fd_reg, static_cast<float>(fs));
              break;
2325 2326 2327
            case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
              double rounded = trunc(fs);
              i64 = static_cast<int64_t>(rounded);
2328 2329 2330 2331 2332 2333
              if (IsFp64Mode()) {
                set_fpu_register(fd_reg, i64);
              } else {
                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
                set_fpu_register_word(fd_reg + 1, i64 >> 32);
              }
2334
              break;
2335 2336 2337 2338
            }
            case TRUNC_L_D: {  // Mips32r2 instruction.
              double rounded = trunc(fs);
              i64 = static_cast<int64_t>(rounded);
2339 2340 2341 2342 2343 2344
              if (IsFp64Mode()) {
                set_fpu_register(fd_reg, i64);
              } else {
                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
                set_fpu_register_word(fd_reg + 1, i64 >> 32);
              }
2345
              break;
2346
            }
2347
            case ROUND_L_D: {  // Mips32r2 instruction.
2348 2349
              double rounded =
                  fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
2350
              i64 = static_cast<int64_t>(rounded);
2351 2352 2353 2354 2355 2356
              if (IsFp64Mode()) {
                set_fpu_register(fd_reg, i64);
              } else {
                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
                set_fpu_register_word(fd_reg + 1, i64 >> 32);
              }
2357 2358 2359
              break;
            }
            case FLOOR_L_D:  // Mips32r2 instruction.
2360
              i64 = static_cast<int64_t>(std::floor(fs));
2361 2362 2363 2364 2365 2366
              if (IsFp64Mode()) {
                set_fpu_register(fd_reg, i64);
              } else {
                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
                set_fpu_register_word(fd_reg + 1, i64 >> 32);
              }
2367 2368
              break;
            case CEIL_L_D:  // Mips32r2 instruction.
2369
              i64 = static_cast<int64_t>(std::ceil(fs));
2370 2371 2372 2373 2374 2375
              if (IsFp64Mode()) {
                set_fpu_register(fd_reg, i64);
              } else {
                set_fpu_register_word(fd_reg, i64 & 0xffffffff);
                set_fpu_register_word(fd_reg + 1, i64 >> 32);
              }
2376 2377
              break;
            case C_F_D:
2378 2379 2380 2381 2382 2383 2384 2385
              UNIMPLEMENTED_MIPS();
              break;
            default:
              UNREACHABLE();
          }
          break;
        case W:
          switch (instr->FunctionFieldRaw()) {
2386
            case CVT_S_W:   // Convert word to float (single).
2387
              alu_out = get_fpu_register_signed_word(fs_reg);
2388
              set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
2389 2390
              break;
            case CVT_D_W:   // Convert word to double.
2391
              alu_out = get_fpu_register_signed_word(fs_reg);
2392
              set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
2393
              break;
2394
            default:  // Mips64r6 CMP.S instructions unimplemented.
2395
              UNREACHABLE();
2396
          }
2397 2398
          break;
        case L:
2399 2400
          fs = get_fpu_register_double(fs_reg);
          ft = get_fpu_register_double(ft_reg);
2401
          switch (instr->FunctionFieldRaw()) {
2402 2403 2404
          case CVT_D_L:  // Mips32r2 instruction.
            // Watch the signs here, we want 2 32-bit vals
            // to make a sign-64.
2405 2406 2407 2408 2409 2410 2411
            if (IsFp64Mode()) {
              i64 = get_fpu_register(fs_reg);
            } else {
              i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg));
              i64 |= static_cast<int64_t>(
                  get_fpu_register_word(fs_reg + 1)) << 32;
            }
2412 2413
            set_fpu_register_double(fd_reg, static_cast<double>(i64));
            break;
2414 2415 2416
            case CVT_S_L:
              UNIMPLEMENTED_MIPS();
              break;
2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
            case CMP_AF:  // Mips64r6 CMP.D instructions.
              UNIMPLEMENTED_MIPS();
              break;
            case CMP_UN:
              if (std::isnan(fs) || std::isnan(ft)) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_EQ:
              if (fs == ft) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_UEQ:
              if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_LT:
              if (fs < ft) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_ULT:
              if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_LE:
              if (fs <= ft) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            case CMP_ULE:
              if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
                set_fpu_register(fd_reg, -1);
              } else {
                set_fpu_register(fd_reg, 0);
              }
              break;
            default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
2470 2471 2472 2473 2474
              UNREACHABLE();
          }
          break;
        default:
          UNREACHABLE();
2475
      }
2476
      break;
2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
    case COP1X:
      switch (instr->FunctionFieldRaw()) {
        case MADD_D:
          double fr, ft, fs;
          fr = get_fpu_register_double(fr_reg);
          fs = get_fpu_register_double(fs_reg);
          ft = get_fpu_register_double(ft_reg);
          set_fpu_register_double(fd_reg, fs * ft + fr);
          break;
        default:
          UNREACHABLE();
2488
      }
2489
      break;
2490 2491 2492 2493
    case SPECIAL:
      switch (instr->FunctionFieldRaw()) {
        case JR: {
          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
2494
              current_pc+Instruction::kInstrSize);
2495 2496 2497 2498 2499 2500 2501
          BranchDelayInstructionDecode(branch_delay_instr);
          set_pc(next_pc);
          pc_modified_ = true;
          break;
        }
        case JALR: {
          Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
2502
              current_pc+Instruction::kInstrSize);
2503
          BranchDelayInstructionDecode(branch_delay_instr);
2504 2505
          set_register(return_addr_reg,
                       current_pc + 2 * Instruction::kInstrSize);
2506 2507 2508 2509 2510 2511
          set_pc(next_pc);
          pc_modified_ = true;
          break;
        }
        // Instructions using HI and LO registers.
        case MULT:
2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
          if (!IsMipsArchVariant(kMips32r6)) {
            set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
            set_register(HI, static_cast<int32_t>(i64hilo >> 32));
          } else {
            switch (instr->SaValue()) {
              case MUL_OP:
                set_register(rd_reg,
                    static_cast<int32_t>(i64hilo & 0xffffffff));
                break;
              case MUH_OP:
                set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32));
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
            }
          }
2529
          break;
2530
        case MULTU:
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
          if (!IsMipsArchVariant(kMips32r6)) {
            set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
            set_register(HI, static_cast<int32_t>(u64hilo >> 32));
          } else {
            switch (instr->SaValue()) {
              case MUL_OP:
                set_register(rd_reg,
                    static_cast<int32_t>(u64hilo & 0xffffffff));
                break;
              case MUH_OP:
                set_register(rd_reg, static_cast<int32_t>(u64hilo >> 32));
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
            }
          }
2548 2549
          break;
        case DIV:
2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
          if (IsMipsArchVariant(kMips32r6)) {
            switch (instr->SaValue()) {
              case DIV_OP:
                if (rs == INT_MIN && rt == -1) {
                  set_register(rd_reg, INT_MIN);
                } else if (rt != 0) {
                  set_register(rd_reg, rs / rt);
                }
                break;
              case MOD_OP:
                if (rs == INT_MIN && rt == -1) {
                  set_register(rd_reg, 0);
                } else if (rt != 0) {
                  set_register(rd_reg, rs % rt);
                }
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
            }
          } else {
            // Divide by zero and overflow was not checked in the
            // configuration step - div and divu do not raise exceptions. On
            // division by 0 the result will be UNPREDICTABLE. On overflow
            // (INT_MIN/-1), return INT_MIN which is what the hardware does.
            if (rs == INT_MIN && rt == -1) {
              set_register(LO, INT_MIN);
              set_register(HI, 0);
            } else if (rt != 0) {
              set_register(LO, rs / rt);
              set_register(HI, rs % rt);
            }
2582
          }
2583 2584
          break;
        case DIVU:
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605
          if (IsMipsArchVariant(kMips32r6)) {
            switch (instr->SaValue()) {
              case DIV_OP:
                if (rt_u != 0) {
                  set_register(rd_reg, rs_u / rt_u);
                }
                break;
              case MOD_OP:
                if (rt_u != 0) {
                  set_register(rd_reg, rs_u % rt_u);
                }
                break;
              default:
                UNIMPLEMENTED_MIPS();
                break;
              }
          } else {
            if (rt_u != 0) {
              set_register(LO, rs_u / rt_u);
              set_register(HI, rs_u % rt_u);
            }
2606
          }
2607
          break;
2608
        // Break and trap instructions.
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
        case BREAK:
        case TGE:
        case TGEU:
        case TLT:
        case TLTU:
        case TEQ:
        case TNE:
          if (do_interrupt) {
            SoftwareInterrupt(instr);
          }
          break;
2620 2621 2622 2623 2624
        // Conditional moves.
        case MOVN:
          if (rt) set_register(rd_reg, rs);
          break;
        case MOVCI: {
2625
          uint32_t cc = instr->FBccValue();
2626
          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
2627
          if (instr->Bit(16)) {  // Read Tf bit.
2628 2629 2630 2631 2632 2633 2634 2635 2636
            if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
          } else {
            if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
          }
          break;
        }
        case MOVZ:
          if (!rt) set_register(rd_reg, rs);
          break;
2637 2638
        default:  // For other special opcodes we do the default operation.
          set_register(rd_reg, alu_out);
2639
      }
2640 2641 2642 2643 2644 2645 2646 2647 2648
      break;
    case SPECIAL2:
      switch (instr->FunctionFieldRaw()) {
        case MUL:
          set_register(rd_reg, alu_out);
          // HI and LO are UNPREDICTABLE after the operation.
          set_register(LO, Unpredictable);
          set_register(HI, Unpredictable);
          break;
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662
        default:  // For other special2 opcodes we do the default operation.
          set_register(rd_reg, alu_out);
      }
      break;
    case SPECIAL3:
      switch (instr->FunctionFieldRaw()) {
        case INS:
          // Ins instr leaves result in Rt, rather than Rd.
          set_register(rt_reg, alu_out);
          break;
        case EXT:
          // Ext instr leaves result in Rt, rather than Rd.
          set_register(rt_reg, alu_out);
          break;
2663 2664
        default:
          UNREACHABLE();
2665
      }
2666 2667 2668 2669 2670 2671
      break;
    // Unimplemented opcodes raised an error in the configuration step before,
    // so we can use the default here to set the destination register in common
    // cases.
    default:
      set_register(rd_reg, alu_out);
2672
  }
2673 2674
}

2675

2676
// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
2677
void Simulator::DecodeTypeImmediate(Instruction* instr) {
2678
  // Instruction fields.
2679
  Opcode   op     = instr->OpcodeFieldRaw();
2680
  int32_t  rs     = get_register(instr->RsValue());
2681
  uint32_t rs_u   = static_cast<uint32_t>(rs);
2682
  int32_t  rt_reg = instr->RtValue();  // Destination register.
2683
  int32_t  rt     = get_register(rt_reg);
2684
  int16_t  imm16  = instr->Imm16Value();
2685

2686
  int32_t  ft_reg = instr->FtValue();  // Destination register.
2687
  int64_t  ft;
2688

2689
  // Zero extended immediate.
2690
  uint32_t  oe_imm16 = 0xffff & imm16;
2691
  // Sign extended immediate.
2692 2693 2694 2695 2696 2697 2698
  int32_t   se_imm16 = imm16;

  // Get current pc.
  int32_t current_pc = get_pc();
  // Next pc.
  int32_t next_pc = bad_ra;

2699
  // Used for conditional branch instructions.
2700 2701 2702
  bool do_branch = false;
  bool execute_branch_delay_instruction = false;

2703
  // Used for arithmetic instructions.
2704
  int32_t alu_out = 0;
2705
  // Floating point.
2706
  double fp_out = 0.0;
2707
  uint32_t cc, cc_value, fcsr_cc;
2708

2709
  // Used for memory instructions.
2710
  int32_t addr = 0x0;
2711
  // Value to be written in memory.
2712
  uint32_t mem_value = 0x0;
2713

2714
  // ---------- Configuration (and execution for REGIMM).
2715
  switch (op) {
2716
    // ------------- COP1. Coprocessor instructions.
2717 2718
    case COP1:
      switch (instr->RsFieldRaw()) {
2719 2720 2721 2722 2723 2724
        case BC1:   // Branch on coprocessor condition.
          cc = instr->FBccValue();
          fcsr_cc = get_fcsr_condition_bit(cc);
          cc_value = test_fcsr_bit(fcsr_cc);
          do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
          execute_branch_delay_instruction = true;
2725
          // Set next_pc.
2726 2727 2728 2729 2730
          if (do_branch) {
            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
          } else {
            next_pc = current_pc + kBranchReturnOffset;
          }
2731
          break;
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753
        case BC1EQZ:
          ft = get_fpu_register(ft_reg);
          do_branch = (ft & 0x1) ? false : true;
          execute_branch_delay_instruction = true;
          // Set next_pc.
          if (do_branch) {
            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
          } else {
            next_pc = current_pc + kBranchReturnOffset;
          }
          break;
        case BC1NEZ:
          ft = get_fpu_register(ft_reg);
          do_branch = (ft & 0x1) ? true : false;
          execute_branch_delay_instruction = true;
          // Set next_pc.
          if (do_branch) {
            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
          } else {
            next_pc = current_pc + kBranchReturnOffset;
          }
          break;
2754 2755
        default:
          UNREACHABLE();
2756
      }
2757
      break;
2758
    // ------------- REGIMM class.
2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774
    case REGIMM:
      switch (instr->RtFieldRaw()) {
        case BLTZ:
          do_branch = (rs  < 0);
          break;
        case BLTZAL:
          do_branch = rs  < 0;
          break;
        case BGEZ:
          do_branch = rs >= 0;
          break;
        case BGEZAL:
          do_branch = rs >= 0;
          break;
        default:
          UNREACHABLE();
2775
      }
2776 2777 2778 2779 2780 2781 2782
      switch (instr->RtFieldRaw()) {
        case BLTZ:
        case BLTZAL:
        case BGEZ:
        case BGEZAL:
          // Branch instructions common part.
          execute_branch_delay_instruction = true;
2783
          // Set next_pc.
2784
          if (do_branch) {
2785
            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2786 2787 2788 2789 2790 2791 2792 2793
            if (instr->IsLinkingInstruction()) {
              set_register(31, current_pc + kBranchReturnOffset);
            }
          } else {
            next_pc = current_pc + kBranchReturnOffset;
          }
        default:
          break;
2794
        }
2795 2796
    break;  // case REGIMM.
    // ------------- Branch instructions.
2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
    // When comparing to zero, the encoding of rt field is always 0, so we don't
    // need to replace rt with zero.
    case BEQ:
      do_branch = (rs == rt);
      break;
    case BNE:
      do_branch = rs != rt;
      break;
    case BLEZ:
      do_branch = rs <= 0;
      break;
    case BGTZ:
      do_branch = rs  > 0;
      break;
2811
    // ------------- Arithmetic instructions.
2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843
    case ADDI:
      if (HaveSameSign(rs, se_imm16)) {
        if (rs > 0) {
          exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
        } else if (rs < 0) {
          exceptions[kIntegerUnderflow] =
              rs < (Registers::kMinValue - se_imm16);
        }
      }
      alu_out = rs + se_imm16;
      break;
    case ADDIU:
      alu_out = rs + se_imm16;
      break;
    case SLTI:
      alu_out = (rs < se_imm16) ? 1 : 0;
      break;
    case SLTIU:
      alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
      break;
    case ANDI:
        alu_out = rs & oe_imm16;
      break;
    case ORI:
        alu_out = rs | oe_imm16;
      break;
    case XORI:
        alu_out = rs ^ oe_imm16;
      break;
    case LUI:
        alu_out = (oe_imm16 << 16);
      break;
2844
    // ------------- Memory instructions.
2845 2846 2847 2848
    case LB:
      addr = rs + se_imm16;
      alu_out = ReadB(addr);
      break;
2849 2850 2851 2852 2853
    case LH:
      addr = rs + se_imm16;
      alu_out = ReadH(addr, instr);
      break;
    case LWL: {
2854
      // al_offset is offset of the effective address within an aligned word.
2855 2856 2857 2858 2859 2860 2861 2862 2863
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = (1 << byte_shift * 8) - 1;
      addr = rs + se_imm16 - al_offset;
      alu_out = ReadW(addr, instr);
      alu_out <<= byte_shift * 8;
      alu_out |= rt & mask;
      break;
    }
2864 2865 2866 2867 2868 2869 2870 2871
    case LW:
      addr = rs + se_imm16;
      alu_out = ReadW(addr, instr);
      break;
    case LBU:
      addr = rs + se_imm16;
      alu_out = ReadBU(addr);
      break;
2872 2873 2874 2875 2876
    case LHU:
      addr = rs + se_imm16;
      alu_out = ReadHU(addr, instr);
      break;
    case LWR: {
2877
      // al_offset is offset of the effective address within an aligned word.
2878 2879 2880 2881 2882 2883 2884 2885 2886
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
      addr = rs + se_imm16 - al_offset;
      alu_out = ReadW(addr, instr);
      alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
      alu_out |= rt & mask;
      break;
    }
2887 2888 2889
    case SB:
      addr = rs + se_imm16;
      break;
2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
    case SH:
      addr = rs + se_imm16;
      break;
    case SWL: {
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
      addr = rs + se_imm16 - al_offset;
      mem_value = ReadW(addr, instr) & mask;
      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
      break;
    }
2902 2903 2904
    case SW:
      addr = rs + se_imm16;
      break;
2905 2906 2907 2908 2909 2910 2911 2912
    case SWR: {
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint32_t mask = (1 << al_offset * 8) - 1;
      addr = rs + se_imm16 - al_offset;
      mem_value = ReadW(addr, instr);
      mem_value = (rt << al_offset * 8) | (mem_value & mask);
      break;
    }
2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
    case LWC1:
      addr = rs + se_imm16;
      alu_out = ReadW(addr, instr);
      break;
    case LDC1:
      addr = rs + se_imm16;
      fp_out = ReadD(addr, instr);
      break;
    case SWC1:
    case SDC1:
      addr = rs + se_imm16;
      break;
    default:
      UNREACHABLE();
2927
  }
2928 2929 2930 2931

  // ---------- Raise exceptions triggered.
  SignalExceptions();

2932
  // ---------- Execution.
2933
  switch (op) {
2934
    // ------------- Branch instructions.
2935 2936 2937 2938 2939 2940
    case BEQ:
    case BNE:
    case BLEZ:
    case BGTZ:
      // Branch instructions common part.
      execute_branch_delay_instruction = true;
2941
      // Set next_pc.
2942
      if (do_branch) {
2943
        next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2944
        if (instr->IsLinkingInstruction()) {
2945
          set_register(31, current_pc + 2* Instruction::kInstrSize);
2946 2947
        }
      } else {
2948
        next_pc = current_pc + 2 * Instruction::kInstrSize;
2949 2950
      }
      break;
2951
    // ------------- Arithmetic instructions.
2952 2953 2954 2955 2956 2957 2958 2959 2960 2961
    case ADDI:
    case ADDIU:
    case SLTI:
    case SLTIU:
    case ANDI:
    case ORI:
    case XORI:
    case LUI:
      set_register(rt_reg, alu_out);
      break;
2962
    // ------------- Memory instructions.
2963
    case LB:
2964 2965
    case LH:
    case LWL:
2966 2967
    case LW:
    case LBU:
2968 2969
    case LHU:
    case LWR:
2970 2971 2972 2973 2974
      set_register(rt_reg, alu_out);
      break;
    case SB:
      WriteB(addr, static_cast<int8_t>(rt));
      break;
2975 2976 2977 2978 2979 2980
    case SH:
      WriteH(addr, static_cast<uint16_t>(rt), instr);
      break;
    case SWL:
      WriteW(addr, mem_value, instr);
      break;
2981 2982 2983
    case SW:
      WriteW(addr, rt, instr);
      break;
2984 2985 2986
    case SWR:
      WriteW(addr, mem_value, instr);
      break;
2987
    case LWC1:
2988 2989
      set_fpu_register_hi_word(ft_reg, 0);
      set_fpu_register_word(ft_reg, alu_out);
2990 2991 2992 2993 2994 2995
      break;
    case LDC1:
      set_fpu_register_double(ft_reg, fp_out);
      break;
    case SWC1:
      addr = rs + se_imm16;
2996
      WriteW(addr, get_fpu_register_word(ft_reg), instr);
2997 2998 2999
      break;
    case SDC1:
      addr = rs + se_imm16;
3000
      WriteD(addr, get_fpu_register_double(ft_reg), instr);
3001 3002 3003
      break;
    default:
      break;
3004
  }
3005 3006 3007 3008 3009 3010 3011


  if (execute_branch_delay_instruction) {
    // Execute branch delay slot
    // We don't check for end_sim_pc. First it should not be met as the current
    // pc is valid. Secondly a jump should always execute its branch delay slot.
    Instruction* branch_delay_instr =
3012
      reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
3013 3014 3015 3016 3017 3018 3019 3020 3021
    BranchDelayInstructionDecode(branch_delay_instr);
  }

  // If needed update pc after the branch delay execution.
  if (next_pc != bad_ra) {
    set_pc(next_pc);
  }
}

3022

3023
// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
3024 3025 3026 3027 3028
void Simulator::DecodeTypeJump(Instruction* instr) {
  // Get current pc.
  int32_t current_pc = get_pc();
  // Get unchanged bits of pc.
  int32_t pc_high_bits = current_pc & 0xf0000000;
3029
  // Next pc.
3030
  int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
3031

3032
  // Execute branch delay slot.
3033 3034 3035
  // We don't check for end_sim_pc. First it should not be met as the current pc
  // is valid. Secondly a jump should always execute its branch delay slot.
  Instruction* branch_delay_instr =
3036
      reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3037 3038 3039 3040 3041
  BranchDelayInstructionDecode(branch_delay_instr);

  // Update pc and ra if necessary.
  // Do this after the branch delay execution.
  if (instr->IsLinkingInstruction()) {
3042
    set_register(31, current_pc + 2 * Instruction::kInstrSize);
3043 3044 3045 3046 3047
  }
  set_pc(next_pc);
  pc_modified_ = true;
}

3048

3049 3050
// Executes the current instruction.
void Simulator::InstructionDecode(Instruction* instr) {
3051 3052 3053
  if (v8::internal::FLAG_check_icache) {
    CheckICache(isolate_->simulator_i_cache(), instr);
  }
3054 3055 3056 3057
  pc_modified_ = false;
  if (::v8::internal::FLAG_trace_sim) {
    disasm::NameConverter converter;
    disasm::Disassembler dasm(converter);
3058
    // Use a reasonably large buffer.
3059
    v8::internal::EmbeddedVector<char, 256> buffer;
3060
    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
3061
    PrintF("  0x%08x  %s\n", reinterpret_cast<intptr_t>(instr),
3062
        buffer.start());
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079
  }

  switch (instr->InstructionType()) {
    case Instruction::kRegisterType:
      DecodeTypeRegister(instr);
      break;
    case Instruction::kImmediateType:
      DecodeTypeImmediate(instr);
      break;
    case Instruction::kJumpType:
      DecodeTypeJump(instr);
      break;
    default:
      UNSUPPORTED();
  }
  if (!pc_modified_) {
    set_register(pc, reinterpret_cast<int32_t>(instr) +
3080
                 Instruction::kInstrSize);
3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105
  }
}



void Simulator::Execute() {
  // Get the PC to simulate. Cannot use the accessor here as we need the
  // raw PC value and not the one used as input to arithmetic instructions.
  int program_counter = get_pc();
  if (::v8::internal::FLAG_stop_sim_at == 0) {
    // Fast version of the dispatch loop without checking whether the simulator
    // should be stopping at a particular executed instruction.
    while (program_counter != end_sim_pc) {
      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
      icount_++;
      InstructionDecode(instr);
      program_counter = get_pc();
    }
  } else {
    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
    // we reach the particular instuction count.
    while (program_counter != end_sim_pc) {
      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
      icount_++;
      if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
3106
        MipsDebugger dbg(this);
3107 3108 3109 3110 3111 3112 3113 3114 3115 3116
        dbg.Debug();
      } else {
        InstructionDecode(instr);
      }
      program_counter = get_pc();
    }
  }
}


3117
void Simulator::CallInternal(byte* entry) {
3118
  // Prepare to execute the code at entry.
3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
  set_register(pc, reinterpret_cast<int32_t>(entry));
  // Put down marker for end of simulation. The simulator will stop simulation
  // when the PC reaches this value. By saving the "end simulation" value into
  // the LR the simulation stops when returning to this call point.
  set_register(ra, end_sim_pc);

  // Remember the values of callee-saved registers.
  // The code below assumes that r9 is not used as sb (static base) in
  // simulator code and therefore is regarded as a callee-saved register.
  int32_t s0_val = get_register(s0);
  int32_t s1_val = get_register(s1);
  int32_t s2_val = get_register(s2);
  int32_t s3_val = get_register(s3);
  int32_t s4_val = get_register(s4);
  int32_t s5_val = get_register(s5);
  int32_t s6_val = get_register(s6);
  int32_t s7_val = get_register(s7);
  int32_t gp_val = get_register(gp);
  int32_t sp_val = get_register(sp);
  int32_t fp_val = get_register(fp);

3140
  // Set up the callee-saved registers with a known value. To be able to check
3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
  // that they are preserved properly across JS execution.
  int32_t callee_saved_value = icount_;
  set_register(s0, callee_saved_value);
  set_register(s1, callee_saved_value);
  set_register(s2, callee_saved_value);
  set_register(s3, callee_saved_value);
  set_register(s4, callee_saved_value);
  set_register(s5, callee_saved_value);
  set_register(s6, callee_saved_value);
  set_register(s7, callee_saved_value);
  set_register(gp, callee_saved_value);
  set_register(fp, callee_saved_value);

3154
  // Start the simulation.
3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180
  Execute();

  // Check that the callee-saved registers have been preserved.
  CHECK_EQ(callee_saved_value, get_register(s0));
  CHECK_EQ(callee_saved_value, get_register(s1));
  CHECK_EQ(callee_saved_value, get_register(s2));
  CHECK_EQ(callee_saved_value, get_register(s3));
  CHECK_EQ(callee_saved_value, get_register(s4));
  CHECK_EQ(callee_saved_value, get_register(s5));
  CHECK_EQ(callee_saved_value, get_register(s6));
  CHECK_EQ(callee_saved_value, get_register(s7));
  CHECK_EQ(callee_saved_value, get_register(gp));
  CHECK_EQ(callee_saved_value, get_register(fp));

  // Restore callee-saved registers with the original value.
  set_register(s0, s0_val);
  set_register(s1, s1_val);
  set_register(s2, s2_val);
  set_register(s3, s3_val);
  set_register(s4, s4_val);
  set_register(s5, s5_val);
  set_register(s6, s6_val);
  set_register(s7, s7_val);
  set_register(gp, gp_val);
  set_register(sp, sp_val);
  set_register(fp, fp_val);
3181 3182 3183 3184 3185 3186 3187 3188 3189
}


int32_t Simulator::Call(byte* entry, int argument_count, ...) {
  va_list parameters;
  va_start(parameters, argument_count);
  // Set up arguments.

  // First four arguments passed in registers.
3190
  DCHECK(argument_count >= 4);
3191 3192 3193 3194 3195 3196 3197 3198 3199 3200
  set_register(a0, va_arg(parameters, int32_t));
  set_register(a1, va_arg(parameters, int32_t));
  set_register(a2, va_arg(parameters, int32_t));
  set_register(a3, va_arg(parameters, int32_t));

  // Remaining arguments passed on stack.
  int original_stack = get_register(sp);
  // Compute position of stack on entry to generated code.
  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
                                    - kCArgsSlotsSize);
3201 3202
  if (base::OS::ActivationFrameAlignment() != 0) {
    entry_stack &= -base::OS::ActivationFrameAlignment();
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212
  }
  // Store remaining arguments on stack, from low to high memory.
  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
  for (int i = 4; i < argument_count; i++) {
    stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
  }
  va_end(parameters);
  set_register(sp, entry_stack);

  CallInternal(entry);
3213 3214 3215 3216 3217 3218 3219 3220 3221 3222

  // Pop stack passed arguments.
  CHECK_EQ(entry_stack, get_register(sp));
  set_register(sp, original_stack);

  int32_t result = get_register(v0);
  return result;
}


3223 3224 3225 3226 3227 3228
double Simulator::CallFP(byte* entry, double d0, double d1) {
  if (!IsMipsSoftFloatABI) {
    set_fpu_register_double(f12, d0);
    set_fpu_register_double(f14, d1);
  } else {
    int buffer[2];
3229
    DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
3230
    memcpy(buffer, &d0, sizeof(d0));
3231
    set_dw_register(a0, buffer);
3232
    memcpy(buffer, &d1, sizeof(d1));
3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243
    set_dw_register(a2, buffer);
  }
  CallInternal(entry);
  if (!IsMipsSoftFloatABI) {
    return get_fpu_register_double(f0);
  } else {
    return get_double_from_register_pair(v0);
  }
}


3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
uintptr_t Simulator::PushAddress(uintptr_t address) {
  int new_sp = get_register(sp) - sizeof(uintptr_t);
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
  *stack_slot = address;
  set_register(sp, new_sp);
  return new_sp;
}


uintptr_t Simulator::PopAddress() {
  int current_sp = get_register(sp);
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
  uintptr_t address = *stack_slot;
  set_register(sp, current_sp + sizeof(uintptr_t));
  return address;
}


#undef UNSUPPORTED

3264
} }  // namespace v8::internal
3265

3266
#endif  // USE_SIMULATOR
3267

3268
#endif  // V8_TARGET_ARCH_MIPS