1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <cmath>
9
10#if V8_TARGET_ARCH_MIPS
11
12#include "src/assembler.h"
13#include "src/base/bits.h"
14#include "src/codegen.h"
15#include "src/disasm.h"
16#include "src/mips/constants-mips.h"
17#include "src/mips/simulator-mips.h"
18#include "src/ostreams.h"
19#include "src/runtime/runtime-utils.h"
20
21
22// Only build the simulator if not compiling for real MIPS hardware.
23#if defined(USE_SIMULATOR)
24
25namespace v8 {
26namespace internal {
27
28// Utils functions.
29bool HaveSameSign(int32_t a, int32_t b) {
30  return ((a ^ b) >= 0);
31}
32
33
34uint32_t get_fcsr_condition_bit(uint32_t cc) {
35  if (cc == 0) {
36    return 23;
37  } else {
38    return 24 + cc;
39  }
40}
41
42
43// This macro provides a platform independent use of sscanf. The reason for
44// SScanF not being implemented in a platform independent was through
45// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
46// Library does not provide vsscanf.
47#define SScanF sscanf  // NOLINT
48
49// The MipsDebugger class is used by the simulator while debugging simulated
50// code.
51class MipsDebugger {
52 public:
53  explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
54
55  void Stop(Instruction* instr);
56  void Debug();
57  // Print all registers with a nice formatting.
58  void PrintAllRegs();
59  void PrintAllRegsIncludingFPU();
60
61 private:
62  // We set the breakpoint code to 0xfffff to easily recognize it.
63  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
64  static const Instr kNopInstr =  0x0;
65
66  Simulator* sim_;
67
68  int32_t GetRegisterValue(int regnum);
69  int32_t GetFPURegisterValue32(int regnum);
70  int64_t GetFPURegisterValue64(int regnum);
71  float GetFPURegisterValueFloat(int regnum);
72  double GetFPURegisterValueDouble(int regnum);
73  bool GetValue(const char* desc, int32_t* value);
74  bool GetValue(const char* desc, int64_t* value);
75
76  // Set or delete a breakpoint. Returns true if successful.
77  bool SetBreakpoint(Instruction* breakpc);
78  bool DeleteBreakpoint(Instruction* breakpc);
79
80  // Undo and redo all breakpoints. This is needed to bracket disassembly and
81  // execution to skip past breakpoints when run from the debugger.
82  void UndoBreakpoints();
83  void RedoBreakpoints();
84};
85
86
87#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
88
89
90void MipsDebugger::Stop(Instruction* instr) {
91  // Get the stop code.
92  uint32_t code = instr->Bits(25, 6);
93  PrintF("Simulator hit (%u)\n", code);
94  sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
95  Debug();
96}
97
98
99int32_t MipsDebugger::GetRegisterValue(int regnum) {
100  if (regnum == kNumSimuRegisters) {
101    return sim_->get_pc();
102  } else {
103    return sim_->get_register(regnum);
104  }
105}
106
107
108int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
109  if (regnum == kNumFPURegisters) {
110    return sim_->get_pc();
111  } else {
112    return sim_->get_fpu_register_word(regnum);
113  }
114}
115
116
117int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
118  if (regnum == kNumFPURegisters) {
119    return sim_->get_pc();
120  } else {
121    return sim_->get_fpu_register(regnum);
122  }
123}
124
125
126float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
127  if (regnum == kNumFPURegisters) {
128    return sim_->get_pc();
129  } else {
130    return sim_->get_fpu_register_float(regnum);
131  }
132}
133
134
135double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
136  if (regnum == kNumFPURegisters) {
137    return sim_->get_pc();
138  } else {
139    return sim_->get_fpu_register_double(regnum);
140  }
141}
142
143
144bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
145  int regnum = Registers::Number(desc);
146  int fpuregnum = FPURegisters::Number(desc);
147
148  if (regnum != kInvalidRegister) {
149    *value = GetRegisterValue(regnum);
150    return true;
151  } else if (fpuregnum != kInvalidFPURegister) {
152    *value = GetFPURegisterValue32(fpuregnum);
153    return true;
154  } else if (strncmp(desc, "0x", 2) == 0) {
155    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
156  } else {
157    return SScanF(desc, "%i", value) == 1;
158  }
159  return false;
160}
161
162
163bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
164  int regnum = Registers::Number(desc);
165  int fpuregnum = FPURegisters::Number(desc);
166
167  if (regnum != kInvalidRegister) {
168    *value = GetRegisterValue(regnum);
169    return true;
170  } else if (fpuregnum != kInvalidFPURegister) {
171    *value = GetFPURegisterValue64(fpuregnum);
172    return true;
173  } else if (strncmp(desc, "0x", 2) == 0) {
174    return SScanF(desc + 2, "%" SCNx64,
175                  reinterpret_cast<uint64_t*>(value)) == 1;
176  } else {
177    return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
178  }
179  return false;
180}
181
182
183bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
184  // Check if a breakpoint can be set. If not return without any side-effects.
185  if (sim_->break_pc_ != NULL) {
186    return false;
187  }
188
189  // Set the breakpoint.
190  sim_->break_pc_ = breakpc;
191  sim_->break_instr_ = breakpc->InstructionBits();
192  // Not setting the breakpoint instruction in the code itself. It will be set
193  // when the debugger shell continues.
194  return true;
195}
196
197
198bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
199  if (sim_->break_pc_ != NULL) {
200    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
201  }
202
203  sim_->break_pc_ = NULL;
204  sim_->break_instr_ = 0;
205  return true;
206}
207
208
209void MipsDebugger::UndoBreakpoints() {
210  if (sim_->break_pc_ != NULL) {
211    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
212  }
213}
214
215
216void MipsDebugger::RedoBreakpoints() {
217  if (sim_->break_pc_ != NULL) {
218    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
219  }
220}
221
222
223void MipsDebugger::PrintAllRegs() {
224#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
225
226  PrintF("\n");
227  // at, v0, a0.
228  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
229         REG_INFO(1), REG_INFO(2), REG_INFO(4));
230  // v1, a1.
231  PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
232         "", REG_INFO(3), REG_INFO(5));
233  // a2.
234  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
235  // a3.
236  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
237  PrintF("\n");
238  // t0-t7, s0-s7
239  for (int i = 0; i < 8; i++) {
240    PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
241           REG_INFO(8+i), REG_INFO(16+i));
242  }
243  PrintF("\n");
244  // t8, k0, LO.
245  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
246         REG_INFO(24), REG_INFO(26), REG_INFO(32));
247  // t9, k1, HI.
248  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
249         REG_INFO(25), REG_INFO(27), REG_INFO(33));
250  // sp, fp, gp.
251  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
252         REG_INFO(29), REG_INFO(30), REG_INFO(28));
253  // pc.
254  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
255         REG_INFO(31), REG_INFO(34));
256
257#undef REG_INFO
258#undef FPU_REG_INFO
259}
260
261
262void MipsDebugger::PrintAllRegsIncludingFPU() {
263#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
264        GetFPURegisterValue32(n+1), \
265        GetFPURegisterValue32(n), \
266        GetFPURegisterValueDouble(n)
267
268#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
269        GetFPURegisterValue64(n), \
270        GetFPURegisterValueDouble(n)
271
272  PrintAllRegs();
273
274  PrintF("\n\n");
275  // f0, f1, f2, ... f31.
276  // This must be a compile-time switch,
277  // compiler will throw out warnings otherwise.
278  if (kFpuMode == kFP64) {
279    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
280    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
281    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
282    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
283    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
284    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
285    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
286    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
287    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
288    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
289    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
290    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
291    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
292    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
293    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
294    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
295    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
296    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
297    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
298    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
299    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
300    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
301    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
302    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
303    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
304    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
305    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
306    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
307    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
308    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
309    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
310    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
311  } else {
312    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
313    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
314    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
315    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
316    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
317    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
318    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
319    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
320    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
321    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
322    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
323    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
324    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
325    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
326    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
327    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
328  }
329
330#undef REG_INFO
331#undef FPU_REG_INFO32
332#undef FPU_REG_INFO64
333}
334
335
336void MipsDebugger::Debug() {
337  intptr_t last_pc = -1;
338  bool done = false;
339
340#define COMMAND_SIZE 63
341#define ARG_SIZE 255
342
343#define STR(a) #a
344#define XSTR(a) STR(a)
345
346  char cmd[COMMAND_SIZE + 1];
347  char arg1[ARG_SIZE + 1];
348  char arg2[ARG_SIZE + 1];
349  char* argv[3] = { cmd, arg1, arg2 };
350
351  // Make sure to have a proper terminating character if reaching the limit.
352  cmd[COMMAND_SIZE] = 0;
353  arg1[ARG_SIZE] = 0;
354  arg2[ARG_SIZE] = 0;
355
356  // Undo all set breakpoints while running in the debugger shell. This will
357  // make them invisible to all commands.
358  UndoBreakpoints();
359
360  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
361    if (last_pc != sim_->get_pc()) {
362      disasm::NameConverter converter;
363      disasm::Disassembler dasm(converter);
364      // Use a reasonably large buffer.
365      v8::internal::EmbeddedVector<char, 256> buffer;
366      dasm.InstructionDecode(buffer,
367                             reinterpret_cast<byte*>(sim_->get_pc()));
368      PrintF("  0x%08x  %s\n", sim_->get_pc(), buffer.start());
369      last_pc = sim_->get_pc();
370    }
371    char* line = ReadLine("sim> ");
372    if (line == NULL) {
373      break;
374    } else {
375      char* last_input = sim_->last_debugger_input();
376      if (strcmp(line, "\n") == 0 && last_input != NULL) {
377        line = last_input;
378      } else {
379        // Ownership is transferred to sim_;
380        sim_->set_last_debugger_input(line);
381      }
382      // Use sscanf to parse the individual parts of the command line. At the
383      // moment no command expects more than two parameters.
384      int argc = SScanF(line,
385                        "%" XSTR(COMMAND_SIZE) "s "
386                        "%" XSTR(ARG_SIZE) "s "
387                        "%" XSTR(ARG_SIZE) "s",
388                        cmd, arg1, arg2);
389      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
390        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
391        if (!(instr->IsTrap()) ||
392            instr->InstructionBits() == rtCallRedirInstr) {
393          sim_->InstructionDecode(
394              reinterpret_cast<Instruction*>(sim_->get_pc()));
395        } else {
396          // Allow si to jump over generated breakpoints.
397          PrintF("/!\\ Jumping over generated breakpoint.\n");
398          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
399        }
400      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
401        // Execute the one instruction we broke at with breakpoints disabled.
402        sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
403        // Leave the debugger shell.
404        done = true;
405      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
406        if (argc == 2) {
407          if (strcmp(arg1, "all") == 0) {
408            PrintAllRegs();
409          } else if (strcmp(arg1, "allf") == 0) {
410            PrintAllRegsIncludingFPU();
411          } else {
412            int regnum = Registers::Number(arg1);
413            int fpuregnum = FPURegisters::Number(arg1);
414
415            if (regnum != kInvalidRegister) {
416              int32_t value;
417              value = GetRegisterValue(regnum);
418              PrintF("%s: 0x%08x %d \n", arg1, value, value);
419            } else if (fpuregnum != kInvalidFPURegister) {
420              if (IsFp64Mode()) {
421                int64_t value;
422                double dvalue;
423                value = GetFPURegisterValue64(fpuregnum);
424                dvalue = GetFPURegisterValueDouble(fpuregnum);
425                PrintF("%3s: 0x%016llx %16.4e\n",
426                       FPURegisters::Name(fpuregnum), value, dvalue);
427              } else {
428                if (fpuregnum % 2 == 1) {
429                  int32_t value;
430                  float fvalue;
431                  value = GetFPURegisterValue32(fpuregnum);
432                  fvalue = GetFPURegisterValueFloat(fpuregnum);
433                  PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
434                } else {
435                  double dfvalue;
436                  int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
437                  int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
438                  dfvalue = GetFPURegisterValueDouble(fpuregnum);
439                  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
440                         FPURegisters::Name(fpuregnum+1),
441                         FPURegisters::Name(fpuregnum),
442                         lvalue1,
443                         lvalue2,
444                         dfvalue);
445                }
446              }
447            } else {
448              PrintF("%s unrecognized\n", arg1);
449            }
450          }
451        } else {
452          if (argc == 3) {
453            if (strcmp(arg2, "single") == 0) {
454              int32_t value;
455              float fvalue;
456              int fpuregnum = FPURegisters::Number(arg1);
457
458              if (fpuregnum != kInvalidFPURegister) {
459                value = GetFPURegisterValue32(fpuregnum);
460                fvalue = GetFPURegisterValueFloat(fpuregnum);
461                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
462              } else {
463                PrintF("%s unrecognized\n", arg1);
464              }
465            } else {
466              PrintF("print <fpu register> single\n");
467            }
468          } else {
469            PrintF("print <register> or print <fpu register> single\n");
470          }
471        }
472      } else if ((strcmp(cmd, "po") == 0)
473                 || (strcmp(cmd, "printobject") == 0)) {
474        if (argc == 2) {
475          int32_t value;
476          OFStream os(stdout);
477          if (GetValue(arg1, &value)) {
478            Object* obj = reinterpret_cast<Object*>(value);
479            os << arg1 << ": \n";
480#ifdef DEBUG
481            obj->Print(os);
482            os << "\n";
483#else
484            os << Brief(obj) << "\n";
485#endif
486          } else {
487            os << arg1 << " unrecognized\n";
488          }
489        } else {
490          PrintF("printobject <value>\n");
491        }
492      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
493        int32_t* cur = NULL;
494        int32_t* end = NULL;
495        int next_arg = 1;
496
497        if (strcmp(cmd, "stack") == 0) {
498          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
499        } else {  // Command "mem".
500          int32_t value;
501          if (!GetValue(arg1, &value)) {
502            PrintF("%s unrecognized\n", arg1);
503            continue;
504          }
505          cur = reinterpret_cast<int32_t*>(value);
506          next_arg++;
507        }
508
509        // TODO(palfia): optimize this.
510        if (IsFp64Mode()) {
511          int64_t words;
512          if (argc == next_arg) {
513            words = 10;
514          } else {
515            if (!GetValue(argv[next_arg], &words)) {
516              words = 10;
517            }
518          }
519          end = cur + words;
520        } else {
521          int32_t words;
522          if (argc == next_arg) {
523            words = 10;
524          } else {
525            if (!GetValue(argv[next_arg], &words)) {
526              words = 10;
527            }
528          }
529          end = cur + words;
530        }
531
532        while (cur < end) {
533          PrintF("  0x%08" PRIxPTR ":  0x%08x %10d",
534                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
535          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
536          int value = *cur;
537          Heap* current_heap = sim_->isolate_->heap();
538          if (((value & 1) == 0) ||
539              current_heap->ContainsSlow(obj->address())) {
540            PrintF(" (");
541            if ((value & 1) == 0) {
542              PrintF("smi %d", value / 2);
543            } else {
544              obj->ShortPrint();
545            }
546            PrintF(")");
547          }
548          PrintF("\n");
549          cur++;
550        }
551
552      } else if ((strcmp(cmd, "disasm") == 0) ||
553                 (strcmp(cmd, "dpc") == 0) ||
554                 (strcmp(cmd, "di") == 0)) {
555        disasm::NameConverter converter;
556        disasm::Disassembler dasm(converter);
557        // Use a reasonably large buffer.
558        v8::internal::EmbeddedVector<char, 256> buffer;
559
560        byte* cur = NULL;
561        byte* end = NULL;
562
563        if (argc == 1) {
564          cur = reinterpret_cast<byte*>(sim_->get_pc());
565          end = cur + (10 * Instruction::kInstrSize);
566        } else if (argc == 2) {
567          int regnum = Registers::Number(arg1);
568          if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
569            // The argument is an address or a register name.
570            int32_t value;
571            if (GetValue(arg1, &value)) {
572              cur = reinterpret_cast<byte*>(value);
573              // Disassemble 10 instructions at <arg1>.
574              end = cur + (10 * Instruction::kInstrSize);
575            }
576          } else {
577            // The argument is the number of instructions.
578            int32_t value;
579            if (GetValue(arg1, &value)) {
580              cur = reinterpret_cast<byte*>(sim_->get_pc());
581              // Disassemble <arg1> instructions.
582              end = cur + (value * Instruction::kInstrSize);
583            }
584          }
585        } else {
586          int32_t value1;
587          int32_t value2;
588          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
589            cur = reinterpret_cast<byte*>(value1);
590            end = cur + (value2 * Instruction::kInstrSize);
591          }
592        }
593
594        while (cur < end) {
595          dasm.InstructionDecode(buffer, cur);
596          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
597                 buffer.start());
598          cur += Instruction::kInstrSize;
599        }
600      } else if (strcmp(cmd, "gdb") == 0) {
601        PrintF("relinquishing control to gdb\n");
602        v8::base::OS::DebugBreak();
603        PrintF("regaining control from gdb\n");
604      } else if (strcmp(cmd, "break") == 0) {
605        if (argc == 2) {
606          int32_t value;
607          if (GetValue(arg1, &value)) {
608            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
609              PrintF("setting breakpoint failed\n");
610            }
611          } else {
612            PrintF("%s unrecognized\n", arg1);
613          }
614        } else {
615          PrintF("break <address>\n");
616        }
617      } else if (strcmp(cmd, "del") == 0) {
618        if (!DeleteBreakpoint(NULL)) {
619          PrintF("deleting breakpoint failed\n");
620        }
621      } else if (strcmp(cmd, "flags") == 0) {
622        PrintF("No flags on MIPS !\n");
623      } else if (strcmp(cmd, "stop") == 0) {
624        int32_t value;
625        intptr_t stop_pc = sim_->get_pc() -
626            2 * Instruction::kInstrSize;
627        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
628        Instruction* msg_address =
629          reinterpret_cast<Instruction*>(stop_pc +
630              Instruction::kInstrSize);
631        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
632          // Remove the current stop.
633          if (sim_->IsStopInstruction(stop_instr)) {
634            stop_instr->SetInstructionBits(kNopInstr);
635            msg_address->SetInstructionBits(kNopInstr);
636          } else {
637            PrintF("Not at debugger stop.\n");
638          }
639        } else if (argc == 3) {
640          // Print information about all/the specified breakpoint(s).
641          if (strcmp(arg1, "info") == 0) {
642            if (strcmp(arg2, "all") == 0) {
643              PrintF("Stop information:\n");
644              for (uint32_t i = kMaxWatchpointCode + 1;
645                   i <= kMaxStopCode;
646                   i++) {
647                sim_->PrintStopInfo(i);
648              }
649            } else if (GetValue(arg2, &value)) {
650              sim_->PrintStopInfo(value);
651            } else {
652              PrintF("Unrecognized argument.\n");
653            }
654          } else if (strcmp(arg1, "enable") == 0) {
655            // Enable all/the specified breakpoint(s).
656            if (strcmp(arg2, "all") == 0) {
657              for (uint32_t i = kMaxWatchpointCode + 1;
658                   i <= kMaxStopCode;
659                   i++) {
660                sim_->EnableStop(i);
661              }
662            } else if (GetValue(arg2, &value)) {
663              sim_->EnableStop(value);
664            } else {
665              PrintF("Unrecognized argument.\n");
666            }
667          } else if (strcmp(arg1, "disable") == 0) {
668            // Disable all/the specified breakpoint(s).
669            if (strcmp(arg2, "all") == 0) {
670              for (uint32_t i = kMaxWatchpointCode + 1;
671                   i <= kMaxStopCode;
672                   i++) {
673                sim_->DisableStop(i);
674              }
675            } else if (GetValue(arg2, &value)) {
676              sim_->DisableStop(value);
677            } else {
678              PrintF("Unrecognized argument.\n");
679            }
680          }
681        } else {
682          PrintF("Wrong usage. Use help command for more information.\n");
683        }
684      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
685        // Print registers and disassemble.
686        PrintAllRegs();
687        PrintF("\n");
688
689        disasm::NameConverter converter;
690        disasm::Disassembler dasm(converter);
691        // Use a reasonably large buffer.
692        v8::internal::EmbeddedVector<char, 256> buffer;
693
694        byte* cur = NULL;
695        byte* end = NULL;
696
697        if (argc == 1) {
698          cur = reinterpret_cast<byte*>(sim_->get_pc());
699          end = cur + (10 * Instruction::kInstrSize);
700        } else if (argc == 2) {
701          int32_t value;
702          if (GetValue(arg1, &value)) {
703            cur = reinterpret_cast<byte*>(value);
704            // no length parameter passed, assume 10 instructions
705            end = cur + (10 * Instruction::kInstrSize);
706          }
707        } else {
708          int32_t value1;
709          int32_t value2;
710          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
711            cur = reinterpret_cast<byte*>(value1);
712            end = cur + (value2 * Instruction::kInstrSize);
713          }
714        }
715
716        while (cur < end) {
717          dasm.InstructionDecode(buffer, cur);
718          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
719                 buffer.start());
720          cur += Instruction::kInstrSize;
721        }
722      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
723        PrintF("cont\n");
724        PrintF("  continue execution (alias 'c')\n");
725        PrintF("stepi\n");
726        PrintF("  step one instruction (alias 'si')\n");
727        PrintF("print <register>\n");
728        PrintF("  print register content (alias 'p')\n");
729        PrintF("  use register name 'all' to print all registers\n");
730        PrintF("printobject <register>\n");
731        PrintF("  print an object from a register (alias 'po')\n");
732        PrintF("stack [<words>]\n");
733        PrintF("  dump stack content, default dump 10 words)\n");
734        PrintF("mem <address> [<words>]\n");
735        PrintF("  dump memory content, default dump 10 words)\n");
736        PrintF("flags\n");
737        PrintF("  print flags\n");
738        PrintF("disasm [<instructions>]\n");
739        PrintF("disasm [<address/register>]\n");
740        PrintF("disasm [[<address/register>] <instructions>]\n");
741        PrintF("  disassemble code, default is 10 instructions\n");
742        PrintF("  from pc (alias 'di')\n");
743        PrintF("gdb\n");
744        PrintF("  enter gdb\n");
745        PrintF("break <address>\n");
746        PrintF("  set a break point on the address\n");
747        PrintF("del\n");
748        PrintF("  delete the breakpoint\n");
749        PrintF("stop feature:\n");
750        PrintF("  Description:\n");
751        PrintF("    Stops are debug instructions inserted by\n");
752        PrintF("    the Assembler::stop() function.\n");
753        PrintF("    When hitting a stop, the Simulator will\n");
754        PrintF("    stop and and give control to the Debugger.\n");
755        PrintF("    All stop codes are watched:\n");
756        PrintF("    - They can be enabled / disabled: the Simulator\n");
757        PrintF("       will / won't stop when hitting them.\n");
758        PrintF("    - The Simulator keeps track of how many times they \n");
759        PrintF("      are met. (See the info command.) Going over a\n");
760        PrintF("      disabled stop still increases its counter. \n");
761        PrintF("  Commands:\n");
762        PrintF("    stop info all/<code> : print infos about number <code>\n");
763        PrintF("      or all stop(s).\n");
764        PrintF("    stop enable/disable all/<code> : enables / disables\n");
765        PrintF("      all or number <code> stop(s)\n");
766        PrintF("    stop unstop\n");
767        PrintF("      ignore the stop instruction at the current location\n");
768        PrintF("      from now on\n");
769      } else {
770        PrintF("Unknown command: %s\n", cmd);
771      }
772    }
773  }
774
775  // Add all the breakpoints back to stop execution and enter the debugger
776  // shell when hit.
777  RedoBreakpoints();
778
779#undef COMMAND_SIZE
780#undef ARG_SIZE
781
782#undef STR
783#undef XSTR
784}
785
786
787static bool ICacheMatch(void* one, void* two) {
788  DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
789  DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
790  return one == two;
791}
792
793
794static uint32_t ICacheHash(void* key) {
795  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
796}
797
798
799static bool AllOnOnePage(uintptr_t start, int size) {
800  intptr_t start_page = (start & ~CachePage::kPageMask);
801  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
802  return start_page == end_page;
803}
804
805
806void Simulator::set_last_debugger_input(char* input) {
807  DeleteArray(last_debugger_input_);
808  last_debugger_input_ = input;
809}
810
811void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
812                            void* start_addr, size_t size) {
813  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
814  int intra_line = (start & CachePage::kLineMask);
815  start -= intra_line;
816  size += intra_line;
817  size = ((size - 1) | CachePage::kLineMask) + 1;
818  int offset = (start & CachePage::kPageMask);
819  while (!AllOnOnePage(start, size - 1)) {
820    int bytes_to_flush = CachePage::kPageSize - offset;
821    FlushOnePage(i_cache, start, bytes_to_flush);
822    start += bytes_to_flush;
823    size -= bytes_to_flush;
824    DCHECK_EQ(0, start & CachePage::kPageMask);
825    offset = 0;
826  }
827  if (size != 0) {
828    FlushOnePage(i_cache, start, size);
829  }
830}
831
832CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
833                                   void* page) {
834  base::CustomMatcherHashMap::Entry* entry =
835      i_cache->LookupOrInsert(page, ICacheHash(page));
836  if (entry->value == NULL) {
837    CachePage* new_page = new CachePage();
838    entry->value = new_page;
839  }
840  return reinterpret_cast<CachePage*>(entry->value);
841}
842
843
844// Flush from start up to and not including start + size.
845void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
846                             intptr_t start, int size) {
847  DCHECK(size <= CachePage::kPageSize);
848  DCHECK(AllOnOnePage(start, size - 1));
849  DCHECK((start & CachePage::kLineMask) == 0);
850  DCHECK((size & CachePage::kLineMask) == 0);
851  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
852  int offset = (start & CachePage::kPageMask);
853  CachePage* cache_page = GetCachePage(i_cache, page);
854  char* valid_bytemap = cache_page->ValidityByte(offset);
855  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
856}
857
858void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
859                            Instruction* instr) {
860  intptr_t address = reinterpret_cast<intptr_t>(instr);
861  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
862  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
863  int offset = (address & CachePage::kPageMask);
864  CachePage* cache_page = GetCachePage(i_cache, page);
865  char* cache_valid_byte = cache_page->ValidityByte(offset);
866  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
867  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
868  if (cache_hit) {
869    // Check that the data in memory matches the contents of the I-cache.
870    CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
871                       cache_page->CachedData(offset),
872                       Instruction::kInstrSize));
873  } else {
874    // Cache miss.  Load memory into the cache.
875    memcpy(cached_line, line, CachePage::kLineLength);
876    *cache_valid_byte = CachePage::LINE_VALID;
877  }
878}
879
880
881void Simulator::Initialize(Isolate* isolate) {
882  if (isolate->simulator_initialized()) return;
883  isolate->set_simulator_initialized(true);
884  ::v8::internal::ExternalReference::set_redirector(isolate,
885                                                    &RedirectExternalReference);
886}
887
888
889Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
890  i_cache_ = isolate_->simulator_i_cache();
891  if (i_cache_ == NULL) {
892    i_cache_ = new base::CustomMatcherHashMap(&ICacheMatch);
893    isolate_->set_simulator_i_cache(i_cache_);
894  }
895  Initialize(isolate);
896  // Set up simulator support first. Some of this information is needed to
897  // setup the architecture state.
898  stack_ = reinterpret_cast<char*>(malloc(stack_size_));
899  pc_modified_ = false;
900  icount_ = 0;
901  break_count_ = 0;
902  break_pc_ = NULL;
903  break_instr_ = 0;
904
905  // Set up architecture state.
906  // All registers are initialized to zero to start with.
907  for (int i = 0; i < kNumSimuRegisters; i++) {
908    registers_[i] = 0;
909  }
910  for (int i = 0; i < kNumFPURegisters; i++) {
911    FPUregisters_[i] = 0;
912  }
913  if (IsMipsArchVariant(kMips32r6)) {
914    FCSR_ = kFCSRNaN2008FlagMask;
915  } else {
916    DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
917    FCSR_ = 0;
918  }
919
920  // The sp is initialized to point to the bottom (high address) of the
921  // allocated stack area. To be safe in potential stack underflows we leave
922  // some buffer below.
923  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
924  // The ra and pc are initialized to a known bad value that will cause an
925  // access violation if the simulator ever tries to execute it.
926  registers_[pc] = bad_ra;
927  registers_[ra] = bad_ra;
928  last_debugger_input_ = NULL;
929}
930
931
932Simulator::~Simulator() { free(stack_); }
933
934
935// When the generated code calls an external reference we need to catch that in
936// the simulator.  The external reference will be a function compiled for the
937// host architecture.  We need to call that function instead of trying to
938// execute it with the simulator.  We do that by redirecting the external
939// reference to a swi (software-interrupt) instruction that is handled by
940// the simulator.  We write the original destination of the jump just at a known
941// offset from the swi instruction so the simulator knows what to call.
942class Redirection {
943 public:
944  Redirection(Isolate* isolate, void* external_function,
945              ExternalReference::Type type)
946      : external_function_(external_function),
947        swi_instruction_(rtCallRedirInstr),
948        type_(type),
949        next_(NULL) {
950    next_ = isolate->simulator_redirection();
951    Simulator::current(isolate)->
952        FlushICache(isolate->simulator_i_cache(),
953                    reinterpret_cast<void*>(&swi_instruction_),
954                    Instruction::kInstrSize);
955    isolate->set_simulator_redirection(this);
956  }
957
958  void* address_of_swi_instruction() {
959    return reinterpret_cast<void*>(&swi_instruction_);
960  }
961
962  void* external_function() { return external_function_; }
963  ExternalReference::Type type() { return type_; }
964
965  static Redirection* Get(Isolate* isolate, void* external_function,
966                          ExternalReference::Type type) {
967    Redirection* current = isolate->simulator_redirection();
968    for (; current != NULL; current = current->next_) {
969      if (current->external_function_ == external_function) return current;
970    }
971    return new Redirection(isolate, external_function, type);
972  }
973
974  static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
975    char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
976    char* addr_of_redirection =
977        addr_of_swi - offsetof(Redirection, swi_instruction_);
978    return reinterpret_cast<Redirection*>(addr_of_redirection);
979  }
980
981  static void* ReverseRedirection(int32_t reg) {
982    Redirection* redirection = FromSwiInstruction(
983        reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
984    return redirection->external_function();
985  }
986
987  static void DeleteChain(Redirection* redirection) {
988    while (redirection != nullptr) {
989      Redirection* next = redirection->next_;
990      delete redirection;
991      redirection = next;
992    }
993  }
994
995 private:
996  void* external_function_;
997  uint32_t swi_instruction_;
998  ExternalReference::Type type_;
999  Redirection* next_;
1000};
1001
1002
1003// static
1004void Simulator::TearDown(base::CustomMatcherHashMap* i_cache,
1005                         Redirection* first) {
1006  Redirection::DeleteChain(first);
1007  if (i_cache != nullptr) {
1008    for (base::CustomMatcherHashMap::Entry* entry = i_cache->Start();
1009         entry != nullptr; entry = i_cache->Next(entry)) {
1010      delete static_cast<CachePage*>(entry->value);
1011    }
1012    delete i_cache;
1013  }
1014}
1015
1016
1017void* Simulator::RedirectExternalReference(Isolate* isolate,
1018                                           void* external_function,
1019                                           ExternalReference::Type type) {
1020  Redirection* redirection = Redirection::Get(isolate, external_function, type);
1021  return redirection->address_of_swi_instruction();
1022}
1023
1024
1025// Get the active Simulator for the current thread.
1026Simulator* Simulator::current(Isolate* isolate) {
1027  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
1028       isolate->FindOrAllocatePerThreadDataForThisThread();
1029  DCHECK(isolate_data != NULL);
1030  DCHECK(isolate_data != NULL);
1031
1032  Simulator* sim = isolate_data->simulator();
1033  if (sim == NULL) {
1034    // TODO(146): delete the simulator object when a thread/isolate goes away.
1035    sim = new Simulator(isolate);
1036    isolate_data->set_simulator(sim);
1037  }
1038  return sim;
1039}
1040
1041
1042// Sets the register in the architecture state. It will also deal with updating
1043// Simulator internal state for special registers such as PC.
1044void Simulator::set_register(int reg, int32_t value) {
1045  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1046  if (reg == pc) {
1047    pc_modified_ = true;
1048  }
1049
1050  // Zero register always holds 0.
1051  registers_[reg] = (reg == 0) ? 0 : value;
1052}
1053
1054
1055void Simulator::set_dw_register(int reg, const int* dbl) {
1056  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1057  registers_[reg] = dbl[0];
1058  registers_[reg + 1] = dbl[1];
1059}
1060
1061
1062void Simulator::set_fpu_register(int fpureg, int64_t value) {
1063  DCHECK(IsFp64Mode());
1064  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1065  FPUregisters_[fpureg] = value;
1066}
1067
1068
1069void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1070  // Set ONLY lower 32-bits, leaving upper bits untouched.
1071  // TODO(plind): big endian issue.
1072  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1073  int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1074  *pword = value;
1075}
1076
1077
1078void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1079  // Set ONLY upper 32-bits, leaving lower bits untouched.
1080  // TODO(plind): big endian issue.
1081  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1082  int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1083  *phiword = value;
1084}
1085
1086
1087void Simulator::set_fpu_register_float(int fpureg, float value) {
1088  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1089  *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
1090}
1091
1092
1093void Simulator::set_fpu_register_double(int fpureg, double value) {
1094  if (IsFp64Mode()) {
1095    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1096    *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1097  } else {
1098    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1099    int64_t i64 = bit_cast<int64_t>(value);
1100    set_fpu_register_word(fpureg, i64 & 0xffffffff);
1101    set_fpu_register_word(fpureg + 1, i64 >> 32);
1102  }
1103}
1104
1105
1106// Get the register from the architecture state. This function does handle
1107// the special case of accessing the PC register.
1108int32_t Simulator::get_register(int reg) const {
1109  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1110  if (reg == 0)
1111    return 0;
1112  else
1113    return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1114}
1115
1116
1117double Simulator::get_double_from_register_pair(int reg) {
1118  // TODO(plind): bad ABI stuff, refactor or remove.
1119  DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1120
1121  double dm_val = 0.0;
1122  // Read the bits from the unsigned integer register_[] array
1123  // into the double precision floating point value and return it.
1124  char buffer[2 * sizeof(registers_[0])];
1125  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1126  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1127  return(dm_val);
1128}
1129
1130
1131int64_t Simulator::get_fpu_register(int fpureg) const {
1132  DCHECK(IsFp64Mode());
1133  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1134  return FPUregisters_[fpureg];
1135}
1136
1137
1138int32_t Simulator::get_fpu_register_word(int fpureg) const {
1139  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1140  return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1141}
1142
1143
1144int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1145  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1146  return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1147}
1148
1149
1150int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1151  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1152  return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
1153}
1154
1155
1156float Simulator::get_fpu_register_float(int fpureg) const {
1157  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1158  return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
1159}
1160
1161
1162double Simulator::get_fpu_register_double(int fpureg) const {
1163  if (IsFp64Mode()) {
1164    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1165    return *bit_cast<double*>(&FPUregisters_[fpureg]);
1166  } else {
1167    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1168    int64_t i64;
1169    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1170    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1171    return bit_cast<double>(i64);
1172  }
1173}
1174
1175
1176// Runtime FP routines take up to two double arguments and zero
1177// or one integer arguments. All are constructed here,
1178// from a0-a3 or f12 and f14.
1179void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1180  if (!IsMipsSoftFloatABI) {
1181    *x = get_fpu_register_double(12);
1182    *y = get_fpu_register_double(14);
1183    *z = get_register(a2);
1184  } else {
1185    // TODO(plind): bad ABI stuff, refactor or remove.
1186    // We use a char buffer to get around the strict-aliasing rules which
1187    // otherwise allow the compiler to optimize away the copy.
1188    char buffer[sizeof(*x)];
1189    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1190
1191    // Registers a0 and a1 -> x.
1192    reg_buffer[0] = get_register(a0);
1193    reg_buffer[1] = get_register(a1);
1194    memcpy(x, buffer, sizeof(buffer));
1195    // Registers a2 and a3 -> y.
1196    reg_buffer[0] = get_register(a2);
1197    reg_buffer[1] = get_register(a3);
1198    memcpy(y, buffer, sizeof(buffer));
1199    // Register 2 -> z.
1200    reg_buffer[0] = get_register(a2);
1201    memcpy(z, buffer, sizeof(*z));
1202  }
1203}
1204
1205
1206// The return value is either in v0/v1 or f0.
1207void Simulator::SetFpResult(const double& result) {
1208  if (!IsMipsSoftFloatABI) {
1209    set_fpu_register_double(0, result);
1210  } else {
1211    char buffer[2 * sizeof(registers_[0])];
1212    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1213    memcpy(buffer, &result, sizeof(buffer));
1214    // Copy result to v0 and v1.
1215    set_register(v0, reg_buffer[0]);
1216    set_register(v1, reg_buffer[1]);
1217  }
1218}
1219
1220
1221// Helper functions for setting and testing the FCSR register's bits.
1222void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1223  if (value) {
1224    FCSR_ |= (1 << cc);
1225  } else {
1226    FCSR_ &= ~(1 << cc);
1227  }
1228}
1229
1230
1231bool Simulator::test_fcsr_bit(uint32_t cc) {
1232  return FCSR_ & (1 << cc);
1233}
1234
1235
1236void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1237  FCSR_ |= mode & kFPURoundingModeMask;
1238}
1239
1240
1241unsigned int Simulator::get_fcsr_rounding_mode() {
1242  return FCSR_ & kFPURoundingModeMask;
1243}
1244
1245
1246void Simulator::set_fpu_register_word_invalid_result(float original,
1247                                                     float rounded) {
1248  if (FCSR_ & kFCSRNaN2008FlagMask) {
1249    double max_int32 = std::numeric_limits<int32_t>::max();
1250    double min_int32 = std::numeric_limits<int32_t>::min();
1251    if (std::isnan(original)) {
1252      set_fpu_register_word(fd_reg(), 0);
1253    } else if (rounded > max_int32) {
1254      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1255    } else if (rounded < min_int32) {
1256      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1257    } else {
1258      UNREACHABLE();
1259    }
1260  } else {
1261    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1262  }
1263}
1264
1265
1266void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1267  if (FCSR_ & kFCSRNaN2008FlagMask) {
1268    double max_int32 = std::numeric_limits<int32_t>::max();
1269    double min_int32 = std::numeric_limits<int32_t>::min();
1270    if (std::isnan(original)) {
1271      set_fpu_register(fd_reg(), 0);
1272    } else if (rounded > max_int32) {
1273      set_fpu_register(fd_reg(), kFPUInvalidResult);
1274    } else if (rounded < min_int32) {
1275      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1276    } else {
1277      UNREACHABLE();
1278    }
1279  } else {
1280    set_fpu_register(fd_reg(), kFPUInvalidResult);
1281  }
1282}
1283
1284
1285void Simulator::set_fpu_register_invalid_result64(float original,
1286                                                  float rounded) {
1287  if (FCSR_ & kFCSRNaN2008FlagMask) {
1288    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1289    // loading the most accurate representation into max_int64, which is 2^63.
1290    double max_int64 = std::numeric_limits<int64_t>::max();
1291    double min_int64 = std::numeric_limits<int64_t>::min();
1292    if (std::isnan(original)) {
1293      set_fpu_register(fd_reg(), 0);
1294    } else if (rounded >= max_int64) {
1295      set_fpu_register(fd_reg(), kFPU64InvalidResult);
1296    } else if (rounded < min_int64) {
1297      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1298    } else {
1299      UNREACHABLE();
1300    }
1301  } else {
1302    set_fpu_register(fd_reg(), kFPU64InvalidResult);
1303  }
1304}
1305
1306
1307void Simulator::set_fpu_register_word_invalid_result(double original,
1308                                                     double rounded) {
1309  if (FCSR_ & kFCSRNaN2008FlagMask) {
1310    double max_int32 = std::numeric_limits<int32_t>::max();
1311    double min_int32 = std::numeric_limits<int32_t>::min();
1312    if (std::isnan(original)) {
1313      set_fpu_register_word(fd_reg(), 0);
1314    } else if (rounded > max_int32) {
1315      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1316    } else if (rounded < min_int32) {
1317      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1318    } else {
1319      UNREACHABLE();
1320    }
1321  } else {
1322    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1323  }
1324}
1325
1326
1327void Simulator::set_fpu_register_invalid_result(double original,
1328                                                double rounded) {
1329  if (FCSR_ & kFCSRNaN2008FlagMask) {
1330    double max_int32 = std::numeric_limits<int32_t>::max();
1331    double min_int32 = std::numeric_limits<int32_t>::min();
1332    if (std::isnan(original)) {
1333      set_fpu_register(fd_reg(), 0);
1334    } else if (rounded > max_int32) {
1335      set_fpu_register(fd_reg(), kFPUInvalidResult);
1336    } else if (rounded < min_int32) {
1337      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1338    } else {
1339      UNREACHABLE();
1340    }
1341  } else {
1342    set_fpu_register(fd_reg(), kFPUInvalidResult);
1343  }
1344}
1345
1346
1347void Simulator::set_fpu_register_invalid_result64(double original,
1348                                                  double rounded) {
1349  if (FCSR_ & kFCSRNaN2008FlagMask) {
1350    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1351    // loading the most accurate representation into max_int64, which is 2^63.
1352    double max_int64 = std::numeric_limits<int64_t>::max();
1353    double min_int64 = std::numeric_limits<int64_t>::min();
1354    if (std::isnan(original)) {
1355      set_fpu_register(fd_reg(), 0);
1356    } else if (rounded >= max_int64) {
1357      set_fpu_register(fd_reg(), kFPU64InvalidResult);
1358    } else if (rounded < min_int64) {
1359      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1360    } else {
1361      UNREACHABLE();
1362    }
1363  } else {
1364    set_fpu_register(fd_reg(), kFPU64InvalidResult);
1365  }
1366}
1367
1368
1369// Sets the rounding error codes in FCSR based on the result of the rounding.
1370// Returns true if the operation was invalid.
1371bool Simulator::set_fcsr_round_error(double original, double rounded) {
1372  bool ret = false;
1373  double max_int32 = std::numeric_limits<int32_t>::max();
1374  double min_int32 = std::numeric_limits<int32_t>::min();
1375
1376  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1377    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1378    ret = true;
1379  }
1380
1381  if (original != rounded) {
1382    set_fcsr_bit(kFCSRInexactFlagBit, true);
1383  }
1384
1385  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1386    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1387    ret = true;
1388  }
1389
1390  if (rounded > max_int32 || rounded < min_int32) {
1391    set_fcsr_bit(kFCSROverflowFlagBit, true);
1392    // The reference is not really clear but it seems this is required:
1393    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1394    ret = true;
1395  }
1396
1397  return ret;
1398}
1399
1400
1401// Sets the rounding error codes in FCSR based on the result of the rounding.
1402// Returns true if the operation was invalid.
1403bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1404  bool ret = false;
1405  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1406  // loading the most accurate representation into max_int64, which is 2^63.
1407  double max_int64 = std::numeric_limits<int64_t>::max();
1408  double min_int64 = std::numeric_limits<int64_t>::min();
1409
1410  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1411    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1412    ret = true;
1413  }
1414
1415  if (original != rounded) {
1416    set_fcsr_bit(kFCSRInexactFlagBit, true);
1417  }
1418
1419  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1420    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1421    ret = true;
1422  }
1423
1424  if (rounded >= max_int64 || rounded < min_int64) {
1425    set_fcsr_bit(kFCSROverflowFlagBit, true);
1426    // The reference is not really clear but it seems this is required:
1427    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1428    ret = true;
1429  }
1430
1431  return ret;
1432}
1433
1434
1435// Sets the rounding error codes in FCSR based on the result of the rounding.
1436// Returns true if the operation was invalid.
1437bool Simulator::set_fcsr_round_error(float original, float rounded) {
1438  bool ret = false;
1439  double max_int32 = std::numeric_limits<int32_t>::max();
1440  double min_int32 = std::numeric_limits<int32_t>::min();
1441
1442  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1443    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1444    ret = true;
1445  }
1446
1447  if (original != rounded) {
1448    set_fcsr_bit(kFCSRInexactFlagBit, true);
1449  }
1450
1451  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1452    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1453    ret = true;
1454  }
1455
1456  if (rounded > max_int32 || rounded < min_int32) {
1457    set_fcsr_bit(kFCSROverflowFlagBit, true);
1458    // The reference is not really clear but it seems this is required:
1459    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1460    ret = true;
1461  }
1462
1463  return ret;
1464}
1465
1466
1467// Sets the rounding error codes in FCSR based on the result of the rounding.
1468// Returns true if the operation was invalid.
1469bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1470  bool ret = false;
1471  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1472  // loading the most accurate representation into max_int64, which is 2^63.
1473  double max_int64 = std::numeric_limits<int64_t>::max();
1474  double min_int64 = std::numeric_limits<int64_t>::min();
1475
1476  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1477    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1478    ret = true;
1479  }
1480
1481  if (original != rounded) {
1482    set_fcsr_bit(kFCSRInexactFlagBit, true);
1483  }
1484
1485  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1486    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1487    ret = true;
1488  }
1489
1490  if (rounded >= max_int64 || rounded < min_int64) {
1491    set_fcsr_bit(kFCSROverflowFlagBit, true);
1492    // The reference is not really clear but it seems this is required:
1493    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1494    ret = true;
1495  }
1496
1497  return ret;
1498}
1499
1500
1501void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1502                                        int32_t& rounded_int, double fs) {
1503  // 0 RN (round to nearest): Round a result to the nearest
1504  // representable value; if the result is exactly halfway between
1505  // two representable values, round to zero. Behave like round_w_d.
1506
1507  // 1 RZ (round toward zero): Round a result to the closest
1508  // representable value whose absolute value is less than or
1509  // equal to the infinitely accurate result. Behave like trunc_w_d.
1510
1511  // 2 RP (round up, or toward  infinity): Round a result to the
1512  // next representable value up. Behave like ceil_w_d.
1513
1514  // 3 RD (round down, or toward −infinity): Round a result to
1515  // the next representable value down. Behave like floor_w_d.
1516  switch (get_fcsr_rounding_mode()) {
1517    case kRoundToNearest:
1518      rounded = std::floor(fs + 0.5);
1519      rounded_int = static_cast<int32_t>(rounded);
1520      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1521        // If the number is halfway between two integers,
1522        // round to the even one.
1523        rounded_int--;
1524      }
1525      break;
1526    case kRoundToZero:
1527      rounded = trunc(fs);
1528      rounded_int = static_cast<int32_t>(rounded);
1529      break;
1530    case kRoundToPlusInf:
1531      rounded = std::ceil(fs);
1532      rounded_int = static_cast<int32_t>(rounded);
1533      break;
1534    case kRoundToMinusInf:
1535      rounded = std::floor(fs);
1536      rounded_int = static_cast<int32_t>(rounded);
1537      break;
1538  }
1539}
1540
1541
1542void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1543                                        int32_t& rounded_int, float fs) {
1544  // 0 RN (round to nearest): Round a result to the nearest
1545  // representable value; if the result is exactly halfway between
1546  // two representable values, round to zero. Behave like round_w_d.
1547
1548  // 1 RZ (round toward zero): Round a result to the closest
1549  // representable value whose absolute value is less than or
1550  // equal to the infinitely accurate result. Behave like trunc_w_d.
1551
1552  // 2 RP (round up, or toward  infinity): Round a result to the
1553  // next representable value up. Behave like ceil_w_d.
1554
1555  // 3 RD (round down, or toward −infinity): Round a result to
1556  // the next representable value down. Behave like floor_w_d.
1557  switch (get_fcsr_rounding_mode()) {
1558    case kRoundToNearest:
1559      rounded = std::floor(fs + 0.5);
1560      rounded_int = static_cast<int32_t>(rounded);
1561      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1562        // If the number is halfway between two integers,
1563        // round to the even one.
1564        rounded_int--;
1565      }
1566      break;
1567    case kRoundToZero:
1568      rounded = trunc(fs);
1569      rounded_int = static_cast<int32_t>(rounded);
1570      break;
1571    case kRoundToPlusInf:
1572      rounded = std::ceil(fs);
1573      rounded_int = static_cast<int32_t>(rounded);
1574      break;
1575    case kRoundToMinusInf:
1576      rounded = std::floor(fs);
1577      rounded_int = static_cast<int32_t>(rounded);
1578      break;
1579  }
1580}
1581
1582
1583void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1584                                          int64_t& rounded_int, double fs) {
1585  // 0 RN (round to nearest): Round a result to the nearest
1586  // representable value; if the result is exactly halfway between
1587  // two representable values, round to zero. Behave like round_w_d.
1588
1589  // 1 RZ (round toward zero): Round a result to the closest
1590  // representable value whose absolute value is less than or.
1591  // equal to the infinitely accurate result. Behave like trunc_w_d.
1592
1593  // 2 RP (round up, or toward +infinity): Round a result to the
1594  // next representable value up. Behave like ceil_w_d.
1595
1596  // 3 RN (round down, or toward −infinity): Round a result to
1597  // the next representable value down. Behave like floor_w_d.
1598  switch (FCSR_ & 3) {
1599    case kRoundToNearest:
1600      rounded = std::floor(fs + 0.5);
1601      rounded_int = static_cast<int64_t>(rounded);
1602      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1603        // If the number is halfway between two integers,
1604        // round to the even one.
1605        rounded_int--;
1606      }
1607      break;
1608    case kRoundToZero:
1609      rounded = trunc(fs);
1610      rounded_int = static_cast<int64_t>(rounded);
1611      break;
1612    case kRoundToPlusInf:
1613      rounded = std::ceil(fs);
1614      rounded_int = static_cast<int64_t>(rounded);
1615      break;
1616    case kRoundToMinusInf:
1617      rounded = std::floor(fs);
1618      rounded_int = static_cast<int64_t>(rounded);
1619      break;
1620  }
1621}
1622
1623
1624void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1625                                          int64_t& rounded_int, float fs) {
1626  // 0 RN (round to nearest): Round a result to the nearest
1627  // representable value; if the result is exactly halfway between
1628  // two representable values, round to zero. Behave like round_w_d.
1629
1630  // 1 RZ (round toward zero): Round a result to the closest
1631  // representable value whose absolute value is less than or.
1632  // equal to the infinitely accurate result. Behave like trunc_w_d.
1633
1634  // 2 RP (round up, or toward +infinity): Round a result to the
1635  // next representable value up. Behave like ceil_w_d.
1636
1637  // 3 RN (round down, or toward −infinity): Round a result to
1638  // the next representable value down. Behave like floor_w_d.
1639  switch (FCSR_ & 3) {
1640    case kRoundToNearest:
1641      rounded = std::floor(fs + 0.5);
1642      rounded_int = static_cast<int64_t>(rounded);
1643      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1644        // If the number is halfway between two integers,
1645        // round to the even one.
1646        rounded_int--;
1647      }
1648      break;
1649    case kRoundToZero:
1650      rounded = trunc(fs);
1651      rounded_int = static_cast<int64_t>(rounded);
1652      break;
1653    case kRoundToPlusInf:
1654      rounded = std::ceil(fs);
1655      rounded_int = static_cast<int64_t>(rounded);
1656      break;
1657    case kRoundToMinusInf:
1658      rounded = std::floor(fs);
1659      rounded_int = static_cast<int64_t>(rounded);
1660      break;
1661  }
1662}
1663
1664
1665// Raw access to the PC register.
1666void Simulator::set_pc(int32_t value) {
1667  pc_modified_ = true;
1668  registers_[pc] = value;
1669}
1670
1671
1672bool Simulator::has_bad_pc() const {
1673  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1674}
1675
1676
1677// Raw access to the PC register without the special adjustment when reading.
1678int32_t Simulator::get_pc() const {
1679  return registers_[pc];
1680}
1681
1682
1683// The MIPS cannot do unaligned reads and writes.  On some MIPS platforms an
1684// interrupt is caused.  On others it does a funky rotation thing.  For now we
1685// simply disallow unaligned reads, but at some point we may want to move to
1686// emulating the rotate behaviour.  Note that simulator runs have the runtime
1687// system running directly on the host system and only generated code is
1688// executed in the simulator.  Since the host is typically IA32 we will not
1689// get the correct MIPS-like behaviour on unaligned accesses.
1690
1691void Simulator::TraceRegWr(int32_t value) {
1692  if (::v8::internal::FLAG_trace_sim) {
1693    SNPrintF(trace_buf_, "%08x", value);
1694  }
1695}
1696
1697
1698// TODO(plind): consider making icount_ printing a flag option.
1699void Simulator::TraceMemRd(int32_t addr, int32_t value) {
1700  if (::v8::internal::FLAG_trace_sim) {
1701    SNPrintF(trace_buf_, "%08x <-- [%08x]    (%" PRIu64 ")", value, addr,
1702             icount_);
1703  }
1704}
1705
1706
1707void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1708  if (::v8::internal::FLAG_trace_sim) {
1709    switch (t) {
1710      case BYTE:
1711        SNPrintF(trace_buf_, "      %02x --> [%08x]",
1712                 static_cast<int8_t>(value), addr);
1713        break;
1714      case HALF:
1715        SNPrintF(trace_buf_, "    %04x --> [%08x]", static_cast<int16_t>(value),
1716                 addr);
1717        break;
1718      case WORD:
1719        SNPrintF(trace_buf_, "%08x --> [%08x]", value, addr);
1720        break;
1721    }
1722  }
1723}
1724
1725
1726int Simulator::ReadW(int32_t addr, Instruction* instr) {
1727  if (addr >=0 && addr < 0x400) {
1728    // This has to be a NULL-dereference, drop into debugger.
1729    PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1730           reinterpret_cast<intptr_t>(instr));
1731    MipsDebugger dbg(this);
1732    dbg.Debug();
1733  }
1734  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1735    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1736    TraceMemRd(addr, static_cast<int32_t>(*ptr));
1737    return *ptr;
1738  }
1739  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1740         addr,
1741         reinterpret_cast<intptr_t>(instr));
1742  MipsDebugger dbg(this);
1743  dbg.Debug();
1744  return 0;
1745}
1746
1747
1748void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1749  if (addr >= 0 && addr < 0x400) {
1750    // This has to be a NULL-dereference, drop into debugger.
1751    PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1752           reinterpret_cast<intptr_t>(instr));
1753    MipsDebugger dbg(this);
1754    dbg.Debug();
1755  }
1756  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1757    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1758    TraceMemWr(addr, value, WORD);
1759    *ptr = value;
1760    return;
1761  }
1762  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1763         addr,
1764         reinterpret_cast<intptr_t>(instr));
1765  MipsDebugger dbg(this);
1766  dbg.Debug();
1767}
1768
1769
1770double Simulator::ReadD(int32_t addr, Instruction* instr) {
1771  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1772    double* ptr = reinterpret_cast<double*>(addr);
1773    return *ptr;
1774  }
1775  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1776         addr,
1777         reinterpret_cast<intptr_t>(instr));
1778  base::OS::Abort();
1779  return 0;
1780}
1781
1782
1783void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1784  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1785    double* ptr = reinterpret_cast<double*>(addr);
1786    *ptr = value;
1787    return;
1788  }
1789  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1790         addr,
1791         reinterpret_cast<intptr_t>(instr));
1792  base::OS::Abort();
1793}
1794
1795
1796uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1797  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
1798    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1799    TraceMemRd(addr, static_cast<int32_t>(*ptr));
1800    return *ptr;
1801  }
1802  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1803         addr,
1804         reinterpret_cast<intptr_t>(instr));
1805  base::OS::Abort();
1806  return 0;
1807}
1808
1809
1810int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1811  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
1812    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1813    TraceMemRd(addr, static_cast<int32_t>(*ptr));
1814    return *ptr;
1815  }
1816  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1817         addr,
1818         reinterpret_cast<intptr_t>(instr));
1819  base::OS::Abort();
1820  return 0;
1821}
1822
1823
1824void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1825  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
1826    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1827    TraceMemWr(addr, value, HALF);
1828    *ptr = value;
1829    return;
1830  }
1831  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1832         addr,
1833         reinterpret_cast<intptr_t>(instr));
1834  base::OS::Abort();
1835}
1836
1837
1838void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1839  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
1840    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1841    TraceMemWr(addr, value, HALF);
1842    *ptr = value;
1843    return;
1844  }
1845  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1846         addr,
1847         reinterpret_cast<intptr_t>(instr));
1848  base::OS::Abort();
1849}
1850
1851
1852uint32_t Simulator::ReadBU(int32_t addr) {
1853  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1854  TraceMemRd(addr, static_cast<int32_t>(*ptr));
1855  return *ptr & 0xff;
1856}
1857
1858
1859int32_t Simulator::ReadB(int32_t addr) {
1860  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1861  TraceMemRd(addr, static_cast<int32_t>(*ptr));
1862  return *ptr;
1863}
1864
1865
1866void Simulator::WriteB(int32_t addr, uint8_t value) {
1867  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1868  TraceMemWr(addr, value, BYTE);
1869  *ptr = value;
1870}
1871
1872
1873void Simulator::WriteB(int32_t addr, int8_t value) {
1874  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1875  TraceMemWr(addr, value, BYTE);
1876  *ptr = value;
1877}
1878
1879
1880// Returns the limit of the stack area to enable checking for stack overflows.
1881uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1882  // The simulator uses a separate JS stack. If we have exhausted the C stack,
1883  // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1884  if (GetCurrentStackPosition() < c_limit) {
1885    return reinterpret_cast<uintptr_t>(get_sp());
1886  }
1887
1888  // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1889  // to prevent overrunning the stack when pushing values.
1890  return reinterpret_cast<uintptr_t>(stack_) + 1024;
1891}
1892
1893
1894// Unsupported instructions use Format to print an error and stop execution.
1895void Simulator::Format(Instruction* instr, const char* format) {
1896  PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
1897         reinterpret_cast<intptr_t>(instr), format);
1898  UNIMPLEMENTED_MIPS();
1899}
1900
1901
1902// Calls into the V8 runtime are based on this very simple interface.
1903// Note: To be able to return two values from some calls the code in runtime.cc
1904// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1905// 64-bit value. With the code below we assume that all runtime calls return
1906// 64 bits of result. If they don't, the v1 result register contains a bogus
1907// value, which is fine because it is caller-saved.
1908typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1909                                        int32_t arg1,
1910                                        int32_t arg2,
1911                                        int32_t arg3,
1912                                        int32_t arg4,
1913                                        int32_t arg5);
1914
1915typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1916                                                   int32_t arg2, int32_t arg3,
1917                                                   int32_t arg4);
1918
1919// These prototypes handle the four types of FP calls.
1920typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1921typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1922typedef double (*SimulatorRuntimeFPCall)(double darg0);
1923typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1924
1925// This signature supports direct call in to API function native callback
1926// (refer to InvocationCallback in v8.h).
1927typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1928typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
1929
1930// This signature supports direct call to accessor getter callback.
1931typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1932typedef void (*SimulatorRuntimeProfilingGetterCall)(
1933    int32_t arg0, int32_t arg1, void* arg2);
1934
1935// Software interrupt instructions are used by the simulator to call into the
1936// C-based V8 runtime. They are also used for debugging with simulator.
1937void Simulator::SoftwareInterrupt() {
1938  // There are several instructions that could get us here,
1939  // the break_ instruction, or several variants of traps. All
1940  // Are "SPECIAL" class opcode, and are distinuished by function.
1941  int32_t func = instr_.FunctionFieldRaw();
1942  uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
1943
1944  // We first check if we met a call_rt_redirected.
1945  if (instr_.InstructionBits() == rtCallRedirInstr) {
1946    Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr());
1947    int32_t arg0 = get_register(a0);
1948    int32_t arg1 = get_register(a1);
1949    int32_t arg2 = get_register(a2);
1950    int32_t arg3 = get_register(a3);
1951
1952    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1953    // Args 4 and 5 are on the stack after the reserved space for args 0..3.
1954    int32_t arg4 = stack_pointer[4];
1955    int32_t arg5 = stack_pointer[5];
1956
1957    bool fp_call =
1958         (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1959         (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1960         (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1961         (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1962
1963    if (!IsMipsSoftFloatABI) {
1964      // With the hard floating point calling convention, double
1965      // arguments are passed in FPU registers. Fetch the arguments
1966      // from there and call the builtin using soft floating point
1967      // convention.
1968      switch (redirection->type()) {
1969      case ExternalReference::BUILTIN_FP_FP_CALL:
1970      case ExternalReference::BUILTIN_COMPARE_CALL:
1971        if (IsFp64Mode()) {
1972          arg0 = get_fpu_register_word(f12);
1973          arg1 = get_fpu_register_hi_word(f12);
1974          arg2 = get_fpu_register_word(f14);
1975          arg3 = get_fpu_register_hi_word(f14);
1976        } else {
1977          arg0 = get_fpu_register_word(f12);
1978          arg1 = get_fpu_register_word(f13);
1979          arg2 = get_fpu_register_word(f14);
1980          arg3 = get_fpu_register_word(f15);
1981        }
1982        break;
1983      case ExternalReference::BUILTIN_FP_CALL:
1984        if (IsFp64Mode()) {
1985          arg0 = get_fpu_register_word(f12);
1986          arg1 = get_fpu_register_hi_word(f12);
1987        } else {
1988          arg0 = get_fpu_register_word(f12);
1989          arg1 = get_fpu_register_word(f13);
1990        }
1991        break;
1992      case ExternalReference::BUILTIN_FP_INT_CALL:
1993        if (IsFp64Mode()) {
1994          arg0 = get_fpu_register_word(f12);
1995          arg1 = get_fpu_register_hi_word(f12);
1996        } else {
1997          arg0 = get_fpu_register_word(f12);
1998          arg1 = get_fpu_register_word(f13);
1999        }
2000        arg2 = get_register(a2);
2001        break;
2002      default:
2003        break;
2004      }
2005    }
2006
2007    // This is dodgy but it works because the C entry stubs are never moved.
2008    // See comment in codegen-arm.cc and bug 1242173.
2009    int32_t saved_ra = get_register(ra);
2010
2011    intptr_t external =
2012          reinterpret_cast<intptr_t>(redirection->external_function());
2013
2014    // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2015    // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2016    // simulator. Soft-float has additional abstraction of ExternalReference,
2017    // to support serialization.
2018    if (fp_call) {
2019      double dval0, dval1;  // one or two double parameters
2020      int32_t ival;         // zero or one integer parameters
2021      int64_t iresult = 0;  // integer return value
2022      double dresult = 0;   // double return value
2023      GetFpArgs(&dval0, &dval1, &ival);
2024      SimulatorRuntimeCall generic_target =
2025          reinterpret_cast<SimulatorRuntimeCall>(external);
2026      if (::v8::internal::FLAG_trace_sim) {
2027        switch (redirection->type()) {
2028          case ExternalReference::BUILTIN_FP_FP_CALL:
2029          case ExternalReference::BUILTIN_COMPARE_CALL:
2030            PrintF("Call to host function at %p with args %f, %f",
2031                   static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2032                   dval1);
2033            break;
2034          case ExternalReference::BUILTIN_FP_CALL:
2035            PrintF("Call to host function at %p with arg %f",
2036                   static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0);
2037            break;
2038          case ExternalReference::BUILTIN_FP_INT_CALL:
2039            PrintF("Call to host function at %p with args %f, %d",
2040                   static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2041                   ival);
2042            break;
2043          default:
2044            UNREACHABLE();
2045            break;
2046        }
2047      }
2048      switch (redirection->type()) {
2049      case ExternalReference::BUILTIN_COMPARE_CALL: {
2050        SimulatorRuntimeCompareCall target =
2051          reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2052        iresult = target(dval0, dval1);
2053        set_register(v0, static_cast<int32_t>(iresult));
2054        set_register(v1, static_cast<int32_t>(iresult >> 32));
2055        break;
2056      }
2057      case ExternalReference::BUILTIN_FP_FP_CALL: {
2058        SimulatorRuntimeFPFPCall target =
2059          reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2060        dresult = target(dval0, dval1);
2061        SetFpResult(dresult);
2062        break;
2063      }
2064      case ExternalReference::BUILTIN_FP_CALL: {
2065        SimulatorRuntimeFPCall target =
2066          reinterpret_cast<SimulatorRuntimeFPCall>(external);
2067        dresult = target(dval0);
2068        SetFpResult(dresult);
2069        break;
2070      }
2071      case ExternalReference::BUILTIN_FP_INT_CALL: {
2072        SimulatorRuntimeFPIntCall target =
2073          reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2074        dresult = target(dval0, ival);
2075        SetFpResult(dresult);
2076        break;
2077      }
2078      default:
2079        UNREACHABLE();
2080        break;
2081      }
2082      if (::v8::internal::FLAG_trace_sim) {
2083        switch (redirection->type()) {
2084        case ExternalReference::BUILTIN_COMPARE_CALL:
2085          PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2086          break;
2087        case ExternalReference::BUILTIN_FP_FP_CALL:
2088        case ExternalReference::BUILTIN_FP_CALL:
2089        case ExternalReference::BUILTIN_FP_INT_CALL:
2090          PrintF("Returned %f\n", dresult);
2091          break;
2092        default:
2093          UNREACHABLE();
2094          break;
2095        }
2096      }
2097    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2098      if (::v8::internal::FLAG_trace_sim) {
2099        PrintF("Call to host function at %p args %08x\n",
2100            reinterpret_cast<void*>(external), arg0);
2101      }
2102      SimulatorRuntimeDirectApiCall target =
2103          reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2104      target(arg0);
2105    } else if (
2106        redirection->type() == ExternalReference::PROFILING_API_CALL) {
2107      if (::v8::internal::FLAG_trace_sim) {
2108        PrintF("Call to host function at %p args %08x %08x\n",
2109            reinterpret_cast<void*>(external), arg0, arg1);
2110      }
2111      SimulatorRuntimeProfilingApiCall target =
2112          reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2113      target(arg0, Redirection::ReverseRedirection(arg1));
2114    } else if (
2115        redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2116      if (::v8::internal::FLAG_trace_sim) {
2117        PrintF("Call to host function at %p args %08x %08x\n",
2118            reinterpret_cast<void*>(external), arg0, arg1);
2119      }
2120      SimulatorRuntimeDirectGetterCall target =
2121          reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2122      target(arg0, arg1);
2123    } else if (
2124        redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2125      if (::v8::internal::FLAG_trace_sim) {
2126        PrintF("Call to host function at %p args %08x %08x %08x\n",
2127            reinterpret_cast<void*>(external), arg0, arg1, arg2);
2128      }
2129      SimulatorRuntimeProfilingGetterCall target =
2130          reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2131      target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2132    } else if (redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE) {
2133      // builtin call returning ObjectTriple.
2134      SimulatorRuntimeTripleCall target =
2135          reinterpret_cast<SimulatorRuntimeTripleCall>(external);
2136      if (::v8::internal::FLAG_trace_sim) {
2137        PrintF(
2138            "Call to host triple returning runtime function %p "
2139            "args %08x, %08x, %08x, %08x, %08x\n",
2140            static_cast<void*>(FUNCTION_ADDR(target)), arg1, arg2, arg3, arg4,
2141            arg5);
2142      }
2143      // arg0 is a hidden argument pointing to the return location, so don't
2144      // pass it to the target function.
2145      ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
2146      if (::v8::internal::FLAG_trace_sim) {
2147        PrintF("Returned { %p, %p, %p }\n", static_cast<void*>(result.x),
2148               static_cast<void*>(result.y), static_cast<void*>(result.z));
2149      }
2150      // Return is passed back in address pointed to by hidden first argument.
2151      ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
2152      *sim_result = result;
2153      set_register(v0, arg0);
2154    } else {
2155      DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2156             redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2157      SimulatorRuntimeCall target =
2158                  reinterpret_cast<SimulatorRuntimeCall>(external);
2159      if (::v8::internal::FLAG_trace_sim) {
2160        PrintF(
2161            "Call to host function at %p "
2162            "args %08x, %08x, %08x, %08x, %08x, %08x\n",
2163            static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
2164            arg4, arg5);
2165      }
2166      int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2167      set_register(v0, static_cast<int32_t>(result));
2168      set_register(v1, static_cast<int32_t>(result >> 32));
2169    }
2170    if (::v8::internal::FLAG_trace_sim) {
2171      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
2172    }
2173    set_register(ra, saved_ra);
2174    set_pc(get_register(ra));
2175
2176  } else if (func == BREAK && code <= kMaxStopCode) {
2177    if (IsWatchpoint(code)) {
2178      PrintWatchpoint(code);
2179    } else {
2180      IncreaseStopCounter(code);
2181      HandleStop(code, instr_.instr());
2182    }
2183  } else {
2184    // All remaining break_ codes, and all traps are handled here.
2185    MipsDebugger dbg(this);
2186    dbg.Debug();
2187  }
2188}
2189
2190
2191// Stop helper functions.
2192bool Simulator::IsWatchpoint(uint32_t code) {
2193  return (code <= kMaxWatchpointCode);
2194}
2195
2196
2197void Simulator::PrintWatchpoint(uint32_t code) {
2198  MipsDebugger dbg(this);
2199  ++break_count_;
2200  PrintF("\n---- break %d marker: %3d  (instr count: %" PRIu64
2201         ") ----------"
2202         "----------------------------------",
2203         code, break_count_, icount_);
2204  dbg.PrintAllRegs();  // Print registers and continue running.
2205}
2206
2207
2208void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2209  // Stop if it is enabled, otherwise go on jumping over the stop
2210  // and the message address.
2211  if (IsEnabledStop(code)) {
2212    MipsDebugger dbg(this);
2213    dbg.Stop(instr);
2214  } else {
2215    set_pc(get_pc() + 2 * Instruction::kInstrSize);
2216  }
2217}
2218
2219
2220bool Simulator::IsStopInstruction(Instruction* instr) {
2221  int32_t func = instr->FunctionFieldRaw();
2222  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2223  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2224}
2225
2226
2227bool Simulator::IsEnabledStop(uint32_t code) {
2228  DCHECK(code <= kMaxStopCode);
2229  DCHECK(code > kMaxWatchpointCode);
2230  return !(watched_stops_[code].count & kStopDisabledBit);
2231}
2232
2233
2234void Simulator::EnableStop(uint32_t code) {
2235  if (!IsEnabledStop(code)) {
2236    watched_stops_[code].count &= ~kStopDisabledBit;
2237  }
2238}
2239
2240
2241void Simulator::DisableStop(uint32_t code) {
2242  if (IsEnabledStop(code)) {
2243    watched_stops_[code].count |= kStopDisabledBit;
2244  }
2245}
2246
2247
2248void Simulator::IncreaseStopCounter(uint32_t code) {
2249  DCHECK(code <= kMaxStopCode);
2250  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
2251    PrintF("Stop counter for code %i has overflowed.\n"
2252           "Enabling this code and reseting the counter to 0.\n", code);
2253    watched_stops_[code].count = 0;
2254    EnableStop(code);
2255  } else {
2256    watched_stops_[code].count++;
2257  }
2258}
2259
2260
2261// Print a stop status.
2262void Simulator::PrintStopInfo(uint32_t code) {
2263  if (code <= kMaxWatchpointCode) {
2264    PrintF("That is a watchpoint, not a stop.\n");
2265    return;
2266  } else if (code > kMaxStopCode) {
2267    PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2268    return;
2269  }
2270  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2271  int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2272  // Don't print the state of unused breakpoints.
2273  if (count != 0) {
2274    if (watched_stops_[code].desc) {
2275      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
2276             code, code, state, count, watched_stops_[code].desc);
2277    } else {
2278      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2279             code, code, state, count);
2280    }
2281  }
2282}
2283
2284
2285void Simulator::SignalException(Exception e) {
2286  V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2287           static_cast<int>(e));
2288}
2289
2290// Min/Max template functions for Double and Single arguments.
2291
2292template <typename T>
2293static T FPAbs(T a);
2294
2295template <>
2296double FPAbs<double>(double a) {
2297  return fabs(a);
2298}
2299
2300template <>
2301float FPAbs<float>(float a) {
2302  return fabsf(a);
2303}
2304
2305template <typename T>
2306static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2307  if (std::isnan(a) && std::isnan(b)) {
2308    result = a;
2309  } else if (std::isnan(a)) {
2310    result = b;
2311  } else if (std::isnan(b)) {
2312    result = a;
2313  } else if (b == a) {
2314    // Handle -0.0 == 0.0 case.
2315    // std::signbit() returns int 0 or 1 so substracting MaxMinKind::kMax
2316    // negates the result.
2317    result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2318  } else {
2319    return false;
2320  }
2321  return true;
2322}
2323
2324template <typename T>
2325static T FPUMin(T a, T b) {
2326  T result;
2327  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2328    return result;
2329  } else {
2330    return b < a ? b : a;
2331  }
2332}
2333
2334template <typename T>
2335static T FPUMax(T a, T b) {
2336  T result;
2337  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2338    return result;
2339  } else {
2340    return b > a ? b : a;
2341  }
2342}
2343
2344template <typename T>
2345static T FPUMinA(T a, T b) {
2346  T result;
2347  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2348    if (FPAbs(a) < FPAbs(b)) {
2349      result = a;
2350    } else if (FPAbs(b) < FPAbs(a)) {
2351      result = b;
2352    } else {
2353      result = a < b ? a : b;
2354    }
2355  }
2356  return result;
2357}
2358
2359template <typename T>
2360static T FPUMaxA(T a, T b) {
2361  T result;
2362  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2363    if (FPAbs(a) > FPAbs(b)) {
2364      result = a;
2365    } else if (FPAbs(b) > FPAbs(a)) {
2366      result = b;
2367    } else {
2368      result = a > b ? a : b;
2369    }
2370  }
2371  return result;
2372}
2373
2374enum class KeepSign : bool { no = false, yes };
2375
2376template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2377                                              int>::type = 0>
2378T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2379  DCHECK(std::isnan(arg));
2380  T qNaN = std::numeric_limits<T>::quiet_NaN();
2381  if (keepSign == KeepSign::yes) {
2382    return std::copysign(qNaN, result);
2383  }
2384  return qNaN;
2385}
2386
2387template <typename T>
2388T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2389  if (std::isnan(first)) {
2390    return FPUCanonalizeNaNArg(result, first, keepSign);
2391  }
2392  return result;
2393}
2394
2395template <typename T, typename... Args>
2396T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2397  if (std::isnan(first)) {
2398    return FPUCanonalizeNaNArg(result, first, keepSign);
2399  }
2400  return FPUCanonalizeNaNArgs(result, keepSign, args...);
2401}
2402
2403template <typename Func, typename T, typename... Args>
2404T FPUCanonalizeOperation(Func f, T first, Args... args) {
2405  return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2406}
2407
2408template <typename Func, typename T, typename... Args>
2409T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2410  T result = f(first, args...);
2411  if (std::isnan(result)) {
2412    result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2413  }
2414  return result;
2415}
2416
2417// Handle execution based on instruction types.
2418
2419void Simulator::DecodeTypeRegisterDRsType() {
2420  double ft, fs, fd;
2421  uint32_t cc, fcsr_cc;
2422  int64_t i64;
2423  fs = get_fpu_register_double(fs_reg());
2424  ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
2425                                           : 0.0;
2426  fd = get_fpu_register_double(fd_reg());
2427  int64_t ft_int = bit_cast<int64_t>(ft);
2428  int64_t fd_int = bit_cast<int64_t>(fd);
2429  cc = instr_.FCccValue();
2430  fcsr_cc = get_fcsr_condition_bit(cc);
2431  switch (instr_.FunctionFieldRaw()) {
2432    case RINT: {
2433      DCHECK(IsMipsArchVariant(kMips32r6));
2434      double result, temp, temp_result;
2435      double upper = std::ceil(fs);
2436      double lower = std::floor(fs);
2437      switch (get_fcsr_rounding_mode()) {
2438        case kRoundToNearest:
2439          if (upper - fs < fs - lower) {
2440            result = upper;
2441          } else if (upper - fs > fs - lower) {
2442            result = lower;
2443          } else {
2444            temp_result = upper / 2;
2445            double reminder = modf(temp_result, &temp);
2446            if (reminder == 0) {
2447              result = upper;
2448            } else {
2449              result = lower;
2450            }
2451          }
2452          break;
2453        case kRoundToZero:
2454          result = (fs > 0 ? lower : upper);
2455          break;
2456        case kRoundToPlusInf:
2457          result = upper;
2458          break;
2459        case kRoundToMinusInf:
2460          result = lower;
2461          break;
2462      }
2463      set_fpu_register_double(fd_reg(), result);
2464      if (result != fs) {
2465        set_fcsr_bit(kFCSRInexactFlagBit, true);
2466      }
2467      break;
2468    }
2469    case SEL:
2470      DCHECK(IsMipsArchVariant(kMips32r6));
2471      set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2472      break;
2473    case SELEQZ_C:
2474      DCHECK(IsMipsArchVariant(kMips32r6));
2475      set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2476      break;
2477    case SELNEZ_C:
2478      DCHECK(IsMipsArchVariant(kMips32r6));
2479      set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2480      break;
2481    case MOVZ_C: {
2482      DCHECK(IsMipsArchVariant(kMips32r2));
2483      if (rt() == 0) {
2484        set_fpu_register_double(fd_reg(), fs);
2485      }
2486      break;
2487    }
2488    case MOVN_C: {
2489      DCHECK(IsMipsArchVariant(kMips32r2));
2490      int32_t rt_reg = instr_.RtValue();
2491      int32_t rt = get_register(rt_reg);
2492      if (rt != 0) {
2493        set_fpu_register_double(fd_reg(), fs);
2494      }
2495      break;
2496    }
2497    case MOVF: {
2498      // Same function field for MOVT.D and MOVF.D
2499      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2500      ft_cc = get_fcsr_condition_bit(ft_cc);
2501      if (instr_.Bit(16)) {  // Read Tf bit.
2502        // MOVT.D
2503        if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2504      } else {
2505        // MOVF.D
2506        if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2507      }
2508      break;
2509    }
2510    case MIN:
2511      DCHECK(IsMipsArchVariant(kMips32r6));
2512      set_fpu_register_double(fd_reg(), FPUMin(ft, fs));
2513      break;
2514    case MAX:
2515      DCHECK(IsMipsArchVariant(kMips32r6));
2516      set_fpu_register_double(fd_reg(), FPUMax(ft, fs));
2517      break;
2518    case MINA:
2519      DCHECK(IsMipsArchVariant(kMips32r6));
2520      set_fpu_register_double(fd_reg(), FPUMinA(ft, fs));
2521      break;
2522    case MAXA:
2523      DCHECK(IsMipsArchVariant(kMips32r6));
2524      set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs));
2525      break;
2526    case ADD_D:
2527      set_fpu_register_double(
2528          fd_reg(),
2529          FPUCanonalizeOperation(
2530              [](double lhs, double rhs) { return lhs + rhs; }, fs, ft));
2531      break;
2532    case SUB_D:
2533      set_fpu_register_double(
2534          fd_reg(),
2535          FPUCanonalizeOperation(
2536              [](double lhs, double rhs) { return lhs - rhs; }, fs, ft));
2537      break;
2538    case MADDF_D:
2539      DCHECK(IsMipsArchVariant(kMips32r6));
2540      set_fpu_register_double(fd_reg(), fd + (fs * ft));
2541      break;
2542    case MSUBF_D:
2543      DCHECK(IsMipsArchVariant(kMips32r6));
2544      set_fpu_register_double(fd_reg(), fd - (fs * ft));
2545      break;
2546    case MUL_D:
2547      set_fpu_register_double(
2548          fd_reg(),
2549          FPUCanonalizeOperation(
2550              [](double lhs, double rhs) { return lhs * rhs; }, fs, ft));
2551      break;
2552    case DIV_D:
2553      set_fpu_register_double(
2554          fd_reg(),
2555          FPUCanonalizeOperation(
2556              [](double lhs, double rhs) { return lhs / rhs; }, fs, ft));
2557      break;
2558    case ABS_D:
2559      set_fpu_register_double(
2560          fd_reg(),
2561          FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs));
2562      break;
2563    case MOV_D:
2564      set_fpu_register_double(fd_reg(), fs);
2565      break;
2566    case NEG_D:
2567      set_fpu_register_double(
2568          fd_reg(), FPUCanonalizeOperation([](double src) { return -src; },
2569                                           KeepSign::yes, fs));
2570      break;
2571    case SQRT_D:
2572      set_fpu_register_double(
2573          fd_reg(),
2574          FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs));
2575      break;
2576    case RSQRT_D:
2577      set_fpu_register_double(
2578          fd_reg(), FPUCanonalizeOperation(
2579                        [](double fs) { return 1.0 / std::sqrt(fs); }, fs));
2580      break;
2581    case RECIP_D:
2582      set_fpu_register_double(
2583          fd_reg(),
2584          FPUCanonalizeOperation([](double fs) { return 1.0 / fs; }, fs));
2585      break;
2586    case C_UN_D:
2587      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2588      break;
2589    case C_EQ_D:
2590      set_fcsr_bit(fcsr_cc, (fs == ft));
2591      break;
2592    case C_UEQ_D:
2593      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2594      break;
2595    case C_OLT_D:
2596      set_fcsr_bit(fcsr_cc, (fs < ft));
2597      break;
2598    case C_ULT_D:
2599      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2600      break;
2601    case C_OLE_D:
2602      set_fcsr_bit(fcsr_cc, (fs <= ft));
2603      break;
2604    case C_ULE_D:
2605      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2606      break;
2607    case CVT_W_D: {  // Convert double to word.
2608      double rounded;
2609      int32_t result;
2610      round_according_to_fcsr(fs, rounded, result, fs);
2611      set_fpu_register_word(fd_reg(), result);
2612      if (set_fcsr_round_error(fs, rounded)) {
2613        set_fpu_register_word_invalid_result(fs, rounded);
2614      }
2615    } break;
2616    case ROUND_W_D:  // Round double to word (round half to even).
2617    {
2618      double rounded = std::floor(fs + 0.5);
2619      int32_t result = static_cast<int32_t>(rounded);
2620      if ((result & 1) != 0 && result - fs == 0.5) {
2621        // If the number is halfway between two integers,
2622        // round to the even one.
2623        result--;
2624      }
2625      set_fpu_register_word(fd_reg(), result);
2626      if (set_fcsr_round_error(fs, rounded)) {
2627        set_fpu_register_word_invalid_result(fs, rounded);
2628      }
2629    } break;
2630    case TRUNC_W_D:  // Truncate double to word (round towards 0).
2631    {
2632      double rounded = trunc(fs);
2633      int32_t result = static_cast<int32_t>(rounded);
2634      set_fpu_register_word(fd_reg(), result);
2635      if (set_fcsr_round_error(fs, rounded)) {
2636        set_fpu_register_word_invalid_result(fs, rounded);
2637      }
2638    } break;
2639    case FLOOR_W_D:  // Round double to word towards negative infinity.
2640    {
2641      double rounded = std::floor(fs);
2642      int32_t result = static_cast<int32_t>(rounded);
2643      set_fpu_register_word(fd_reg(), result);
2644      if (set_fcsr_round_error(fs, rounded)) {
2645        set_fpu_register_word_invalid_result(fs, rounded);
2646      }
2647    } break;
2648    case CEIL_W_D:  // Round double to word towards positive infinity.
2649    {
2650      double rounded = std::ceil(fs);
2651      int32_t result = static_cast<int32_t>(rounded);
2652      set_fpu_register_word(fd_reg(), result);
2653      if (set_fcsr_round_error(fs, rounded)) {
2654        set_fpu_register_word_invalid_result(fs, rounded);
2655      }
2656    } break;
2657    case CVT_S_D:  // Convert double to float (single).
2658      set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2659      break;
2660    case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
2661      if (IsFp64Mode()) {
2662        int64_t result;
2663        double rounded;
2664        round64_according_to_fcsr(fs, rounded, result, fs);
2665        set_fpu_register(fd_reg(), result);
2666        if (set_fcsr_round64_error(fs, rounded)) {
2667          set_fpu_register_invalid_result64(fs, rounded);
2668        }
2669      } else {
2670        UNSUPPORTED();
2671      }
2672      break;
2673      break;
2674    }
2675    case TRUNC_L_D: {  // Mips32r2 instruction.
2676      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2677      double rounded = trunc(fs);
2678      i64 = static_cast<int64_t>(rounded);
2679      if (IsFp64Mode()) {
2680        set_fpu_register(fd_reg(), i64);
2681        if (set_fcsr_round64_error(fs, rounded)) {
2682          set_fpu_register_invalid_result64(fs, rounded);
2683        }
2684      } else {
2685        UNSUPPORTED();
2686      }
2687      break;
2688    }
2689    case ROUND_L_D: {  // Mips32r2 instruction.
2690      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2691      double rounded = std::floor(fs + 0.5);
2692      int64_t result = static_cast<int64_t>(rounded);
2693      if ((result & 1) != 0 && result - fs == 0.5) {
2694        // If the number is halfway between two integers,
2695        // round to the even one.
2696        result--;
2697      }
2698      int64_t i64 = static_cast<int64_t>(result);
2699      if (IsFp64Mode()) {
2700        set_fpu_register(fd_reg(), i64);
2701        if (set_fcsr_round64_error(fs, rounded)) {
2702          set_fpu_register_invalid_result64(fs, rounded);
2703        }
2704      } else {
2705        UNSUPPORTED();
2706      }
2707      break;
2708    }
2709    case FLOOR_L_D: {  // Mips32r2 instruction.
2710      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2711      double rounded = std::floor(fs);
2712      int64_t i64 = static_cast<int64_t>(rounded);
2713      if (IsFp64Mode()) {
2714        set_fpu_register(fd_reg(), i64);
2715        if (set_fcsr_round64_error(fs, rounded)) {
2716          set_fpu_register_invalid_result64(fs, rounded);
2717        }
2718      } else {
2719        UNSUPPORTED();
2720      }
2721      break;
2722    }
2723    case CEIL_L_D: {  // Mips32r2 instruction.
2724      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2725      double rounded = std::ceil(fs);
2726      int64_t i64 = static_cast<int64_t>(rounded);
2727      if (IsFp64Mode()) {
2728        set_fpu_register(fd_reg(), i64);
2729        if (set_fcsr_round64_error(fs, rounded)) {
2730          set_fpu_register_invalid_result64(fs, rounded);
2731        }
2732      } else {
2733        UNSUPPORTED();
2734      }
2735      break;
2736    }
2737    case CLASS_D: {  // Mips32r6 instruction
2738      // Convert double input to uint64_t for easier bit manipulation
2739      uint64_t classed = bit_cast<uint64_t>(fs);
2740
2741      // Extracting sign, exponent and mantissa from the input double
2742      uint32_t sign = (classed >> 63) & 1;
2743      uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
2744      uint64_t mantissa = classed & 0x000fffffffffffff;
2745      uint64_t result;
2746      double dResult;
2747
2748      // Setting flags if input double is negative infinity,
2749      // positive infinity, negative zero or positive zero
2750      bool negInf = (classed == 0xFFF0000000000000);
2751      bool posInf = (classed == 0x7FF0000000000000);
2752      bool negZero = (classed == 0x8000000000000000);
2753      bool posZero = (classed == 0x0000000000000000);
2754
2755      bool signalingNan;
2756      bool quietNan;
2757      bool negSubnorm;
2758      bool posSubnorm;
2759      bool negNorm;
2760      bool posNorm;
2761
2762      // Setting flags if double is NaN
2763      signalingNan = false;
2764      quietNan = false;
2765      if (!negInf && !posInf && exponent == 0x7ff) {
2766        quietNan = ((mantissa & 0x0008000000000000) != 0) &&
2767                   ((mantissa & (0x0008000000000000 - 1)) == 0);
2768        signalingNan = !quietNan;
2769      }
2770
2771      // Setting flags if double is subnormal number
2772      posSubnorm = false;
2773      negSubnorm = false;
2774      if ((exponent == 0) && (mantissa != 0)) {
2775        DCHECK(sign == 0 || sign == 1);
2776        posSubnorm = (sign == 0);
2777        negSubnorm = (sign == 1);
2778      }
2779
2780      // Setting flags if double is normal number
2781      posNorm = false;
2782      negNorm = false;
2783      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2784          !quietNan && !negZero && !posZero) {
2785        DCHECK(sign == 0 || sign == 1);
2786        posNorm = (sign == 0);
2787        negNorm = (sign == 1);
2788      }
2789
2790      // Calculating result according to description of CLASS.D instruction
2791      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2792               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2793               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2794
2795      DCHECK(result != 0);
2796
2797      dResult = bit_cast<double>(result);
2798      set_fpu_register_double(fd_reg(), dResult);
2799
2800      break;
2801    }
2802    case C_F_D: {
2803      set_fcsr_bit(fcsr_cc, false);
2804      break;
2805    }
2806    default:
2807      UNREACHABLE();
2808  }
2809}
2810
2811
2812void Simulator::DecodeTypeRegisterWRsType() {
2813  float fs = get_fpu_register_float(fs_reg());
2814  float ft = get_fpu_register_float(ft_reg());
2815  int32_t alu_out = 0x12345678;
2816  switch (instr_.FunctionFieldRaw()) {
2817    case CVT_S_W:  // Convert word to float (single).
2818      alu_out = get_fpu_register_signed_word(fs_reg());
2819      set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
2820      break;
2821    case CVT_D_W:  // Convert word to double.
2822      alu_out = get_fpu_register_signed_word(fs_reg());
2823      set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
2824      break;
2825    case CMP_AF:
2826      set_fpu_register_word(fd_reg(), 0);
2827      break;
2828    case CMP_UN:
2829      if (std::isnan(fs) || std::isnan(ft)) {
2830        set_fpu_register_word(fd_reg(), -1);
2831      } else {
2832        set_fpu_register_word(fd_reg(), 0);
2833      }
2834      break;
2835    case CMP_EQ:
2836      if (fs == ft) {
2837        set_fpu_register_word(fd_reg(), -1);
2838      } else {
2839        set_fpu_register_word(fd_reg(), 0);
2840      }
2841      break;
2842    case CMP_UEQ:
2843      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
2844        set_fpu_register_word(fd_reg(), -1);
2845      } else {
2846        set_fpu_register_word(fd_reg(), 0);
2847      }
2848      break;
2849    case CMP_LT:
2850      if (fs < ft) {
2851        set_fpu_register_word(fd_reg(), -1);
2852      } else {
2853        set_fpu_register_word(fd_reg(), 0);
2854      }
2855      break;
2856    case CMP_ULT:
2857      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
2858        set_fpu_register_word(fd_reg(), -1);
2859      } else {
2860        set_fpu_register_word(fd_reg(), 0);
2861      }
2862      break;
2863    case CMP_LE:
2864      if (fs <= ft) {
2865        set_fpu_register_word(fd_reg(), -1);
2866      } else {
2867        set_fpu_register_word(fd_reg(), 0);
2868      }
2869      break;
2870    case CMP_ULE:
2871      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
2872        set_fpu_register_word(fd_reg(), -1);
2873      } else {
2874        set_fpu_register_word(fd_reg(), 0);
2875      }
2876      break;
2877    case CMP_OR:
2878      if (!std::isnan(fs) && !std::isnan(ft)) {
2879        set_fpu_register_word(fd_reg(), -1);
2880      } else {
2881        set_fpu_register_word(fd_reg(), 0);
2882      }
2883      break;
2884    case CMP_UNE:
2885      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
2886        set_fpu_register_word(fd_reg(), -1);
2887      } else {
2888        set_fpu_register_word(fd_reg(), 0);
2889      }
2890      break;
2891    case CMP_NE:
2892      if (fs != ft) {
2893        set_fpu_register_word(fd_reg(), -1);
2894      } else {
2895        set_fpu_register_word(fd_reg(), 0);
2896      }
2897      break;
2898    default:
2899      UNREACHABLE();
2900  }
2901}
2902
2903
2904void Simulator::DecodeTypeRegisterSRsType() {
2905  float fs, ft, fd;
2906  fs = get_fpu_register_float(fs_reg());
2907  ft = get_fpu_register_float(ft_reg());
2908  fd = get_fpu_register_float(fd_reg());
2909  int32_t ft_int = bit_cast<int32_t>(ft);
2910  int32_t fd_int = bit_cast<int32_t>(fd);
2911  uint32_t cc, fcsr_cc;
2912  cc = instr_.FCccValue();
2913  fcsr_cc = get_fcsr_condition_bit(cc);
2914  switch (instr_.FunctionFieldRaw()) {
2915    case RINT: {
2916      DCHECK(IsMipsArchVariant(kMips32r6));
2917      float result, temp_result;
2918      double temp;
2919      float upper = std::ceil(fs);
2920      float lower = std::floor(fs);
2921      switch (get_fcsr_rounding_mode()) {
2922        case kRoundToNearest:
2923          if (upper - fs < fs - lower) {
2924            result = upper;
2925          } else if (upper - fs > fs - lower) {
2926            result = lower;
2927          } else {
2928            temp_result = upper / 2;
2929            float reminder = modf(temp_result, &temp);
2930            if (reminder == 0) {
2931              result = upper;
2932            } else {
2933              result = lower;
2934            }
2935          }
2936          break;
2937        case kRoundToZero:
2938          result = (fs > 0 ? lower : upper);
2939          break;
2940        case kRoundToPlusInf:
2941          result = upper;
2942          break;
2943        case kRoundToMinusInf:
2944          result = lower;
2945          break;
2946      }
2947      set_fpu_register_float(fd_reg(), result);
2948      if (result != fs) {
2949        set_fcsr_bit(kFCSRInexactFlagBit, true);
2950      }
2951      break;
2952    }
2953    case ADD_S:
2954      set_fpu_register_float(
2955          fd_reg(),
2956          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
2957                                 fs, ft));
2958      break;
2959    case SUB_S:
2960      set_fpu_register_float(
2961          fd_reg(),
2962          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
2963                                 fs, ft));
2964      break;
2965    case MADDF_S:
2966      DCHECK(IsMipsArchVariant(kMips32r6));
2967      set_fpu_register_float(fd_reg(), fd + (fs * ft));
2968      break;
2969    case MSUBF_S:
2970      DCHECK(IsMipsArchVariant(kMips32r6));
2971      set_fpu_register_float(fd_reg(), fd - (fs * ft));
2972      break;
2973    case MUL_S:
2974      set_fpu_register_float(
2975          fd_reg(),
2976          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
2977                                 fs, ft));
2978      break;
2979    case DIV_S:
2980      set_fpu_register_float(
2981          fd_reg(),
2982          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
2983                                 fs, ft));
2984      break;
2985    case ABS_S:
2986      set_fpu_register_float(
2987          fd_reg(),
2988          FPUCanonalizeOperation([](float fs) { return FPAbs(fs); }, fs));
2989      break;
2990    case MOV_S:
2991      set_fpu_register_float(fd_reg(), fs);
2992      break;
2993    case NEG_S:
2994      set_fpu_register_float(
2995          fd_reg(), FPUCanonalizeOperation([](float src) { return -src; },
2996                                           KeepSign::yes, fs));
2997      break;
2998    case SQRT_S:
2999      set_fpu_register_float(
3000          fd_reg(),
3001          FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs));
3002      break;
3003    case RSQRT_S:
3004      set_fpu_register_float(
3005          fd_reg(), FPUCanonalizeOperation(
3006                        [](float src) { return 1.0 / std::sqrt(src); }, fs));
3007      break;
3008    case RECIP_S:
3009      set_fpu_register_float(
3010          fd_reg(),
3011          FPUCanonalizeOperation([](float src) { return 1.0 / src; }, fs));
3012      break;
3013    case C_F_D:
3014      set_fcsr_bit(fcsr_cc, false);
3015      break;
3016    case C_UN_D:
3017      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
3018      break;
3019    case C_EQ_D:
3020      set_fcsr_bit(fcsr_cc, (fs == ft));
3021      break;
3022    case C_UEQ_D:
3023      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
3024      break;
3025    case C_OLT_D:
3026      set_fcsr_bit(fcsr_cc, (fs < ft));
3027      break;
3028    case C_ULT_D:
3029      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3030      break;
3031    case C_OLE_D:
3032      set_fcsr_bit(fcsr_cc, (fs <= ft));
3033      break;
3034    case C_ULE_D:
3035      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3036      break;
3037    case CVT_D_S:
3038      set_fpu_register_double(fd_reg(), static_cast<double>(fs));
3039      break;
3040    case SEL:
3041      DCHECK(IsMipsArchVariant(kMips32r6));
3042      set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3043      break;
3044    case CLASS_S: {  // Mips32r6 instruction
3045      // Convert float input to uint32_t for easier bit manipulation
3046      float fs = get_fpu_register_float(fs_reg());
3047      uint32_t classed = bit_cast<uint32_t>(fs);
3048
3049      // Extracting sign, exponent and mantissa from the input float
3050      uint32_t sign = (classed >> 31) & 1;
3051      uint32_t exponent = (classed >> 23) & 0x000000ff;
3052      uint32_t mantissa = classed & 0x007fffff;
3053      uint32_t result;
3054      float fResult;
3055
3056      // Setting flags if input float is negative infinity,
3057      // positive infinity, negative zero or positive zero
3058      bool negInf = (classed == 0xFF800000);
3059      bool posInf = (classed == 0x7F800000);
3060      bool negZero = (classed == 0x80000000);
3061      bool posZero = (classed == 0x00000000);
3062
3063      bool signalingNan;
3064      bool quietNan;
3065      bool negSubnorm;
3066      bool posSubnorm;
3067      bool negNorm;
3068      bool posNorm;
3069
3070      // Setting flags if float is NaN
3071      signalingNan = false;
3072      quietNan = false;
3073      if (!negInf && !posInf && (exponent == 0xff)) {
3074        quietNan = ((mantissa & 0x00200000) == 0) &&
3075                   ((mantissa & (0x00200000 - 1)) == 0);
3076        signalingNan = !quietNan;
3077      }
3078
3079      // Setting flags if float is subnormal number
3080      posSubnorm = false;
3081      negSubnorm = false;
3082      if ((exponent == 0) && (mantissa != 0)) {
3083        DCHECK(sign == 0 || sign == 1);
3084        posSubnorm = (sign == 0);
3085        negSubnorm = (sign == 1);
3086      }
3087
3088      // Setting flags if float is normal number
3089      posNorm = false;
3090      negNorm = false;
3091      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3092          !quietNan && !negZero && !posZero) {
3093        DCHECK(sign == 0 || sign == 1);
3094        posNorm = (sign == 0);
3095        negNorm = (sign == 1);
3096      }
3097
3098      // Calculating result according to description of CLASS.S instruction
3099      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3100               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3101               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3102
3103      DCHECK(result != 0);
3104
3105      fResult = bit_cast<float>(result);
3106      set_fpu_register_float(fd_reg(), fResult);
3107
3108      break;
3109    }
3110    case SELEQZ_C:
3111      DCHECK(IsMipsArchVariant(kMips32r6));
3112      set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
3113                                           ? get_fpu_register_float(fs_reg())
3114                                           : 0.0);
3115      break;
3116    case SELNEZ_C:
3117      DCHECK(IsMipsArchVariant(kMips32r6));
3118      set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
3119                                           ? get_fpu_register_float(fs_reg())
3120                                           : 0.0);
3121      break;
3122    case MOVZ_C: {
3123      DCHECK(IsMipsArchVariant(kMips32r2));
3124      if (rt() == 0) {
3125        set_fpu_register_float(fd_reg(), fs);
3126      }
3127      break;
3128    }
3129    case MOVN_C: {
3130      DCHECK(IsMipsArchVariant(kMips32r2));
3131      if (rt() != 0) {
3132        set_fpu_register_float(fd_reg(), fs);
3133      }
3134      break;
3135    }
3136    case MOVF: {
3137      // Same function field for MOVT.D and MOVF.D
3138      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3139      ft_cc = get_fcsr_condition_bit(ft_cc);
3140
3141      if (instr_.Bit(16)) {  // Read Tf bit.
3142        // MOVT.D
3143        if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3144      } else {
3145        // MOVF.D
3146        if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3147      }
3148      break;
3149    }
3150    case TRUNC_W_S: {  // Truncate single to word (round towards 0).
3151      float rounded = trunc(fs);
3152      int32_t result = static_cast<int32_t>(rounded);
3153      set_fpu_register_word(fd_reg(), result);
3154      if (set_fcsr_round_error(fs, rounded)) {
3155        set_fpu_register_word_invalid_result(fs, rounded);
3156      }
3157    } break;
3158    case TRUNC_L_S: {  // Mips32r2 instruction.
3159      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3160      float rounded = trunc(fs);
3161      int64_t i64 = static_cast<int64_t>(rounded);
3162      if (IsFp64Mode()) {
3163        set_fpu_register(fd_reg(), i64);
3164        if (set_fcsr_round64_error(fs, rounded)) {
3165          set_fpu_register_invalid_result64(fs, rounded);
3166        }
3167      } else {
3168        UNSUPPORTED();
3169      }
3170      break;
3171    }
3172    case FLOOR_W_S:  // Round double to word towards negative infinity.
3173    {
3174      float rounded = std::floor(fs);
3175      int32_t result = static_cast<int32_t>(rounded);
3176      set_fpu_register_word(fd_reg(), result);
3177      if (set_fcsr_round_error(fs, rounded)) {
3178        set_fpu_register_word_invalid_result(fs, rounded);
3179      }
3180    } break;
3181    case FLOOR_L_S: {  // Mips32r2 instruction.
3182      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3183      float rounded = std::floor(fs);
3184      int64_t i64 = static_cast<int64_t>(rounded);
3185      if (IsFp64Mode()) {
3186        set_fpu_register(fd_reg(), i64);
3187        if (set_fcsr_round64_error(fs, rounded)) {
3188          set_fpu_register_invalid_result64(fs, rounded);
3189        }
3190      } else {
3191        UNSUPPORTED();
3192      }
3193      break;
3194    }
3195    case ROUND_W_S: {
3196      float rounded = std::floor(fs + 0.5);
3197      int32_t result = static_cast<int32_t>(rounded);
3198      if ((result & 1) != 0 && result - fs == 0.5) {
3199        // If the number is halfway between two integers,
3200        // round to the even one.
3201        result--;
3202      }
3203      set_fpu_register_word(fd_reg(), result);
3204      if (set_fcsr_round_error(fs, rounded)) {
3205        set_fpu_register_word_invalid_result(fs, rounded);
3206      }
3207      break;
3208    }
3209    case ROUND_L_S: {  // Mips32r2 instruction.
3210      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3211      float rounded = std::floor(fs + 0.5);
3212      int64_t result = static_cast<int64_t>(rounded);
3213      if ((result & 1) != 0 && result - fs == 0.5) {
3214        // If the number is halfway between two integers,
3215        // round to the even one.
3216        result--;
3217      }
3218      int64_t i64 = static_cast<int64_t>(result);
3219      if (IsFp64Mode()) {
3220        set_fpu_register(fd_reg(), i64);
3221        if (set_fcsr_round64_error(fs, rounded)) {
3222          set_fpu_register_invalid_result64(fs, rounded);
3223        }
3224      } else {
3225        UNSUPPORTED();
3226      }
3227      break;
3228    }
3229    case CEIL_W_S:  // Round double to word towards positive infinity.
3230    {
3231      float rounded = std::ceil(fs);
3232      int32_t result = static_cast<int32_t>(rounded);
3233      set_fpu_register_word(fd_reg(), result);
3234      if (set_fcsr_round_error(fs, rounded)) {
3235        set_fpu_register_word_invalid_result(fs, rounded);
3236      }
3237    } break;
3238    case CEIL_L_S: {  // Mips32r2 instruction.
3239      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3240      float rounded = std::ceil(fs);
3241      int64_t i64 = static_cast<int64_t>(rounded);
3242      if (IsFp64Mode()) {
3243        set_fpu_register(fd_reg(), i64);
3244        if (set_fcsr_round64_error(fs, rounded)) {
3245          set_fpu_register_invalid_result64(fs, rounded);
3246        }
3247      } else {
3248        UNSUPPORTED();
3249      }
3250      break;
3251    }
3252    case MIN:
3253      DCHECK(IsMipsArchVariant(kMips32r6));
3254      set_fpu_register_float(fd_reg(), FPUMin(ft, fs));
3255      break;
3256    case MAX:
3257      DCHECK(IsMipsArchVariant(kMips32r6));
3258      set_fpu_register_float(fd_reg(), FPUMax(ft, fs));
3259      break;
3260    case MINA:
3261      DCHECK(IsMipsArchVariant(kMips32r6));
3262      set_fpu_register_float(fd_reg(), FPUMinA(ft, fs));
3263      break;
3264    case MAXA:
3265      DCHECK(IsMipsArchVariant(kMips32r6));
3266      set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs));
3267      break;
3268    case CVT_L_S: {
3269      if (IsFp64Mode()) {
3270        int64_t result;
3271        float rounded;
3272        round64_according_to_fcsr(fs, rounded, result, fs);
3273        set_fpu_register(fd_reg(), result);
3274        if (set_fcsr_round64_error(fs, rounded)) {
3275          set_fpu_register_invalid_result64(fs, rounded);
3276        }
3277      } else {
3278        UNSUPPORTED();
3279      }
3280      break;
3281    }
3282    case CVT_W_S: {
3283      float rounded;
3284      int32_t result;
3285      round_according_to_fcsr(fs, rounded, result, fs);
3286      set_fpu_register_word(fd_reg(), result);
3287      if (set_fcsr_round_error(fs, rounded)) {
3288        set_fpu_register_word_invalid_result(fs, rounded);
3289      }
3290      break;
3291    }
3292    default:
3293      // CVT_W_S CVT_L_S  ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3294      // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3295      UNREACHABLE();
3296  }
3297}
3298
3299
3300void Simulator::DecodeTypeRegisterLRsType() {
3301  double fs = get_fpu_register_double(fs_reg());
3302  double ft = get_fpu_register_double(ft_reg());
3303  switch (instr_.FunctionFieldRaw()) {
3304    case CVT_D_L:  // Mips32r2 instruction.
3305      // Watch the signs here, we want 2 32-bit vals
3306      // to make a sign-64.
3307      int64_t i64;
3308      if (IsFp64Mode()) {
3309        i64 = get_fpu_register(fs_reg());
3310      } else {
3311        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3312        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3313      }
3314      set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3315      break;
3316    case CVT_S_L:
3317      if (IsFp64Mode()) {
3318        i64 = get_fpu_register(fs_reg());
3319      } else {
3320        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3321        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3322      }
3323      set_fpu_register_float(fd_reg(), static_cast<float>(i64));
3324      break;
3325    case CMP_AF:  // Mips64r6 CMP.D instructions.
3326      set_fpu_register(fd_reg(), 0);
3327      break;
3328    case CMP_UN:
3329      if (std::isnan(fs) || std::isnan(ft)) {
3330        set_fpu_register(fd_reg(), -1);
3331      } else {
3332        set_fpu_register(fd_reg(), 0);
3333      }
3334      break;
3335    case CMP_EQ:
3336      if (fs == ft) {
3337        set_fpu_register(fd_reg(), -1);
3338      } else {
3339        set_fpu_register(fd_reg(), 0);
3340      }
3341      break;
3342    case CMP_UEQ:
3343      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3344        set_fpu_register(fd_reg(), -1);
3345      } else {
3346        set_fpu_register(fd_reg(), 0);
3347      }
3348      break;
3349    case CMP_LT:
3350      if (fs < ft) {
3351        set_fpu_register(fd_reg(), -1);
3352      } else {
3353        set_fpu_register(fd_reg(), 0);
3354      }
3355      break;
3356    case CMP_ULT:
3357      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3358        set_fpu_register(fd_reg(), -1);
3359      } else {
3360        set_fpu_register(fd_reg(), 0);
3361      }
3362      break;
3363    case CMP_LE:
3364      if (fs <= ft) {
3365        set_fpu_register(fd_reg(), -1);
3366      } else {
3367        set_fpu_register(fd_reg(), 0);
3368      }
3369      break;
3370    case CMP_ULE:
3371      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3372        set_fpu_register(fd_reg(), -1);
3373      } else {
3374        set_fpu_register(fd_reg(), 0);
3375      }
3376      break;
3377    case CMP_OR:
3378      if (!std::isnan(fs) && !std::isnan(ft)) {
3379        set_fpu_register(fd_reg(), -1);
3380      } else {
3381        set_fpu_register(fd_reg(), 0);
3382      }
3383      break;
3384    case CMP_UNE:
3385      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3386        set_fpu_register(fd_reg(), -1);
3387      } else {
3388        set_fpu_register(fd_reg(), 0);
3389      }
3390      break;
3391    case CMP_NE:
3392      if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3393        set_fpu_register(fd_reg(), -1);
3394      } else {
3395        set_fpu_register(fd_reg(), 0);
3396      }
3397      break;
3398    default:
3399      UNREACHABLE();
3400  }
3401}
3402
3403
3404void Simulator::DecodeTypeRegisterCOP1() {
3405  switch (instr_.RsFieldRaw()) {
3406    case CFC1:
3407      // At the moment only FCSR is supported.
3408      DCHECK(fs_reg() == kFCSRRegister);
3409      set_register(rt_reg(), FCSR_);
3410      break;
3411    case MFC1:
3412      set_register(rt_reg(), get_fpu_register_word(fs_reg()));
3413      break;
3414    case MFHC1:
3415      if (IsFp64Mode()) {
3416        set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3417      } else {
3418        set_register(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3419      }
3420      break;
3421    case CTC1: {
3422      // At the moment only FCSR is supported.
3423      DCHECK(fs_reg() == kFCSRRegister);
3424      int32_t reg = registers_[rt_reg()];
3425      if (IsMipsArchVariant(kMips32r6)) {
3426        FCSR_ = reg | kFCSRNaN2008FlagMask;
3427      } else {
3428        DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3429        FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3430      }
3431      break;
3432    }
3433    case MTC1:
3434      // Hardware writes upper 32-bits to zero on mtc1.
3435      set_fpu_register_hi_word(fs_reg(), 0);
3436      set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3437      break;
3438    case MTHC1:
3439      if (IsFp64Mode()) {
3440        set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3441      } else {
3442        set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3443      }
3444      break;
3445    case S: {
3446      DecodeTypeRegisterSRsType();
3447      break;
3448    }
3449    case D:
3450      DecodeTypeRegisterDRsType();
3451      break;
3452    case W:
3453      DecodeTypeRegisterWRsType();
3454      break;
3455    case L:
3456      DecodeTypeRegisterLRsType();
3457      break;
3458    case PS:
3459      // Not implemented.
3460      UNREACHABLE();
3461    default:
3462      UNREACHABLE();
3463  }
3464}
3465
3466
3467void Simulator::DecodeTypeRegisterCOP1X() {
3468  switch (instr_.FunctionFieldRaw()) {
3469    case MADD_S: {
3470      DCHECK(IsMipsArchVariant(kMips32r2));
3471      float fr, ft, fs;
3472      fr = get_fpu_register_float(fr_reg());
3473      fs = get_fpu_register_float(fs_reg());
3474      ft = get_fpu_register_float(ft_reg());
3475      set_fpu_register_float(fd_reg(), fs * ft + fr);
3476      break;
3477    }
3478    case MSUB_S: {
3479      DCHECK(IsMipsArchVariant(kMips32r2));
3480      float fr, ft, fs;
3481      fr = get_fpu_register_float(fr_reg());
3482      fs = get_fpu_register_float(fs_reg());
3483      ft = get_fpu_register_float(ft_reg());
3484      set_fpu_register_float(fd_reg(), fs * ft - fr);
3485      break;
3486    }
3487    case MADD_D: {
3488      DCHECK(IsMipsArchVariant(kMips32r2));
3489      double fr, ft, fs;
3490      fr = get_fpu_register_double(fr_reg());
3491      fs = get_fpu_register_double(fs_reg());
3492      ft = get_fpu_register_double(ft_reg());
3493      set_fpu_register_double(fd_reg(), fs * ft + fr);
3494      break;
3495    }
3496    case MSUB_D: {
3497      DCHECK(IsMipsArchVariant(kMips32r2));
3498      double fr, ft, fs;
3499      fr = get_fpu_register_double(fr_reg());
3500      fs = get_fpu_register_double(fs_reg());
3501      ft = get_fpu_register_double(ft_reg());
3502      set_fpu_register_double(fd_reg(), fs * ft - fr);
3503      break;
3504    }
3505    default:
3506      UNREACHABLE();
3507  }
3508}
3509
3510
3511void Simulator::DecodeTypeRegisterSPECIAL() {
3512  int64_t alu_out = 0x12345678;
3513  int64_t i64hilo = 0;
3514  uint64_t u64hilo = 0;
3515  bool do_interrupt = false;
3516
3517  switch (instr_.FunctionFieldRaw()) {
3518    case SELEQZ_S:
3519      DCHECK(IsMipsArchVariant(kMips32r6));
3520      set_register(rd_reg(), rt() == 0 ? rs() : 0);
3521      break;
3522    case SELNEZ_S:
3523      DCHECK(IsMipsArchVariant(kMips32r6));
3524      set_register(rd_reg(), rt() != 0 ? rs() : 0);
3525      break;
3526    case JR: {
3527      int32_t next_pc = rs();
3528      int32_t current_pc = get_pc();
3529      Instruction* branch_delay_instr =
3530          reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3531      BranchDelayInstructionDecode(branch_delay_instr);
3532      set_pc(next_pc);
3533      pc_modified_ = true;
3534      break;
3535    }
3536    case JALR: {
3537      int32_t next_pc = rs();
3538      int32_t return_addr_reg = rd_reg();
3539      int32_t current_pc = get_pc();
3540      Instruction* branch_delay_instr =
3541          reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3542      BranchDelayInstructionDecode(branch_delay_instr);
3543      set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3544      set_pc(next_pc);
3545      pc_modified_ = true;
3546      break;
3547    }
3548    case SLL:
3549      alu_out = rt() << sa();
3550      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3551      break;
3552    case SRL:
3553      if (rs_reg() == 0) {
3554        // Regular logical right shift of a word by a fixed number of
3555        // bits instruction. RS field is always equal to 0.
3556        alu_out = rt_u() >> sa();
3557      } else {
3558        // Logical right-rotate of a word by a fixed number of bits. This
3559        // is special case of SRL instruction, added in MIPS32 Release 2.
3560        // RS field is equal to 00001.
3561        alu_out = base::bits::RotateRight32(rt_u(), sa());
3562      }
3563      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3564      break;
3565    case SRA:
3566      alu_out = rt() >> sa();
3567      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3568      break;
3569    case SLLV:
3570      alu_out = rt() << rs();
3571      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3572      break;
3573    case SRLV:
3574      if (sa() == 0) {
3575        // Regular logical right-shift of a word by a variable number of
3576        // bits instruction. SA field is always equal to 0.
3577        alu_out = rt_u() >> rs();
3578      } else {
3579        // Logical right-rotate of a word by a variable number of bits.
3580        // This is special case od SRLV instruction, added in MIPS32
3581        // Release 2. SA field is equal to 00001.
3582        alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3583      }
3584      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3585      break;
3586    case SRAV:
3587      SetResult(rd_reg(), rt() >> rs());
3588      break;
3589    case LSA: {
3590      DCHECK(IsMipsArchVariant(kMips32r6));
3591      int8_t sa = lsa_sa() + 1;
3592      int32_t _rt = rt();
3593      int32_t _rs = rs();
3594      int32_t res = _rs << sa;
3595      res += _rt;
3596      DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3597      SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3598      break;
3599    }
3600    case MFHI:  // MFHI == CLZ on R6.
3601      if (!IsMipsArchVariant(kMips32r6)) {
3602        DCHECK(sa() == 0);
3603        alu_out = get_register(HI);
3604      } else {
3605        // MIPS spec: If no bits were set in GPR rs, the result written to
3606        // GPR rd is 32.
3607        DCHECK(sa() == 1);
3608        alu_out = base::bits::CountLeadingZeros32(rs_u());
3609      }
3610      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3611      break;
3612    case MFLO:
3613      alu_out = get_register(LO);
3614      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3615      break;
3616    // Instructions using HI and LO registers.
3617    case MULT:
3618      i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3619      if (!IsMipsArchVariant(kMips32r6)) {
3620        set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3621        set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3622      } else {
3623        switch (sa()) {
3624          case MUL_OP:
3625            set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3626            break;
3627          case MUH_OP:
3628            set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3629            break;
3630          default:
3631            UNIMPLEMENTED_MIPS();
3632            break;
3633        }
3634      }
3635      break;
3636    case MULTU:
3637      u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3638      if (!IsMipsArchVariant(kMips32r6)) {
3639        set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3640        set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3641      } else {
3642        switch (sa()) {
3643          case MUL_OP:
3644            set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3645            break;
3646          case MUH_OP:
3647            set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3648            break;
3649          default:
3650            UNIMPLEMENTED_MIPS();
3651            break;
3652        }
3653      }
3654      break;
3655    case DIV:
3656      if (IsMipsArchVariant(kMips32r6)) {
3657        switch (sa()) {
3658          case DIV_OP:
3659            if (rs() == INT_MIN && rt() == -1) {
3660              set_register(rd_reg(), INT_MIN);
3661            } else if (rt() != 0) {
3662              set_register(rd_reg(), rs() / rt());
3663            }
3664            break;
3665          case MOD_OP:
3666            if (rs() == INT_MIN && rt() == -1) {
3667              set_register(rd_reg(), 0);
3668            } else if (rt() != 0) {
3669              set_register(rd_reg(), rs() % rt());
3670            }
3671            break;
3672          default:
3673            UNIMPLEMENTED_MIPS();
3674            break;
3675        }
3676      } else {
3677        // Divide by zero and overflow was not checked in the
3678        // configuration step - div and divu do not raise exceptions. On
3679        // division by 0 the result will be UNPREDICTABLE. On overflow
3680        // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3681        if (rs() == INT_MIN && rt() == -1) {
3682          set_register(LO, INT_MIN);
3683          set_register(HI, 0);
3684        } else if (rt() != 0) {
3685          set_register(LO, rs() / rt());
3686          set_register(HI, rs() % rt());
3687        }
3688      }
3689      break;
3690    case DIVU:
3691      if (IsMipsArchVariant(kMips32r6)) {
3692        switch (sa()) {
3693          case DIV_OP:
3694            if (rt_u() != 0) {
3695              set_register(rd_reg(), rs_u() / rt_u());
3696            }
3697            break;
3698          case MOD_OP:
3699            if (rt_u() != 0) {
3700              set_register(rd_reg(), rs_u() % rt_u());
3701            }
3702            break;
3703          default:
3704            UNIMPLEMENTED_MIPS();
3705            break;
3706        }
3707      } else {
3708        if (rt_u() != 0) {
3709          set_register(LO, rs_u() / rt_u());
3710          set_register(HI, rs_u() % rt_u());
3711        }
3712      }
3713      break;
3714    case ADD:
3715      if (HaveSameSign(rs(), rt())) {
3716        if (rs() > 0) {
3717          if (rs() <= (Registers::kMaxValue - rt())) {
3718            SignalException(kIntegerOverflow);
3719          }
3720        } else if (rs() < 0) {
3721          if (rs() >= (Registers::kMinValue - rt())) {
3722            SignalException(kIntegerUnderflow);
3723          }
3724        }
3725      }
3726      SetResult(rd_reg(), rs() + rt());
3727      break;
3728    case ADDU:
3729      SetResult(rd_reg(), rs() + rt());
3730      break;
3731    case SUB:
3732      if (!HaveSameSign(rs(), rt())) {
3733        if (rs() > 0) {
3734          if (rs() <= (Registers::kMaxValue + rt())) {
3735            SignalException(kIntegerOverflow);
3736          }
3737        } else if (rs() < 0) {
3738          if (rs() >= (Registers::kMinValue + rt())) {
3739            SignalException(kIntegerUnderflow);
3740          }
3741        }
3742      }
3743      SetResult(rd_reg(), rs() - rt());
3744      break;
3745    case SUBU:
3746      SetResult(rd_reg(), rs() - rt());
3747      break;
3748    case AND:
3749      SetResult(rd_reg(), rs() & rt());
3750      break;
3751    case OR:
3752      SetResult(rd_reg(), rs() | rt());
3753      break;
3754    case XOR:
3755      SetResult(rd_reg(), rs() ^ rt());
3756      break;
3757    case NOR:
3758      SetResult(rd_reg(), ~(rs() | rt()));
3759      break;
3760    case SLT:
3761      SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3762      break;
3763    case SLTU:
3764      SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3765      break;
3766    // Break and trap instructions.
3767    case BREAK:
3768      do_interrupt = true;
3769      break;
3770    case TGE:
3771      do_interrupt = rs() >= rt();
3772      break;
3773    case TGEU:
3774      do_interrupt = rs_u() >= rt_u();
3775      break;
3776    case TLT:
3777      do_interrupt = rs() < rt();
3778      break;
3779    case TLTU:
3780      do_interrupt = rs_u() < rt_u();
3781      break;
3782    case TEQ:
3783      do_interrupt = rs() == rt();
3784      break;
3785    case TNE:
3786      do_interrupt = rs() != rt();
3787      break;
3788    case SYNC:
3789      // TODO(palfia): Ignore sync instruction for now.
3790      break;
3791    // Conditional moves.
3792    case MOVN:
3793      if (rt()) {
3794        set_register(rd_reg(), rs());
3795        TraceRegWr(rs());
3796      }
3797      break;
3798    case MOVCI: {
3799      uint32_t cc = instr_.FBccValue();
3800      uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3801      if (instr_.Bit(16)) {  // Read Tf bit.
3802        if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3803      } else {
3804        if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3805      }
3806      break;
3807    }
3808    case MOVZ:
3809      if (!rt()) {
3810        set_register(rd_reg(), rs());
3811        TraceRegWr(rs());
3812      }
3813      break;
3814    default:
3815      UNREACHABLE();
3816  }
3817  if (do_interrupt) {
3818    SoftwareInterrupt();
3819  }
3820}
3821
3822
3823void Simulator::DecodeTypeRegisterSPECIAL2() {
3824  int32_t alu_out;
3825  switch (instr_.FunctionFieldRaw()) {
3826    case MUL:
3827      // Only the lower 32 bits are kept.
3828      alu_out = rs_u() * rt_u();
3829      // HI and LO are UNPREDICTABLE after the operation.
3830      set_register(LO, Unpredictable);
3831      set_register(HI, Unpredictable);
3832      break;
3833    case CLZ:
3834      // MIPS32 spec: If no bits were set in GPR rs, the result written to
3835      // GPR rd is 32.
3836      alu_out = base::bits::CountLeadingZeros32(rs_u());
3837      break;
3838    default:
3839      alu_out = 0x12345678;
3840      UNREACHABLE();
3841  }
3842  SetResult(rd_reg(), alu_out);
3843}
3844
3845
3846void Simulator::DecodeTypeRegisterSPECIAL3() {
3847  int32_t alu_out;
3848  switch (instr_.FunctionFieldRaw()) {
3849    case INS: {  // Mips32r2 instruction.
3850      // Interpret rd field as 5-bit msb of insert.
3851      uint16_t msb = rd_reg();
3852      // Interpret sa field as 5-bit lsb of insert.
3853      uint16_t lsb = sa();
3854      uint16_t size = msb - lsb + 1;
3855      uint32_t mask = (1 << size) - 1;
3856      alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3857      // Ins instr leaves result in Rt, rather than Rd.
3858      SetResult(rt_reg(), alu_out);
3859      break;
3860    }
3861    case EXT: {  // Mips32r2 instruction.
3862      // Interpret rd field as 5-bit msb of extract.
3863      uint16_t msb = rd_reg();
3864      // Interpret sa field as 5-bit lsb of extract.
3865      uint16_t lsb = sa();
3866      uint16_t size = msb + 1;
3867      uint32_t mask = (1 << size) - 1;
3868      alu_out = (rs_u() & (mask << lsb)) >> lsb;
3869      SetResult(rt_reg(), alu_out);
3870      break;
3871    }
3872    case BSHFL: {
3873      int sa = instr_.SaFieldRaw() >> kSaShift;
3874      switch (sa) {
3875        case BITSWAP: {
3876          uint32_t input = static_cast<uint32_t>(rt());
3877          uint32_t output = 0;
3878          uint8_t i_byte, o_byte;
3879
3880          // Reverse the bit in byte for each individual byte
3881          for (int i = 0; i < 4; i++) {
3882            output = output >> 8;
3883            i_byte = input & 0xff;
3884
3885            // Fast way to reverse bits in byte
3886            // Devised by Sean Anderson, July 13, 2001
3887            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3888                                           (i_byte * 0x8020LU & 0x88440LU)) *
3889                                              0x10101LU >>
3890                                          16);
3891
3892            output = output | (static_cast<uint32_t>(o_byte << 24));
3893            input = input >> 8;
3894          }
3895
3896          alu_out = static_cast<int32_t>(output);
3897          break;
3898        }
3899        case SEB: {
3900          uint8_t input = static_cast<uint8_t>(rt());
3901          uint32_t output = input;
3902          uint32_t mask = 0x00000080;
3903
3904          // Extending sign
3905          if (mask & input) {
3906            output |= 0xFFFFFF00;
3907          }
3908
3909          alu_out = static_cast<int32_t>(output);
3910          break;
3911        }
3912        case SEH: {
3913          uint16_t input = static_cast<uint16_t>(rt());
3914          uint32_t output = input;
3915          uint32_t mask = 0x00008000;
3916
3917          // Extending sign
3918          if (mask & input) {
3919            output |= 0xFFFF0000;
3920          }
3921
3922          alu_out = static_cast<int32_t>(output);
3923          break;
3924        }
3925        case WSBH: {
3926          uint32_t input = static_cast<uint32_t>(rt());
3927          uint32_t output = 0;
3928
3929          uint32_t mask = 0xFF000000;
3930          for (int i = 0; i < 4; i++) {
3931            uint32_t tmp = mask & input;
3932            if (i % 2 == 0) {
3933              tmp = tmp >> 8;
3934            } else {
3935              tmp = tmp << 8;
3936            }
3937            output = output | tmp;
3938            mask = mask >> 8;
3939          }
3940
3941          alu_out = static_cast<int32_t>(output);
3942          break;
3943        }
3944        default: {
3945          const uint8_t bp = instr_.Bp2Value();
3946          sa >>= kBp2Bits;
3947          switch (sa) {
3948            case ALIGN: {
3949              if (bp == 0) {
3950                alu_out = static_cast<int32_t>(rt());
3951              } else {
3952                uint32_t rt_hi = rt() << (8 * bp);
3953                uint32_t rs_lo = rs() >> (8 * (4 - bp));
3954                alu_out = static_cast<int32_t>(rt_hi | rs_lo);
3955              }
3956              break;
3957            }
3958            default:
3959              alu_out = 0x12345678;
3960              UNREACHABLE();
3961              break;
3962          }
3963        }
3964      }
3965      SetResult(rd_reg(), alu_out);
3966      break;
3967    }
3968    default:
3969      UNREACHABLE();
3970  }
3971}
3972
3973void Simulator::DecodeTypeRegister() {
3974  // ---------- Execution.
3975  switch (instr_.OpcodeFieldRaw()) {
3976    case COP1:
3977      DecodeTypeRegisterCOP1();
3978      break;
3979    case COP1X:
3980      DecodeTypeRegisterCOP1X();
3981      break;
3982    case SPECIAL:
3983      DecodeTypeRegisterSPECIAL();
3984      break;
3985    case SPECIAL2:
3986      DecodeTypeRegisterSPECIAL2();
3987      break;
3988    case SPECIAL3:
3989      DecodeTypeRegisterSPECIAL3();
3990      break;
3991    default:
3992      UNREACHABLE();
3993  }
3994}
3995
3996
3997// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
3998void Simulator::DecodeTypeImmediate() {
3999  // Instruction fields.
4000  Opcode op = instr_.OpcodeFieldRaw();
4001  int32_t rs_reg = instr_.RsValue();
4002  int32_t rs = get_register(instr_.RsValue());
4003  uint32_t rs_u = static_cast<uint32_t>(rs);
4004  int32_t rt_reg = instr_.RtValue();  // Destination register.
4005  int32_t rt = get_register(rt_reg);
4006  int16_t imm16 = instr_.Imm16Value();
4007
4008  int32_t ft_reg = instr_.FtValue();  // Destination register.
4009
4010  // Zero extended immediate.
4011  uint32_t oe_imm16 = 0xffff & imm16;
4012  // Sign extended immediate.
4013  int32_t se_imm16 = imm16;
4014
4015  // Next pc.
4016  int32_t next_pc = bad_ra;
4017
4018  // Used for conditional branch instructions.
4019  bool execute_branch_delay_instruction = false;
4020
4021  // Used for arithmetic instructions.
4022  int32_t alu_out = 0;
4023
4024  // Used for memory instructions.
4025  int32_t addr = 0x0;
4026
4027  // Branch instructions common part.
4028  auto BranchAndLinkHelper =
4029      [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
4030        execute_branch_delay_instruction = true;
4031        int32_t current_pc = get_pc();
4032        if (do_branch) {
4033          int16_t imm16 = this->instr_.Imm16Value();
4034          next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4035          set_register(31, current_pc + 2 * Instruction::kInstrSize);
4036        } else {
4037          next_pc = current_pc + 2 * Instruction::kInstrSize;
4038        }
4039      };
4040
4041  auto BranchHelper = [this, &next_pc,
4042                       &execute_branch_delay_instruction](bool do_branch) {
4043    execute_branch_delay_instruction = true;
4044    int32_t current_pc = get_pc();
4045    if (do_branch) {
4046      int16_t imm16 = this->instr_.Imm16Value();
4047      next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4048    } else {
4049      next_pc = current_pc + 2 * Instruction::kInstrSize;
4050    }
4051  };
4052
4053  auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
4054    int32_t current_pc = get_pc();
4055    CheckForbiddenSlot(current_pc);
4056    if (do_branch) {
4057      int32_t imm = this->instr_.ImmValue(bits);
4058      imm <<= 32 - bits;
4059      imm >>= 32 - bits;
4060      next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
4061      set_register(31, current_pc + Instruction::kInstrSize);
4062    }
4063  };
4064
4065  auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
4066    int32_t current_pc = get_pc();
4067    CheckForbiddenSlot(current_pc);
4068    if (do_branch) {
4069      int32_t imm = this->instr_.ImmValue(bits);
4070      imm <<= 32 - bits;
4071      imm >>= 32 - bits;
4072      next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
4073    }
4074  };
4075
4076  switch (op) {
4077    // ------------- COP1. Coprocessor instructions.
4078    case COP1:
4079      switch (instr_.RsFieldRaw()) {
4080        case BC1: {  // Branch on coprocessor condition.
4081          // Floating point.
4082          uint32_t cc = instr_.FBccValue();
4083          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4084          uint32_t cc_value = test_fcsr_bit(fcsr_cc);
4085          bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
4086          BranchHelper(do_branch);
4087          break;
4088        }
4089        case BC1EQZ:
4090          BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
4091          break;
4092        case BC1NEZ:
4093          BranchHelper(get_fpu_register(ft_reg) & 0x1);
4094          break;
4095        default:
4096          UNREACHABLE();
4097      }
4098      break;
4099    // ------------- REGIMM class.
4100    case REGIMM:
4101      switch (instr_.RtFieldRaw()) {
4102        case BLTZ:
4103          BranchHelper(rs < 0);
4104          break;
4105        case BGEZ:
4106          BranchHelper(rs >= 0);
4107          break;
4108        case BLTZAL:
4109          BranchAndLinkHelper(rs < 0);
4110          break;
4111        case BGEZAL:
4112          BranchAndLinkHelper(rs >= 0);
4113          break;
4114        default:
4115          UNREACHABLE();
4116      }
4117      break;  // case REGIMM.
4118    // ------------- Branch instructions.
4119    // When comparing to zero, the encoding of rt field is always 0, so we don't
4120    // need to replace rt with zero.
4121    case BEQ:
4122      BranchHelper(rs == rt);
4123      break;
4124    case BNE:
4125      BranchHelper(rs != rt);
4126      break;
4127    case POP06:  // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4128      if (IsMipsArchVariant(kMips32r6)) {
4129        if (rt_reg != 0) {
4130          if (rs_reg == 0) {  // BLEZALC
4131            BranchAndLinkCompactHelper(rt <= 0, 16);
4132          } else {
4133            if (rs_reg == rt_reg) {  // BGEZALC
4134              BranchAndLinkCompactHelper(rt >= 0, 16);
4135            } else {  // BGEUC
4136              BranchCompactHelper(
4137                  static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
4138            }
4139          }
4140        } else {  // BLEZ
4141          BranchHelper(rs <= 0);
4142        }
4143      } else {  // BLEZ
4144        BranchHelper(rs <= 0);
4145      }
4146      break;
4147    case POP07:  // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4148      if (IsMipsArchVariant(kMips32r6)) {
4149        if (rt_reg != 0) {
4150          if (rs_reg == 0) {  // BGTZALC
4151            BranchAndLinkCompactHelper(rt > 0, 16);
4152          } else {
4153            if (rt_reg == rs_reg) {  // BLTZALC
4154              BranchAndLinkCompactHelper(rt < 0, 16);
4155            } else {  // BLTUC
4156              BranchCompactHelper(
4157                  static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
4158            }
4159          }
4160        } else {  // BGTZ
4161          BranchHelper(rs > 0);
4162        }
4163      } else {  // BGTZ
4164        BranchHelper(rs > 0);
4165      }
4166      break;
4167    case POP26:  // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4168      if (IsMipsArchVariant(kMips32r6)) {
4169        if (rt_reg != 0) {
4170          if (rs_reg == 0) {  // BLEZC
4171            BranchCompactHelper(rt <= 0, 16);
4172          } else {
4173            if (rs_reg == rt_reg) {  // BGEZC
4174              BranchCompactHelper(rt >= 0, 16);
4175            } else {  // BGEC/BLEC
4176              BranchCompactHelper(rs >= rt, 16);
4177            }
4178          }
4179        }
4180      } else {  // BLEZL
4181        BranchAndLinkHelper(rs <= 0);
4182      }
4183      break;
4184    case POP27:  // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4185      if (IsMipsArchVariant(kMips32r6)) {
4186        if (rt_reg != 0) {
4187          if (rs_reg == 0) {  // BGTZC
4188            BranchCompactHelper(rt > 0, 16);
4189          } else {
4190            if (rs_reg == rt_reg) {  // BLTZC
4191              BranchCompactHelper(rt < 0, 16);
4192            } else {  // BLTC/BGTC
4193              BranchCompactHelper(rs < rt, 16);
4194            }
4195          }
4196        }
4197      } else {  // BGTZL
4198        BranchAndLinkHelper(rs > 0);
4199      }
4200      break;
4201    case POP66:           // BEQZC, JIC
4202      if (rs_reg != 0) {  // BEQZC
4203        BranchCompactHelper(rs == 0, 21);
4204      } else {  // JIC
4205        next_pc = rt + imm16;
4206      }
4207      break;
4208    case POP76:           // BNEZC, JIALC
4209      if (rs_reg != 0) {  // BNEZC
4210        BranchCompactHelper(rs != 0, 21);
4211      } else {  // JIALC
4212        set_register(31, get_pc() + Instruction::kInstrSize);
4213        next_pc = rt + imm16;
4214      }
4215      break;
4216    case BC:
4217      BranchCompactHelper(true, 26);
4218      break;
4219    case BALC:
4220      BranchAndLinkCompactHelper(true, 26);
4221      break;
4222    case POP10:  // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4223      if (IsMipsArchVariant(kMips32r6)) {
4224        if (rs_reg >= rt_reg) {  // BOVC
4225          if (HaveSameSign(rs, rt)) {
4226            if (rs > 0) {
4227              BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
4228            } else if (rs < 0) {
4229              BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
4230            }
4231          }
4232        } else {
4233          if (rs_reg == 0) {  // BEQZALC
4234            BranchAndLinkCompactHelper(rt == 0, 16);
4235          } else {  // BEQC
4236            BranchCompactHelper(rt == rs, 16);
4237          }
4238        }
4239      } else {  // ADDI
4240        if (HaveSameSign(rs, se_imm16)) {
4241          if (rs > 0) {
4242            if (rs <= Registers::kMaxValue - se_imm16) {
4243              SignalException(kIntegerOverflow);
4244            }
4245          } else if (rs < 0) {
4246            if (rs >= Registers::kMinValue - se_imm16) {
4247              SignalException(kIntegerUnderflow);
4248            }
4249          }
4250        }
4251        SetResult(rt_reg, rs + se_imm16);
4252      }
4253      break;
4254    case POP30:  // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4255      if (IsMipsArchVariant(kMips32r6)) {
4256        if (rs_reg >= rt_reg) {  // BNVC
4257          if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
4258            BranchCompactHelper(true, 16);
4259          } else {
4260            if (rs > 0) {
4261              BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
4262            } else if (rs < 0) {
4263              BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
4264            }
4265          }
4266        } else {
4267          if (rs_reg == 0) {  // BNEZALC
4268            BranchAndLinkCompactHelper(rt != 0, 16);
4269          } else {  // BNEC
4270            BranchCompactHelper(rt != rs, 16);
4271          }
4272        }
4273      }
4274      break;
4275    // ------------- Arithmetic instructions.
4276    case ADDIU:
4277      SetResult(rt_reg, rs + se_imm16);
4278      break;
4279    case SLTI:
4280      SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
4281      break;
4282    case SLTIU:
4283      SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
4284      break;
4285    case ANDI:
4286      SetResult(rt_reg, rs & oe_imm16);
4287      break;
4288    case ORI:
4289      SetResult(rt_reg, rs | oe_imm16);
4290      break;
4291    case XORI:
4292      SetResult(rt_reg, rs ^ oe_imm16);
4293      break;
4294    case LUI:
4295      if (rs_reg != 0) {
4296        // AUI
4297        DCHECK(IsMipsArchVariant(kMips32r6));
4298        SetResult(rt_reg, rs + (se_imm16 << 16));
4299      } else {
4300        // LUI
4301        SetResult(rt_reg, oe_imm16 << 16);
4302      }
4303      break;
4304    // ------------- Memory instructions.
4305    case LB:
4306      set_register(rt_reg, ReadB(rs + se_imm16));
4307      break;
4308    case LH:
4309      set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
4310      break;
4311    case LWL: {
4312      // al_offset is offset of the effective address within an aligned word.
4313      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4314      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4315      uint32_t mask = (1 << byte_shift * 8) - 1;
4316      addr = rs + se_imm16 - al_offset;
4317      alu_out = ReadW(addr, instr_.instr());
4318      alu_out <<= byte_shift * 8;
4319      alu_out |= rt & mask;
4320      set_register(rt_reg, alu_out);
4321      break;
4322    }
4323    case LW:
4324      set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
4325      break;
4326    case LBU:
4327      set_register(rt_reg, ReadBU(rs + se_imm16));
4328      break;
4329    case LHU:
4330      set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
4331      break;
4332    case LWR: {
4333      // al_offset is offset of the effective address within an aligned word.
4334      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4335      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4336      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4337      addr = rs + se_imm16 - al_offset;
4338      alu_out = ReadW(addr, instr_.instr());
4339      alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4340      alu_out |= rt & mask;
4341      set_register(rt_reg, alu_out);
4342      break;
4343    }
4344    case SB:
4345      WriteB(rs + se_imm16, static_cast<int8_t>(rt));
4346      break;
4347    case SH:
4348      WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
4349      break;
4350    case SWL: {
4351      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4352      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4353      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4354      addr = rs + se_imm16 - al_offset;
4355      // Value to be written in memory.
4356      uint32_t mem_value = ReadW(addr, instr_.instr()) & mask;
4357      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
4358      WriteW(addr, mem_value, instr_.instr());
4359      break;
4360    }
4361    case SW:
4362      WriteW(rs + se_imm16, rt, instr_.instr());
4363      break;
4364    case SWR: {
4365      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4366      uint32_t mask = (1 << al_offset * 8) - 1;
4367      addr = rs + se_imm16 - al_offset;
4368      uint32_t mem_value = ReadW(addr, instr_.instr());
4369      mem_value = (rt << al_offset * 8) | (mem_value & mask);
4370      WriteW(addr, mem_value, instr_.instr());
4371      break;
4372    }
4373    case LWC1:
4374      set_fpu_register_hi_word(ft_reg, 0);
4375      set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr_.instr()));
4376      break;
4377    case LDC1:
4378      set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
4379      break;
4380    case SWC1:
4381      WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr_.instr());
4382      break;
4383    case SDC1:
4384      WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
4385      break;
4386    // ------------- PC-Relative instructions.
4387    case PCREL: {
4388      // rt field: checking 5-bits.
4389      int32_t imm21 = instr_.Imm21Value();
4390      int32_t current_pc = get_pc();
4391      uint8_t rt = (imm21 >> kImm16Bits);
4392      switch (rt) {
4393        case ALUIPC:
4394          addr = current_pc + (se_imm16 << 16);
4395          alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4396          break;
4397        case AUIPC:
4398          alu_out = current_pc + (se_imm16 << 16);
4399          break;
4400        default: {
4401          int32_t imm19 = instr_.Imm19Value();
4402          // rt field: checking the most significant 2-bits.
4403          rt = (imm21 >> kImm19Bits);
4404          switch (rt) {
4405            case LWPC: {
4406              // Set sign.
4407              imm19 <<= (kOpcodeBits + kRsBits + 2);
4408              imm19 >>= (kOpcodeBits + kRsBits + 2);
4409              addr = current_pc + (imm19 << 2);
4410              uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4411              alu_out = *ptr;
4412              break;
4413            }
4414            case ADDIUPC: {
4415              int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
4416              alu_out = current_pc + (se_imm19 << 2);
4417              break;
4418            }
4419            default:
4420              UNREACHABLE();
4421              break;
4422          }
4423        }
4424      }
4425      set_register(rs_reg, alu_out);
4426      break;
4427    }
4428    default:
4429      UNREACHABLE();
4430  }
4431
4432  if (execute_branch_delay_instruction) {
4433    // Execute branch delay slot
4434    // We don't check for end_sim_pc. First it should not be met as the current
4435    // pc is valid. Secondly a jump should always execute its branch delay slot.
4436    Instruction* branch_delay_instr =
4437        reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
4438    BranchDelayInstructionDecode(branch_delay_instr);
4439  }
4440
4441  // If needed update pc after the branch delay execution.
4442  if (next_pc != bad_ra) {
4443    set_pc(next_pc);
4444  }
4445}
4446
4447
4448// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
4449void Simulator::DecodeTypeJump() {
4450  SimInstruction simInstr = instr_;
4451  // Get current pc.
4452  int32_t current_pc = get_pc();
4453  // Get unchanged bits of pc.
4454  int32_t pc_high_bits = current_pc & 0xf0000000;
4455  // Next pc.
4456
4457  int32_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2);
4458
4459  // Execute branch delay slot.
4460  // We don't check for end_sim_pc. First it should not be met as the current pc
4461  // is valid. Secondly a jump should always execute its branch delay slot.
4462  Instruction* branch_delay_instr =
4463      reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
4464  BranchDelayInstructionDecode(branch_delay_instr);
4465
4466  // Update pc and ra if necessary.
4467  // Do this after the branch delay execution.
4468  if (simInstr.IsLinkingInstruction()) {
4469    set_register(31, current_pc + 2 * Instruction::kInstrSize);
4470  }
4471  set_pc(next_pc);
4472  pc_modified_ = true;
4473}
4474
4475
4476// Executes the current instruction.
4477void Simulator::InstructionDecode(Instruction* instr) {
4478  if (v8::internal::FLAG_check_icache) {
4479    CheckICache(isolate_->simulator_i_cache(), instr);
4480  }
4481  pc_modified_ = false;
4482  v8::internal::EmbeddedVector<char, 256> buffer;
4483  if (::v8::internal::FLAG_trace_sim) {
4484    SNPrintF(trace_buf_, "%s", "");
4485    disasm::NameConverter converter;
4486    disasm::Disassembler dasm(converter);
4487    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
4488  }
4489
4490  instr_ = instr;
4491  switch (instr_.InstructionType()) {
4492    case Instruction::kRegisterType:
4493      DecodeTypeRegister();
4494      break;
4495    case Instruction::kImmediateType:
4496      DecodeTypeImmediate();
4497      break;
4498    case Instruction::kJumpType:
4499      DecodeTypeJump();
4500      break;
4501    default:
4502      UNSUPPORTED();
4503  }
4504  if (::v8::internal::FLAG_trace_sim) {
4505    PrintF("  0x%08" PRIxPTR "  %-44s   %s\n",
4506           reinterpret_cast<intptr_t>(instr), buffer.start(),
4507           trace_buf_.start());
4508  }
4509  if (!pc_modified_) {
4510    set_register(pc, reinterpret_cast<int32_t>(instr) +
4511                 Instruction::kInstrSize);
4512  }
4513}
4514
4515
4516
4517void Simulator::Execute() {
4518  // Get the PC to simulate. Cannot use the accessor here as we need the
4519  // raw PC value and not the one used as input to arithmetic instructions.
4520  int program_counter = get_pc();
4521  if (::v8::internal::FLAG_stop_sim_at == 0) {
4522    // Fast version of the dispatch loop without checking whether the simulator
4523    // should be stopping at a particular executed instruction.
4524    while (program_counter != end_sim_pc) {
4525      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4526      icount_++;
4527      InstructionDecode(instr);
4528      program_counter = get_pc();
4529    }
4530  } else {
4531    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4532    // we reach the particular instuction count.
4533    while (program_counter != end_sim_pc) {
4534      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4535      icount_++;
4536      if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
4537        MipsDebugger dbg(this);
4538        dbg.Debug();
4539      } else {
4540        InstructionDecode(instr);
4541      }
4542      program_counter = get_pc();
4543    }
4544  }
4545}
4546
4547
4548void Simulator::CallInternal(byte* entry) {
4549  // Adjust JS-based stack limit to C-based stack limit.
4550  isolate_->stack_guard()->AdjustStackLimitForSimulator();
4551
4552  // Prepare to execute the code at entry.
4553  set_register(pc, reinterpret_cast<int32_t>(entry));
4554  // Put down marker for end of simulation. The simulator will stop simulation
4555  // when the PC reaches this value. By saving the "end simulation" value into
4556  // the LR the simulation stops when returning to this call point.
4557  set_register(ra, end_sim_pc);
4558
4559  // Remember the values of callee-saved registers.
4560  // The code below assumes that r9 is not used as sb (static base) in
4561  // simulator code and therefore is regarded as a callee-saved register.
4562  int32_t s0_val = get_register(s0);
4563  int32_t s1_val = get_register(s1);
4564  int32_t s2_val = get_register(s2);
4565  int32_t s3_val = get_register(s3);
4566  int32_t s4_val = get_register(s4);
4567  int32_t s5_val = get_register(s5);
4568  int32_t s6_val = get_register(s6);
4569  int32_t s7_val = get_register(s7);
4570  int32_t gp_val = get_register(gp);
4571  int32_t sp_val = get_register(sp);
4572  int32_t fp_val = get_register(fp);
4573
4574  // Set up the callee-saved registers with a known value. To be able to check
4575  // that they are preserved properly across JS execution.
4576  int32_t callee_saved_value = static_cast<int32_t>(icount_);
4577  set_register(s0, callee_saved_value);
4578  set_register(s1, callee_saved_value);
4579  set_register(s2, callee_saved_value);
4580  set_register(s3, callee_saved_value);
4581  set_register(s4, callee_saved_value);
4582  set_register(s5, callee_saved_value);
4583  set_register(s6, callee_saved_value);
4584  set_register(s7, callee_saved_value);
4585  set_register(gp, callee_saved_value);
4586  set_register(fp, callee_saved_value);
4587
4588  // Start the simulation.
4589  Execute();
4590
4591  // Check that the callee-saved registers have been preserved.
4592  CHECK_EQ(callee_saved_value, get_register(s0));
4593  CHECK_EQ(callee_saved_value, get_register(s1));
4594  CHECK_EQ(callee_saved_value, get_register(s2));
4595  CHECK_EQ(callee_saved_value, get_register(s3));
4596  CHECK_EQ(callee_saved_value, get_register(s4));
4597  CHECK_EQ(callee_saved_value, get_register(s5));
4598  CHECK_EQ(callee_saved_value, get_register(s6));
4599  CHECK_EQ(callee_saved_value, get_register(s7));
4600  CHECK_EQ(callee_saved_value, get_register(gp));
4601  CHECK_EQ(callee_saved_value, get_register(fp));
4602
4603  // Restore callee-saved registers with the original value.
4604  set_register(s0, s0_val);
4605  set_register(s1, s1_val);
4606  set_register(s2, s2_val);
4607  set_register(s3, s3_val);
4608  set_register(s4, s4_val);
4609  set_register(s5, s5_val);
4610  set_register(s6, s6_val);
4611  set_register(s7, s7_val);
4612  set_register(gp, gp_val);
4613  set_register(sp, sp_val);
4614  set_register(fp, fp_val);
4615}
4616
4617
4618int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4619  va_list parameters;
4620  va_start(parameters, argument_count);
4621  // Set up arguments.
4622
4623  // First four arguments passed in registers.
4624  DCHECK(argument_count >= 4);
4625  set_register(a0, va_arg(parameters, int32_t));
4626  set_register(a1, va_arg(parameters, int32_t));
4627  set_register(a2, va_arg(parameters, int32_t));
4628  set_register(a3, va_arg(parameters, int32_t));
4629
4630  // Remaining arguments passed on stack.
4631  int original_stack = get_register(sp);
4632  // Compute position of stack on entry to generated code.
4633  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
4634                                    - kCArgsSlotsSize);
4635  if (base::OS::ActivationFrameAlignment() != 0) {
4636    entry_stack &= -base::OS::ActivationFrameAlignment();
4637  }
4638  // Store remaining arguments on stack, from low to high memory.
4639  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4640  for (int i = 4; i < argument_count; i++) {
4641    stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
4642  }
4643  va_end(parameters);
4644  set_register(sp, entry_stack);
4645
4646  CallInternal(entry);
4647
4648  // Pop stack passed arguments.
4649  CHECK_EQ(entry_stack, get_register(sp));
4650  set_register(sp, original_stack);
4651
4652  int32_t result = get_register(v0);
4653  return result;
4654}
4655
4656
4657double Simulator::CallFP(byte* entry, double d0, double d1) {
4658  if (!IsMipsSoftFloatABI) {
4659    set_fpu_register_double(f12, d0);
4660    set_fpu_register_double(f14, d1);
4661  } else {
4662    int buffer[2];
4663    DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4664    memcpy(buffer, &d0, sizeof(d0));
4665    set_dw_register(a0, buffer);
4666    memcpy(buffer, &d1, sizeof(d1));
4667    set_dw_register(a2, buffer);
4668  }
4669  CallInternal(entry);
4670  if (!IsMipsSoftFloatABI) {
4671    return get_fpu_register_double(f0);
4672  } else {
4673    return get_double_from_register_pair(v0);
4674  }
4675}
4676
4677
4678uintptr_t Simulator::PushAddress(uintptr_t address) {
4679  int new_sp = get_register(sp) - sizeof(uintptr_t);
4680  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4681  *stack_slot = address;
4682  set_register(sp, new_sp);
4683  return new_sp;
4684}
4685
4686
4687uintptr_t Simulator::PopAddress() {
4688  int current_sp = get_register(sp);
4689  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4690  uintptr_t address = *stack_slot;
4691  set_register(sp, current_sp + sizeof(uintptr_t));
4692  return address;
4693}
4694
4695
4696#undef UNSUPPORTED
4697
4698}  // namespace internal
4699}  // namespace v8
4700
4701#endif  // USE_SIMULATOR
4702
4703#endif  // V8_TARGET_ARCH_MIPS
4704