V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
simulator-mips.cc
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-inl.h"
13 #include "src/base/bits.h"
14 #include "src/codegen.h"
15 #include "src/disasm.h"
16 #include "src/macro-assembler.h"
17 #include "src/mips/constants-mips.h"
18 #include "src/mips/simulator-mips.h"
19 #include "src/ostreams.h"
20 #include "src/runtime/runtime-utils.h"
21 
22 
23 // Only build the simulator if not compiling for real MIPS hardware.
24 #if defined(USE_SIMULATOR)
25 
26 namespace v8 {
27 namespace internal {
28 
29 // Utils functions.
30 bool HaveSameSign(int32_t a, int32_t b) {
31  return ((a ^ b) >= 0);
32 }
33 
34 
35 uint32_t get_fcsr_condition_bit(uint32_t cc) {
36  if (cc == 0) {
37  return 23;
38  } else {
39  return 24 + cc;
40  }
41 }
42 
43 
44 // This macro provides a platform independent use of sscanf. The reason for
45 // SScanF not being implemented in a platform independent was through
46 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
47 // Library does not provide vsscanf.
48 #define SScanF sscanf // NOLINT
49 
50 // The MipsDebugger class is used by the simulator while debugging simulated
51 // code.
52 class MipsDebugger {
53  public:
54  explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
55 
56  void Stop(Instruction* instr);
57  void Debug();
58  // Print all registers with a nice formatting.
59  void PrintAllRegs();
60  void PrintAllRegsIncludingFPU();
61 
62  private:
63  // We set the breakpoint code to 0xFFFFF to easily recognize it.
64  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xFFFFF << 6;
65  static const Instr kNopInstr = 0x0;
66 
67  Simulator* sim_;
68 
69  int32_t GetRegisterValue(int regnum);
70  int32_t GetFPURegisterValue32(int regnum);
71  int64_t GetFPURegisterValue64(int regnum);
72  float GetFPURegisterValueFloat(int regnum);
73  double GetFPURegisterValueDouble(int regnum);
74  bool GetValue(const char* desc, int32_t* value);
75  bool GetValue(const char* desc, int64_t* value);
76 
77  // Set or delete a breakpoint. Returns true if successful.
78  bool SetBreakpoint(Instruction* breakpc);
79  bool DeleteBreakpoint(Instruction* breakpc);
80 
81  // Undo and redo all breakpoints. This is needed to bracket disassembly and
82  // execution to skip past breakpoints when run from the debugger.
83  void UndoBreakpoints();
84  void RedoBreakpoints();
85 };
86 
87 
88 #define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
89 
90 
91 void MipsDebugger::Stop(Instruction* instr) {
92  // Get the stop code.
93  uint32_t code = instr->Bits(25, 6);
94  PrintF("Simulator hit (%u)\n", code);
95  Debug();
96 }
97 
98 
99 int32_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 
108 int32_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 
117 int64_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 
126 float 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 
135 double 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 
144 bool 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 
163 bool 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 
183 bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
184  // Check if a breakpoint can be set. If not return without any side-effects.
185  if (sim_->break_pc_ != nullptr) {
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 
198 bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
199  if (sim_->break_pc_ != nullptr) {
200  sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
201  }
202 
203  sim_->break_pc_ = nullptr;
204  sim_->break_instr_ = 0;
205  return true;
206 }
207 
208 
209 void MipsDebugger::UndoBreakpoints() {
210  if (sim_->break_pc_ != nullptr) {
211  sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
212  }
213 }
214 
215 
216 void MipsDebugger::RedoBreakpoints() {
217  if (sim_->break_pc_ != nullptr) {
218  sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
219  }
220 }
221 
222 
223 void 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 
262 void 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 
336 void 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.
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 == nullptr) {
373  break;
374  } else {
375  char* last_input = sim_->last_debugger_input();
376  if (strcmp(line, "\n") == 0 && last_input != nullptr) {
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() + 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  StdoutStream os;
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 = nullptr;
494  int32_t* end = nullptr;
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) || current_heap->Contains(obj)) {
539  PrintF(" (");
540  if ((value & 1) == 0) {
541  PrintF("smi %d", value / 2);
542  } else {
543  obj->ShortPrint();
544  }
545  PrintF(")");
546  }
547  PrintF("\n");
548  cur++;
549  }
550 
551  } else if ((strcmp(cmd, "disasm") == 0) ||
552  (strcmp(cmd, "dpc") == 0) ||
553  (strcmp(cmd, "di") == 0)) {
554  disasm::NameConverter converter;
555  disasm::Disassembler dasm(converter);
556  // Use a reasonably large buffer.
558 
559  byte* cur = nullptr;
560  byte* end = nullptr;
561 
562  if (argc == 1) {
563  cur = reinterpret_cast<byte*>(sim_->get_pc());
564  end = cur + (10 * kInstrSize);
565  } else if (argc == 2) {
566  int regnum = Registers::Number(arg1);
567  if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
568  // The argument is an address or a register name.
569  int32_t value;
570  if (GetValue(arg1, &value)) {
571  cur = reinterpret_cast<byte*>(value);
572  // Disassemble 10 instructions at <arg1>.
573  end = cur + (10 * kInstrSize);
574  }
575  } else {
576  // The argument is the number of instructions.
577  int32_t value;
578  if (GetValue(arg1, &value)) {
579  cur = reinterpret_cast<byte*>(sim_->get_pc());
580  // Disassemble <arg1> instructions.
581  end = cur + (value * kInstrSize);
582  }
583  }
584  } else {
585  int32_t value1;
586  int32_t value2;
587  if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
588  cur = reinterpret_cast<byte*>(value1);
589  end = cur + (value2 * kInstrSize);
590  }
591  }
592 
593  while (cur < end) {
594  dasm.InstructionDecode(buffer, cur);
595  PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
596  buffer.start());
597  cur += kInstrSize;
598  }
599  } else if (strcmp(cmd, "gdb") == 0) {
600  PrintF("relinquishing control to gdb\n");
601  v8::base::OS::DebugBreak();
602  PrintF("regaining control from gdb\n");
603  } else if (strcmp(cmd, "break") == 0) {
604  if (argc == 2) {
605  int32_t value;
606  if (GetValue(arg1, &value)) {
607  if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
608  PrintF("setting breakpoint failed\n");
609  }
610  } else {
611  PrintF("%s unrecognized\n", arg1);
612  }
613  } else {
614  PrintF("break <address>\n");
615  }
616  } else if (strcmp(cmd, "del") == 0) {
617  if (!DeleteBreakpoint(nullptr)) {
618  PrintF("deleting breakpoint failed\n");
619  }
620  } else if (strcmp(cmd, "flags") == 0) {
621  PrintF("No flags on MIPS !\n");
622  } else if (strcmp(cmd, "stop") == 0) {
623  int32_t value;
624  intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
625  Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
626  Instruction* msg_address =
627  reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
628  if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
629  // Remove the current stop.
630  if (sim_->IsStopInstruction(stop_instr)) {
631  stop_instr->SetInstructionBits(kNopInstr);
632  msg_address->SetInstructionBits(kNopInstr);
633  } else {
634  PrintF("Not at debugger stop.\n");
635  }
636  } else if (argc == 3) {
637  // Print information about all/the specified breakpoint(s).
638  if (strcmp(arg1, "info") == 0) {
639  if (strcmp(arg2, "all") == 0) {
640  PrintF("Stop information:\n");
641  for (uint32_t i = kMaxWatchpointCode + 1;
642  i <= kMaxStopCode;
643  i++) {
644  sim_->PrintStopInfo(i);
645  }
646  } else if (GetValue(arg2, &value)) {
647  sim_->PrintStopInfo(value);
648  } else {
649  PrintF("Unrecognized argument.\n");
650  }
651  } else if (strcmp(arg1, "enable") == 0) {
652  // Enable all/the specified breakpoint(s).
653  if (strcmp(arg2, "all") == 0) {
654  for (uint32_t i = kMaxWatchpointCode + 1;
655  i <= kMaxStopCode;
656  i++) {
657  sim_->EnableStop(i);
658  }
659  } else if (GetValue(arg2, &value)) {
660  sim_->EnableStop(value);
661  } else {
662  PrintF("Unrecognized argument.\n");
663  }
664  } else if (strcmp(arg1, "disable") == 0) {
665  // Disable all/the specified breakpoint(s).
666  if (strcmp(arg2, "all") == 0) {
667  for (uint32_t i = kMaxWatchpointCode + 1;
668  i <= kMaxStopCode;
669  i++) {
670  sim_->DisableStop(i);
671  }
672  } else if (GetValue(arg2, &value)) {
673  sim_->DisableStop(value);
674  } else {
675  PrintF("Unrecognized argument.\n");
676  }
677  }
678  } else {
679  PrintF("Wrong usage. Use help command for more information.\n");
680  }
681  } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
682  // Print registers and disassemble.
683  PrintAllRegs();
684  PrintF("\n");
685 
686  disasm::NameConverter converter;
687  disasm::Disassembler dasm(converter);
688  // Use a reasonably large buffer.
690 
691  byte* cur = nullptr;
692  byte* end = nullptr;
693 
694  if (argc == 1) {
695  cur = reinterpret_cast<byte*>(sim_->get_pc());
696  end = cur + (10 * kInstrSize);
697  } else if (argc == 2) {
698  int32_t value;
699  if (GetValue(arg1, &value)) {
700  cur = reinterpret_cast<byte*>(value);
701  // no length parameter passed, assume 10 instructions
702  end = cur + (10 * kInstrSize);
703  }
704  } else {
705  int32_t value1;
706  int32_t value2;
707  if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
708  cur = reinterpret_cast<byte*>(value1);
709  end = cur + (value2 * kInstrSize);
710  }
711  }
712 
713  while (cur < end) {
714  dasm.InstructionDecode(buffer, cur);
715  PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
716  buffer.start());
717  cur += kInstrSize;
718  }
719  } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
720  PrintF("cont\n");
721  PrintF(" continue execution (alias 'c')\n");
722  PrintF("stepi\n");
723  PrintF(" step one instruction (alias 'si')\n");
724  PrintF("print <register>\n");
725  PrintF(" print register content (alias 'p')\n");
726  PrintF(" use register name 'all' to print all registers\n");
727  PrintF("printobject <register>\n");
728  PrintF(" print an object from a register (alias 'po')\n");
729  PrintF("stack [<words>]\n");
730  PrintF(" dump stack content, default dump 10 words)\n");
731  PrintF("mem <address> [<words>]\n");
732  PrintF(" dump memory content, default dump 10 words)\n");
733  PrintF("flags\n");
734  PrintF(" print flags\n");
735  PrintF("disasm [<instructions>]\n");
736  PrintF("disasm [<address/register>]\n");
737  PrintF("disasm [[<address/register>] <instructions>]\n");
738  PrintF(" disassemble code, default is 10 instructions\n");
739  PrintF(" from pc (alias 'di')\n");
740  PrintF("gdb\n");
741  PrintF(" enter gdb\n");
742  PrintF("break <address>\n");
743  PrintF(" set a break point on the address\n");
744  PrintF("del\n");
745  PrintF(" delete the breakpoint\n");
746  PrintF("stop feature:\n");
747  PrintF(" Description:\n");
748  PrintF(" Stops are debug instructions inserted by\n");
749  PrintF(" the Assembler::stop() function.\n");
750  PrintF(" When hitting a stop, the Simulator will\n");
751  PrintF(" stop and give control to the Debugger.\n");
752  PrintF(" All stop codes are watched:\n");
753  PrintF(" - They can be enabled / disabled: the Simulator\n");
754  PrintF(" will / won't stop when hitting them.\n");
755  PrintF(" - The Simulator keeps track of how many times they \n");
756  PrintF(" are met. (See the info command.) Going over a\n");
757  PrintF(" disabled stop still increases its counter. \n");
758  PrintF(" Commands:\n");
759  PrintF(" stop info all/<code> : print infos about number <code>\n");
760  PrintF(" or all stop(s).\n");
761  PrintF(" stop enable/disable all/<code> : enables / disables\n");
762  PrintF(" all or number <code> stop(s)\n");
763  PrintF(" stop unstop\n");
764  PrintF(" ignore the stop instruction at the current location\n");
765  PrintF(" from now on\n");
766  } else {
767  PrintF("Unknown command: %s\n", cmd);
768  }
769  }
770  }
771 
772  // Add all the breakpoints back to stop execution and enter the debugger
773  // shell when hit.
774  RedoBreakpoints();
775 
776 #undef COMMAND_SIZE
777 #undef ARG_SIZE
778 
779 #undef STR
780 #undef XSTR
781 }
782 
783 bool Simulator::ICacheMatch(void* one, void* two) {
784  DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
785  DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
786  return one == two;
787 }
788 
789 
790 static uint32_t ICacheHash(void* key) {
791  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
792 }
793 
794 
795 static bool AllOnOnePage(uintptr_t start, int size) {
796  intptr_t start_page = (start & ~CachePage::kPageMask);
797  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
798  return start_page == end_page;
799 }
800 
801 
802 void Simulator::set_last_debugger_input(char* input) {
803  DeleteArray(last_debugger_input_);
804  last_debugger_input_ = input;
805 }
806 
807 void Simulator::SetRedirectInstruction(Instruction* instruction) {
808  instruction->SetInstructionBits(rtCallRedirInstr);
809 }
810 
811 void 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 
832 CachePage* 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 == nullptr) {
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.
845 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
846  intptr_t start, int size) {
847  DCHECK_LE(size, CachePage::kPageSize);
848  DCHECK(AllOnOnePage(start, size - 1));
849  DCHECK_EQ(start & CachePage::kLineMask, 0);
850  DCHECK_EQ(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 
858 void 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), kInstrSize));
872  } else {
873  // Cache miss. Load memory into the cache.
874  memcpy(cached_line, line, CachePage::kLineLength);
875  *cache_valid_byte = CachePage::LINE_VALID;
876  }
877 }
878 
879 
880 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
881  // Set up simulator support first. Some of this information is needed to
882  // setup the architecture state.
883  stack_ = reinterpret_cast<char*>(malloc(stack_size_));
884  pc_modified_ = false;
885  icount_ = 0;
886  break_count_ = 0;
887  break_pc_ = nullptr;
888  break_instr_ = 0;
889 
890  // Set up architecture state.
891  // All registers are initialized to zero to start with.
892  for (int i = 0; i < kNumSimuRegisters; i++) {
893  registers_[i] = 0;
894  }
895  for (int i = 0; i < kNumFPURegisters; i++) {
896  FPUregisters_[2 * i] = 0;
897  FPUregisters_[2 * i + 1] = 0; // upper part for MSA ASE
898  }
899  if (IsMipsArchVariant(kMips32r6)) {
900  FCSR_ = kFCSRNaN2008FlagMask;
901  MSACSR_ = 0;
902  } else {
903  DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
904  FCSR_ = 0;
905  }
906 
907  // The sp is initialized to point to the bottom (high address) of the
908  // allocated stack area. To be safe in potential stack underflows we leave
909  // some buffer below.
910  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
911  // The ra and pc are initialized to a known bad value that will cause an
912  // access violation if the simulator ever tries to execute it.
913  registers_[pc] = bad_ra;
914  registers_[ra] = bad_ra;
915  last_debugger_input_ = nullptr;
916 }
917 
918 
919 Simulator::~Simulator() { free(stack_); }
920 
921 
922 // Get the active Simulator for the current thread.
923 Simulator* Simulator::current(Isolate* isolate) {
925  isolate->FindOrAllocatePerThreadDataForThisThread();
926  DCHECK_NOT_NULL(isolate_data);
927 
928  Simulator* sim = isolate_data->simulator();
929  if (sim == nullptr) {
930  // TODO(146): delete the simulator object when a thread/isolate goes away.
931  sim = new Simulator(isolate);
932  isolate_data->set_simulator(sim);
933  }
934  return sim;
935 }
936 
937 
938 // Sets the register in the architecture state. It will also deal with updating
939 // Simulator internal state for special registers such as PC.
940 void Simulator::set_register(int reg, int32_t value) {
941  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
942  if (reg == pc) {
943  pc_modified_ = true;
944  }
945 
946  // Zero register always holds 0.
947  registers_[reg] = (reg == 0) ? 0 : value;
948 }
949 
950 
951 void Simulator::set_dw_register(int reg, const int* dbl) {
952  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
953  registers_[reg] = dbl[0];
954  registers_[reg + 1] = dbl[1];
955 }
956 
957 
958 void Simulator::set_fpu_register(int fpureg, int64_t value) {
959  DCHECK(IsFp64Mode());
960  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
961  FPUregisters_[fpureg * 2] = value;
962 }
963 
964 
965 void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
966  // Set ONLY lower 32-bits, leaving upper bits untouched.
967  // TODO(plind): big endian issue.
968  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
969  int32_t* pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
970  *pword = value;
971 }
972 
973 
974 void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
975  // Set ONLY upper 32-bits, leaving lower bits untouched.
976  // TODO(plind): big endian issue.
977  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
978  int32_t* phiword =
979  (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
980  *phiword = value;
981 }
982 
983 
984 void Simulator::set_fpu_register_float(int fpureg, float value) {
985  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
986  *bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
987 }
988 
989 
990 void Simulator::set_fpu_register_double(int fpureg, double value) {
991  if (IsFp64Mode()) {
992  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
993  *bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
994  } else {
995  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
996  int64_t i64 = bit_cast<int64_t>(value);
997  set_fpu_register_word(fpureg, i64 & 0xFFFFFFFF);
998  set_fpu_register_word(fpureg + 1, i64 >> 32);
999  }
1000 }
1001 
1002 
1003 // Get the register from the architecture state. This function does handle
1004 // the special case of accessing the PC register.
1005 int32_t Simulator::get_register(int reg) const {
1006  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1007  if (reg == 0)
1008  return 0;
1009  else
1010  return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1011 }
1012 
1013 
1014 double Simulator::get_double_from_register_pair(int reg) {
1015  // TODO(plind): bad ABI stuff, refactor or remove.
1016  DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1017 
1018  double dm_val = 0.0;
1019  // Read the bits from the unsigned integer register_[] array
1020  // into the double precision floating point value and return it.
1021  char buffer[2 * sizeof(registers_[0])];
1022  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1023  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1024  return(dm_val);
1025 }
1026 
1027 
1028 int64_t Simulator::get_fpu_register(int fpureg) const {
1029  if (IsFp64Mode()) {
1030  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1031  return FPUregisters_[fpureg * 2];
1032  } else {
1033  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1034  uint64_t i64;
1035  i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1036  i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1037  return static_cast<int64_t>(i64);
1038  }
1039 }
1040 
1041 
1042 int32_t Simulator::get_fpu_register_word(int fpureg) const {
1043  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1044  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1045 }
1046 
1047 
1048 int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1049  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1050  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1051 }
1052 
1053 
1054 int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1055  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1056  return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xFFFFFFFF);
1057 }
1058 
1059 
1060 float Simulator::get_fpu_register_float(int fpureg) const {
1061  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1062  return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
1063 }
1064 
1065 
1066 double Simulator::get_fpu_register_double(int fpureg) const {
1067  if (IsFp64Mode()) {
1068  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1069  return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
1070  } else {
1071  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1072  int64_t i64;
1073  i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1074  i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1075  return bit_cast<double>(i64);
1076  }
1077 }
1078 
1079 template <typename T>
1080 void Simulator::get_msa_register(int wreg, T* value) {
1081  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
1082  memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
1083 }
1084 
1085 template <typename T>
1086 void Simulator::set_msa_register(int wreg, const T* value) {
1087  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
1088  memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
1089 }
1090 
1091 // Runtime FP routines take up to two double arguments and zero
1092 // or one integer arguments. All are constructed here,
1093 // from a0-a3 or f12 and f14.
1094 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1095  if (!IsMipsSoftFloatABI) {
1096  *x = get_fpu_register_double(12);
1097  *y = get_fpu_register_double(14);
1098  *z = get_register(a2);
1099  } else {
1100  // TODO(plind): bad ABI stuff, refactor or remove.
1101  // We use a char buffer to get around the strict-aliasing rules which
1102  // otherwise allow the compiler to optimize away the copy.
1103  char buffer[sizeof(*x)];
1104  int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1105 
1106  // Registers a0 and a1 -> x.
1107  reg_buffer[0] = get_register(a0);
1108  reg_buffer[1] = get_register(a1);
1109  memcpy(x, buffer, sizeof(buffer));
1110  // Registers a2 and a3 -> y.
1111  reg_buffer[0] = get_register(a2);
1112  reg_buffer[1] = get_register(a3);
1113  memcpy(y, buffer, sizeof(buffer));
1114  // Register 2 -> z.
1115  reg_buffer[0] = get_register(a2);
1116  memcpy(z, buffer, sizeof(*z));
1117  }
1118 }
1119 
1120 
1121 // The return value is either in v0/v1 or f0.
1122 void Simulator::SetFpResult(const double& result) {
1123  if (!IsMipsSoftFloatABI) {
1124  set_fpu_register_double(0, result);
1125  } else {
1126  char buffer[2 * sizeof(registers_[0])];
1127  int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1128  memcpy(buffer, &result, sizeof(buffer));
1129  // Copy result to v0 and v1.
1130  set_register(v0, reg_buffer[0]);
1131  set_register(v1, reg_buffer[1]);
1132  }
1133 }
1134 
1135 
1136 // Helper functions for setting and testing the FCSR register's bits.
1137 void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1138  if (value) {
1139  FCSR_ |= (1 << cc);
1140  } else {
1141  FCSR_ &= ~(1 << cc);
1142  }
1143 }
1144 
1145 
1146 bool Simulator::test_fcsr_bit(uint32_t cc) {
1147  return FCSR_ & (1 << cc);
1148 }
1149 
1150 
1151 void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1152  FCSR_ |= mode & kFPURoundingModeMask;
1153 }
1154 
1155 void Simulator::set_msacsr_rounding_mode(FPURoundingMode mode) {
1156  MSACSR_ |= mode & kFPURoundingModeMask;
1157 }
1158 
1159 unsigned int Simulator::get_fcsr_rounding_mode() {
1160  return FCSR_ & kFPURoundingModeMask;
1161 }
1162 
1163 unsigned int Simulator::get_msacsr_rounding_mode() {
1164  return MSACSR_ & kFPURoundingModeMask;
1165 }
1166 
1167 void Simulator::set_fpu_register_word_invalid_result(float original,
1168  float rounded) {
1169  if (FCSR_ & kFCSRNaN2008FlagMask) {
1170  double max_int32 = std::numeric_limits<int32_t>::max();
1171  double min_int32 = std::numeric_limits<int32_t>::min();
1172  if (std::isnan(original)) {
1173  set_fpu_register_word(fd_reg(), 0);
1174  } else if (rounded > max_int32) {
1175  set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1176  } else if (rounded < min_int32) {
1177  set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1178  } else {
1179  UNREACHABLE();
1180  }
1181  } else {
1182  set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1183  }
1184 }
1185 
1186 
1187 void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1188  if (FCSR_ & kFCSRNaN2008FlagMask) {
1189  double max_int32 = std::numeric_limits<int32_t>::max();
1190  double min_int32 = std::numeric_limits<int32_t>::min();
1191  if (std::isnan(original)) {
1192  set_fpu_register(fd_reg(), 0);
1193  } else if (rounded > max_int32) {
1194  set_fpu_register(fd_reg(), kFPUInvalidResult);
1195  } else if (rounded < min_int32) {
1196  set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1197  } else {
1198  UNREACHABLE();
1199  }
1200  } else {
1201  set_fpu_register(fd_reg(), kFPUInvalidResult);
1202  }
1203 }
1204 
1205 
1206 void Simulator::set_fpu_register_invalid_result64(float original,
1207  float rounded) {
1208  if (FCSR_ & kFCSRNaN2008FlagMask) {
1209  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1210  // loading the most accurate representation into max_int64, which is 2^63.
1211  double max_int64 = std::numeric_limits<int64_t>::max();
1212  double min_int64 = std::numeric_limits<int64_t>::min();
1213  if (std::isnan(original)) {
1214  set_fpu_register(fd_reg(), 0);
1215  } else if (rounded >= max_int64) {
1216  set_fpu_register(fd_reg(), kFPU64InvalidResult);
1217  } else if (rounded < min_int64) {
1218  set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1219  } else {
1220  UNREACHABLE();
1221  }
1222  } else {
1223  set_fpu_register(fd_reg(), kFPU64InvalidResult);
1224  }
1225 }
1226 
1227 
1228 void Simulator::set_fpu_register_word_invalid_result(double original,
1229  double rounded) {
1230  if (FCSR_ & kFCSRNaN2008FlagMask) {
1231  double max_int32 = std::numeric_limits<int32_t>::max();
1232  double min_int32 = std::numeric_limits<int32_t>::min();
1233  if (std::isnan(original)) {
1234  set_fpu_register_word(fd_reg(), 0);
1235  } else if (rounded > max_int32) {
1236  set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1237  } else if (rounded < min_int32) {
1238  set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1239  } else {
1240  UNREACHABLE();
1241  }
1242  } else {
1243  set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1244  }
1245 }
1246 
1247 
1248 void Simulator::set_fpu_register_invalid_result(double original,
1249  double rounded) {
1250  if (FCSR_ & kFCSRNaN2008FlagMask) {
1251  double max_int32 = std::numeric_limits<int32_t>::max();
1252  double min_int32 = std::numeric_limits<int32_t>::min();
1253  if (std::isnan(original)) {
1254  set_fpu_register(fd_reg(), 0);
1255  } else if (rounded > max_int32) {
1256  set_fpu_register(fd_reg(), kFPUInvalidResult);
1257  } else if (rounded < min_int32) {
1258  set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1259  } else {
1260  UNREACHABLE();
1261  }
1262  } else {
1263  set_fpu_register(fd_reg(), kFPUInvalidResult);
1264  }
1265 }
1266 
1267 
1268 void Simulator::set_fpu_register_invalid_result64(double original,
1269  double rounded) {
1270  if (FCSR_ & kFCSRNaN2008FlagMask) {
1271  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1272  // loading the most accurate representation into max_int64, which is 2^63.
1273  double max_int64 = std::numeric_limits<int64_t>::max();
1274  double min_int64 = std::numeric_limits<int64_t>::min();
1275  if (std::isnan(original)) {
1276  set_fpu_register(fd_reg(), 0);
1277  } else if (rounded >= max_int64) {
1278  set_fpu_register(fd_reg(), kFPU64InvalidResult);
1279  } else if (rounded < min_int64) {
1280  set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1281  } else {
1282  UNREACHABLE();
1283  }
1284  } else {
1285  set_fpu_register(fd_reg(), kFPU64InvalidResult);
1286  }
1287 }
1288 
1289 
1290 // Sets the rounding error codes in FCSR based on the result of the rounding.
1291 // Returns true if the operation was invalid.
1292 bool Simulator::set_fcsr_round_error(double original, double rounded) {
1293  bool ret = false;
1294  double max_int32 = std::numeric_limits<int32_t>::max();
1295  double min_int32 = std::numeric_limits<int32_t>::min();
1296 
1297  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1298  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1299  ret = true;
1300  }
1301 
1302  if (original != rounded) {
1303  set_fcsr_bit(kFCSRInexactFlagBit, true);
1304  }
1305 
1306  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1307  set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1308  ret = true;
1309  }
1310 
1311  if (rounded > max_int32 || rounded < min_int32) {
1312  set_fcsr_bit(kFCSROverflowFlagBit, true);
1313  // The reference is not really clear but it seems this is required:
1314  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1315  ret = true;
1316  }
1317 
1318  return ret;
1319 }
1320 
1321 
1322 // Sets the rounding error codes in FCSR based on the result of the rounding.
1323 // Returns true if the operation was invalid.
1324 bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1325  bool ret = false;
1326  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1327  // loading the most accurate representation into max_int64, which is 2^63.
1328  double max_int64 = std::numeric_limits<int64_t>::max();
1329  double min_int64 = std::numeric_limits<int64_t>::min();
1330 
1331  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1332  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1333  ret = true;
1334  }
1335 
1336  if (original != rounded) {
1337  set_fcsr_bit(kFCSRInexactFlagBit, true);
1338  }
1339 
1340  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1341  set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1342  ret = true;
1343  }
1344 
1345  if (rounded >= max_int64 || rounded < min_int64) {
1346  set_fcsr_bit(kFCSROverflowFlagBit, true);
1347  // The reference is not really clear but it seems this is required:
1348  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1349  ret = true;
1350  }
1351 
1352  return ret;
1353 }
1354 
1355 
1356 // Sets the rounding error codes in FCSR based on the result of the rounding.
1357 // Returns true if the operation was invalid.
1358 bool Simulator::set_fcsr_round_error(float original, float rounded) {
1359  bool ret = false;
1360  double max_int32 = std::numeric_limits<int32_t>::max();
1361  double min_int32 = std::numeric_limits<int32_t>::min();
1362 
1363  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1364  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1365  ret = true;
1366  }
1367 
1368  if (original != rounded) {
1369  set_fcsr_bit(kFCSRInexactFlagBit, true);
1370  }
1371 
1372  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1373  set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1374  ret = true;
1375  }
1376 
1377  if (rounded > max_int32 || rounded < min_int32) {
1378  set_fcsr_bit(kFCSROverflowFlagBit, true);
1379  // The reference is not really clear but it seems this is required:
1380  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1381  ret = true;
1382  }
1383 
1384  return ret;
1385 }
1386 
1387 
1388 // Sets the rounding error codes in FCSR based on the result of the rounding.
1389 // Returns true if the operation was invalid.
1390 bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1391  bool ret = false;
1392  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1393  // loading the most accurate representation into max_int64, which is 2^63.
1394  double max_int64 = std::numeric_limits<int64_t>::max();
1395  double min_int64 = std::numeric_limits<int64_t>::min();
1396 
1397  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1398  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1399  ret = true;
1400  }
1401 
1402  if (original != rounded) {
1403  set_fcsr_bit(kFCSRInexactFlagBit, true);
1404  }
1405 
1406  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1407  set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1408  ret = true;
1409  }
1410 
1411  if (rounded >= max_int64 || rounded < min_int64) {
1412  set_fcsr_bit(kFCSROverflowFlagBit, true);
1413  // The reference is not really clear but it seems this is required:
1414  set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1415  ret = true;
1416  }
1417 
1418  return ret;
1419 }
1420 
1421 
1422 void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1423  int32_t& rounded_int, double fs) {
1424  // 0 RN (round to nearest): Round a result to the nearest
1425  // representable value; if the result is exactly halfway between
1426  // two representable values, round to zero. Behave like round_w_d.
1427 
1428  // 1 RZ (round toward zero): Round a result to the closest
1429  // representable value whose absolute value is less than or
1430  // equal to the infinitely accurate result. Behave like trunc_w_d.
1431 
1432  // 2 RP (round up, or toward infinity): Round a result to the
1433  // next representable value up. Behave like ceil_w_d.
1434 
1435  // 3 RD (round down, or toward −infinity): Round a result to
1436  // the next representable value down. Behave like floor_w_d.
1437  switch (get_fcsr_rounding_mode()) {
1438  case kRoundToNearest:
1439  rounded = std::floor(fs + 0.5);
1440  rounded_int = static_cast<int32_t>(rounded);
1441  if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1442  // If the number is halfway between two integers,
1443  // round to the even one.
1444  rounded_int--;
1445  rounded -= 1.;
1446  }
1447  break;
1448  case kRoundToZero:
1449  rounded = trunc(fs);
1450  rounded_int = static_cast<int32_t>(rounded);
1451  break;
1452  case kRoundToPlusInf:
1453  rounded = std::ceil(fs);
1454  rounded_int = static_cast<int32_t>(rounded);
1455  break;
1456  case kRoundToMinusInf:
1457  rounded = std::floor(fs);
1458  rounded_int = static_cast<int32_t>(rounded);
1459  break;
1460  }
1461 }
1462 
1463 
1464 void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1465  int32_t& rounded_int, float fs) {
1466  // 0 RN (round to nearest): Round a result to the nearest
1467  // representable value; if the result is exactly halfway between
1468  // two representable values, round to zero. Behave like round_w_d.
1469 
1470  // 1 RZ (round toward zero): Round a result to the closest
1471  // representable value whose absolute value is less than or
1472  // equal to the infinitely accurate result. Behave like trunc_w_d.
1473 
1474  // 2 RP (round up, or toward infinity): Round a result to the
1475  // next representable value up. Behave like ceil_w_d.
1476 
1477  // 3 RD (round down, or toward −infinity): Round a result to
1478  // the next representable value down. Behave like floor_w_d.
1479  switch (get_fcsr_rounding_mode()) {
1480  case kRoundToNearest:
1481  rounded = std::floor(fs + 0.5);
1482  rounded_int = static_cast<int32_t>(rounded);
1483  if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1484  // If the number is halfway between two integers,
1485  // round to the even one.
1486  rounded_int--;
1487  rounded -= 1.f;
1488  }
1489  break;
1490  case kRoundToZero:
1491  rounded = trunc(fs);
1492  rounded_int = static_cast<int32_t>(rounded);
1493  break;
1494  case kRoundToPlusInf:
1495  rounded = std::ceil(fs);
1496  rounded_int = static_cast<int32_t>(rounded);
1497  break;
1498  case kRoundToMinusInf:
1499  rounded = std::floor(fs);
1500  rounded_int = static_cast<int32_t>(rounded);
1501  break;
1502  }
1503 }
1504 
1505 template <typename T_fp, typename T_int>
1506 void Simulator::round_according_to_msacsr(T_fp toRound, T_fp& rounded,
1507  T_int& rounded_int) {
1508  // 0 RN (round to nearest): Round a result to the nearest
1509  // representable value; if the result is exactly halfway between
1510  // two representable values, round to zero. Behave like round_w_d.
1511 
1512  // 1 RZ (round toward zero): Round a result to the closest
1513  // representable value whose absolute value is less than or
1514  // equal to the infinitely accurate result. Behave like trunc_w_d.
1515 
1516  // 2 RP (round up, or toward infinity): Round a result to the
1517  // next representable value up. Behave like ceil_w_d.
1518 
1519  // 3 RD (round down, or toward −infinity): Round a result to
1520  // the next representable value down. Behave like floor_w_d.
1521  switch (get_msacsr_rounding_mode()) {
1522  case kRoundToNearest:
1523  rounded = std::floor(toRound + 0.5);
1524  rounded_int = static_cast<T_int>(rounded);
1525  if ((rounded_int & 1) != 0 && rounded_int - toRound == 0.5) {
1526  // If the number is halfway between two integers,
1527  // round to the even one.
1528  rounded_int--;
1529  rounded -= 1;
1530  }
1531  break;
1532  case kRoundToZero:
1533  rounded = trunc(toRound);
1534  rounded_int = static_cast<T_int>(rounded);
1535  break;
1536  case kRoundToPlusInf:
1537  rounded = std::ceil(toRound);
1538  rounded_int = static_cast<T_int>(rounded);
1539  break;
1540  case kRoundToMinusInf:
1541  rounded = std::floor(toRound);
1542  rounded_int = static_cast<T_int>(rounded);
1543  break;
1544  }
1545 }
1546 
1547 void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1548  int64_t& rounded_int, double fs) {
1549  // 0 RN (round to nearest): Round a result to the nearest
1550  // representable value; if the result is exactly halfway between
1551  // two representable values, round to zero. Behave like round_w_d.
1552 
1553  // 1 RZ (round toward zero): Round a result to the closest
1554  // representable value whose absolute value is less than or.
1555  // equal to the infinitely accurate result. Behave like trunc_w_d.
1556 
1557  // 2 RP (round up, or toward +infinity): Round a result to the
1558  // next representable value up. Behave like ceil_w_d.
1559 
1560  // 3 RN (round down, or toward −infinity): Round a result to
1561  // the next representable value down. Behave like floor_w_d.
1562  switch (FCSR_ & 3) {
1563  case kRoundToNearest:
1564  rounded = std::floor(fs + 0.5);
1565  rounded_int = static_cast<int64_t>(rounded);
1566  if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1567  // If the number is halfway between two integers,
1568  // round to the even one.
1569  rounded_int--;
1570  rounded -= 1.;
1571  }
1572  break;
1573  case kRoundToZero:
1574  rounded = trunc(fs);
1575  rounded_int = static_cast<int64_t>(rounded);
1576  break;
1577  case kRoundToPlusInf:
1578  rounded = std::ceil(fs);
1579  rounded_int = static_cast<int64_t>(rounded);
1580  break;
1581  case kRoundToMinusInf:
1582  rounded = std::floor(fs);
1583  rounded_int = static_cast<int64_t>(rounded);
1584  break;
1585  }
1586 }
1587 
1588 
1589 void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1590  int64_t& rounded_int, float fs) {
1591  // 0 RN (round to nearest): Round a result to the nearest
1592  // representable value; if the result is exactly halfway between
1593  // two representable values, round to zero. Behave like round_w_d.
1594 
1595  // 1 RZ (round toward zero): Round a result to the closest
1596  // representable value whose absolute value is less than or.
1597  // equal to the infinitely accurate result. Behave like trunc_w_d.
1598 
1599  // 2 RP (round up, or toward +infinity): Round a result to the
1600  // next representable value up. Behave like ceil_w_d.
1601 
1602  // 3 RN (round down, or toward −infinity): Round a result to
1603  // the next representable value down. Behave like floor_w_d.
1604  switch (FCSR_ & 3) {
1605  case kRoundToNearest:
1606  rounded = std::floor(fs + 0.5);
1607  rounded_int = static_cast<int64_t>(rounded);
1608  if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1609  // If the number is halfway between two integers,
1610  // round to the even one.
1611  rounded_int--;
1612  rounded -= 1.f;
1613  }
1614  break;
1615  case kRoundToZero:
1616  rounded = trunc(fs);
1617  rounded_int = static_cast<int64_t>(rounded);
1618  break;
1619  case kRoundToPlusInf:
1620  rounded = std::ceil(fs);
1621  rounded_int = static_cast<int64_t>(rounded);
1622  break;
1623  case kRoundToMinusInf:
1624  rounded = std::floor(fs);
1625  rounded_int = static_cast<int64_t>(rounded);
1626  break;
1627  }
1628 }
1629 
1630 
1631 // Raw access to the PC register.
1632 void Simulator::set_pc(int32_t value) {
1633  pc_modified_ = true;
1634  registers_[pc] = value;
1635 }
1636 
1637 
1638 bool Simulator::has_bad_pc() const {
1639  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1640 }
1641 
1642 
1643 // Raw access to the PC register without the special adjustment when reading.
1644 int32_t Simulator::get_pc() const {
1645  return registers_[pc];
1646 }
1647 
1648 
1649 // The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1650 // interrupt is caused. On others it does a funky rotation thing. For now we
1651 // simply disallow unaligned reads, but at some point we may want to move to
1652 // emulating the rotate behaviour. Note that simulator runs have the runtime
1653 // system running directly on the host system and only generated code is
1654 // executed in the simulator. Since the host is typically IA32 we will not
1655 // get the correct MIPS-like behaviour on unaligned accesses.
1656 
1657 void Simulator::TraceRegWr(int32_t value, TraceType t) {
1658  if (::v8::internal::FLAG_trace_sim) {
1659  union {
1660  int32_t fmt_int32;
1661  float fmt_float;
1662  } v;
1663  v.fmt_int32 = value;
1664 
1665  switch (t) {
1666  case WORD:
1667  SNPrintF(trace_buf_, "%08" PRIx32 " (%" PRIu64 ") int32:%" PRId32
1668  " uint32:%" PRIu32,
1669  value, icount_, value, value);
1670  break;
1671  case FLOAT:
1672  SNPrintF(trace_buf_, "%08" PRIx32 " (%" PRIu64 ") flt:%e",
1673  v.fmt_int32, icount_, v.fmt_float);
1674  break;
1675  default:
1676  UNREACHABLE();
1677  }
1678  }
1679 }
1680 
1681 void Simulator::TraceRegWr(int64_t value, TraceType t) {
1682  if (::v8::internal::FLAG_trace_sim) {
1683  union {
1684  int64_t fmt_int64;
1685  double fmt_double;
1686  } v;
1687  v.fmt_int64 = value;
1688 
1689  switch (t) {
1690  case DWORD:
1691  SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRIu64 ") int64:%" PRId64
1692  " uint64:%" PRIu64,
1693  value, icount_, value, value);
1694  break;
1695  case DOUBLE:
1696  SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRIu64 ") dbl:%e",
1697  v.fmt_int64, icount_, v.fmt_double);
1698  break;
1699  default:
1700  UNREACHABLE();
1701  }
1702  }
1703 }
1704 
1705 template <typename T>
1706 void Simulator::TraceMSARegWr(T* value, TraceType t) {
1707  if (::v8::internal::FLAG_trace_sim) {
1708  union {
1709  uint8_t b[16];
1710  uint16_t h[8];
1711  uint32_t w[4];
1712  uint64_t d[2];
1713  float f[4];
1714  double df[2];
1715  } v;
1716  memcpy(v.b, value, kSimd128Size);
1717  switch (t) {
1718  case BYTE:
1719  SNPrintF(trace_buf_,
1720  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
1721  v.d[0], v.d[1], icount_);
1722  break;
1723  case HALF:
1724  SNPrintF(trace_buf_,
1725  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
1726  v.d[0], v.d[1], icount_);
1727  break;
1728  case WORD:
1729  SNPrintF(trace_buf_,
1730  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1731  ") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
1732  " %" PRId32,
1733  v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1734  break;
1735  case DWORD:
1736  SNPrintF(trace_buf_,
1737  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
1738  v.d[0], v.d[1], icount_);
1739  break;
1740  case FLOAT:
1741  SNPrintF(trace_buf_,
1742  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1743  ") flt[0..3]:%e %e %e %e",
1744  v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1745  break;
1746  case DOUBLE:
1747  SNPrintF(trace_buf_,
1748  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1749  ") dbl[0..1]:%e %e",
1750  v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1751  break;
1752  default:
1753  UNREACHABLE();
1754  }
1755  }
1756 }
1757 
1758 template <typename T>
1759 void Simulator::TraceMSARegWr(T* value) {
1760  if (::v8::internal::FLAG_trace_sim) {
1761  union {
1762  uint8_t b[kMSALanesByte];
1763  uint16_t h[kMSALanesHalf];
1764  uint32_t w[kMSALanesWord];
1765  uint64_t d[kMSALanesDword];
1766  float f[kMSALanesWord];
1767  double df[kMSALanesDword];
1768  } v;
1769  memcpy(v.b, value, kMSALanesByte);
1770 
1771  if (std::is_same<T, int32_t>::value) {
1772  SNPrintF(trace_buf_,
1773  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1774  ") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
1775  " %" PRId32,
1776  v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1777  } else if (std::is_same<T, float>::value) {
1778  SNPrintF(trace_buf_,
1779  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1780  ") flt[0..3]:%e %e %e %e",
1781  v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1782  } else if (std::is_same<T, double>::value) {
1783  SNPrintF(trace_buf_,
1784  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1785  ") dbl[0..1]:%e %e",
1786  v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1787  } else {
1788  SNPrintF(trace_buf_,
1789  "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
1790  v.d[0], v.d[1], icount_);
1791  }
1792  }
1793 }
1794 
1795 // TODO(plind): consider making icount_ printing a flag option.
1796 void Simulator::TraceMemRd(int32_t addr, int32_t value, TraceType t) {
1797  if (::v8::internal::FLAG_trace_sim) {
1798  union {
1799  int32_t fmt_int32;
1800  float fmt_float;
1801  } v;
1802  v.fmt_int32 = value;
1803 
1804  switch (t) {
1805  case WORD:
1806  SNPrintF(trace_buf_, "%08" PRIx32 " <-- [%08" PRIx32 "] (%" PRIu64
1807  ") int32:%" PRId32 " uint32:%" PRIu32,
1808  value, addr, icount_, value, value);
1809  break;
1810  case FLOAT:
1811  SNPrintF(trace_buf_,
1812  "%08" PRIx32 " <-- [%08" PRIx32 "] (%" PRIu64 ") flt:%e",
1813  v.fmt_int32, addr, icount_, v.fmt_float);
1814  break;
1815  default:
1816  UNREACHABLE();
1817  }
1818  }
1819 }
1820 
1821 
1822 void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1823  if (::v8::internal::FLAG_trace_sim) {
1824  switch (t) {
1825  case BYTE:
1826  SNPrintF(trace_buf_,
1827  " %02" PRIx8 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1828  static_cast<uint8_t>(value), addr, icount_);
1829  break;
1830  case HALF:
1831  SNPrintF(trace_buf_,
1832  " %04" PRIx16 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1833  static_cast<uint16_t>(value), addr, icount_);
1834  break;
1835  case WORD:
1836  SNPrintF(trace_buf_,
1837  "%08" PRIx32 " --> [%08" PRIx32 "] (%" PRIu64 ")", value,
1838  addr, icount_);
1839  break;
1840  default:
1841  UNREACHABLE();
1842  }
1843  }
1844 }
1845 
1846 template <typename T>
1847 void Simulator::TraceMemRd(int32_t addr, T value) {
1848  if (::v8::internal::FLAG_trace_sim) {
1849  switch (sizeof(T)) {
1850  case 1:
1851  SNPrintF(trace_buf_,
1852  "%08" PRIx8 " <-- [%08" PRIx32 "] (%" PRIu64
1853  ") int8:%" PRId8 " uint8:%" PRIu8,
1854  static_cast<uint8_t>(value), addr, icount_,
1855  static_cast<int8_t>(value), static_cast<uint8_t>(value));
1856  break;
1857  case 2:
1858  SNPrintF(trace_buf_,
1859  "%08" PRIx16 " <-- [%08" PRIx32 "] (%" PRIu64
1860  ") int16:%" PRId16 " uint16:%" PRIu16,
1861  static_cast<uint16_t>(value), addr, icount_,
1862  static_cast<int16_t>(value), static_cast<uint16_t>(value));
1863  break;
1864  case 4:
1865  SNPrintF(trace_buf_,
1866  "%08" PRIx32 " <-- [%08" PRIx32 "] (%" PRIu64
1867  ") int32:%" PRId32 " uint32:%" PRIu32,
1868  static_cast<uint32_t>(value), addr, icount_,
1869  static_cast<int32_t>(value), static_cast<uint32_t>(value));
1870  break;
1871  case 8:
1872  SNPrintF(trace_buf_,
1873  "%08" PRIx64 " <-- [%08" PRIx32 "] (%" PRIu64
1874  ") int64:%" PRId64 " uint64:%" PRIu64,
1875  static_cast<uint64_t>(value), addr, icount_,
1876  static_cast<int64_t>(value), static_cast<uint64_t>(value));
1877  break;
1878  default:
1879  UNREACHABLE();
1880  }
1881  }
1882 }
1883 
1884 template <typename T>
1885 void Simulator::TraceMemWr(int32_t addr, T value) {
1886  if (::v8::internal::FLAG_trace_sim) {
1887  switch (sizeof(T)) {
1888  case 1:
1889  SNPrintF(trace_buf_,
1890  " %02" PRIx8 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1891  static_cast<uint8_t>(value), addr, icount_);
1892  break;
1893  case 2:
1894  SNPrintF(trace_buf_,
1895  " %04" PRIx16 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1896  static_cast<uint16_t>(value), addr, icount_);
1897  break;
1898  case 4:
1899  SNPrintF(trace_buf_,
1900  "%08" PRIx32 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1901  static_cast<uint32_t>(value), addr, icount_);
1902  break;
1903  case 8:
1904  SNPrintF(trace_buf_,
1905  "%16" PRIx64 " --> [%08" PRIx32 "] (%" PRIu64 ")",
1906  static_cast<uint64_t>(value), addr, icount_);
1907  break;
1908  default:
1909  UNREACHABLE();
1910  }
1911  }
1912 }
1913 
1914 void Simulator::TraceMemRd(int32_t addr, int64_t value, TraceType t) {
1915  if (::v8::internal::FLAG_trace_sim) {
1916  union {
1917  int64_t fmt_int64;
1918  int32_t fmt_int32[2];
1919  float fmt_float[2];
1920  double fmt_double;
1921  } v;
1922  v.fmt_int64 = value;
1923 
1924  switch (t) {
1925  case DWORD:
1926  SNPrintF(trace_buf_, "%016" PRIx64 " <-- [%08" PRIx32 "] (%" PRIu64
1927  ") int64:%" PRId64 " uint64:%" PRIu64,
1928  v.fmt_int64, addr, icount_, v.fmt_int64, v.fmt_int64);
1929  break;
1930  case DOUBLE:
1931  SNPrintF(trace_buf_, "%016" PRIx64 " <-- [%08" PRIx32 "] (%" PRIu64
1932  ") dbl:%e",
1933  v.fmt_int64, addr, icount_, v.fmt_double);
1934  break;
1935  case FLOAT_DOUBLE:
1936  SNPrintF(trace_buf_, "%08" PRIx32 " <-- [%08" PRIx32 "] (%" PRIu64
1937  ") flt:%e dbl:%e",
1938  v.fmt_int32[1], addr, icount_, v.fmt_float[1], v.fmt_double);
1939  break;
1940  default:
1941  UNREACHABLE();
1942  }
1943  }
1944 }
1945 
1946 void Simulator::TraceMemWr(int32_t addr, int64_t value, TraceType t) {
1947  if (::v8::internal::FLAG_trace_sim) {
1948  switch (t) {
1949  case DWORD:
1950  SNPrintF(trace_buf_,
1951  "%016" PRIx64 " --> [%08" PRIx32 "] (%" PRIu64 ")", value,
1952  addr, icount_);
1953  break;
1954  default:
1955  UNREACHABLE();
1956  }
1957  }
1958 }
1959 
1960 int Simulator::ReadW(int32_t addr, Instruction* instr, TraceType t) {
1961  if (addr >=0 && addr < 0x400) {
1962  // This has to be a nullptr-dereference, drop into debugger.
1963  PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1964  reinterpret_cast<intptr_t>(instr));
1965  MipsDebugger dbg(this);
1966  dbg.Debug();
1967  }
1968  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1969  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1970  switch (t) {
1971  case WORD:
1972  TraceMemRd(addr, static_cast<int32_t>(*ptr), t);
1973  break;
1974  case FLOAT:
1975  // This TraceType is allowed but tracing for this value will be omitted.
1976  break;
1977  default:
1978  UNREACHABLE();
1979  }
1980  return *ptr;
1981  }
1982  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1983  addr,
1984  reinterpret_cast<intptr_t>(instr));
1985  MipsDebugger dbg(this);
1986  dbg.Debug();
1987  return 0;
1988 }
1989 
1990 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1991  if (addr >= 0 && addr < 0x400) {
1992  // This has to be a nullptr-dereference, drop into debugger.
1993  PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1994  reinterpret_cast<intptr_t>(instr));
1995  MipsDebugger dbg(this);
1996  dbg.Debug();
1997  }
1998  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1999  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
2000  TraceMemWr(addr, value, WORD);
2001  *ptr = value;
2002  return;
2003  }
2004  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2005  addr,
2006  reinterpret_cast<intptr_t>(instr));
2007  MipsDebugger dbg(this);
2008  dbg.Debug();
2009 }
2010 
2011 double Simulator::ReadD(int32_t addr, Instruction* instr) {
2012  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2013  double* ptr = reinterpret_cast<double*>(addr);
2014  return *ptr;
2015  }
2016  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2017  addr,
2018  reinterpret_cast<intptr_t>(instr));
2019  base::OS::Abort();
2020  return 0;
2021 }
2022 
2023 
2024 void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
2025  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2026  double* ptr = reinterpret_cast<double*>(addr);
2027  *ptr = value;
2028  return;
2029  }
2030  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2031  addr,
2032  reinterpret_cast<intptr_t>(instr));
2033  base::OS::Abort();
2034 }
2035 
2036 
2037 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
2038  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2039  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2040  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2041  return *ptr;
2042  }
2043  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2044  addr,
2045  reinterpret_cast<intptr_t>(instr));
2046  base::OS::Abort();
2047  return 0;
2048 }
2049 
2050 
2051 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
2052  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2053  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2054  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2055  return *ptr;
2056  }
2057  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2058  addr,
2059  reinterpret_cast<intptr_t>(instr));
2060  base::OS::Abort();
2061  return 0;
2062 }
2063 
2064 
2065 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
2066  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2067  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2068  TraceMemWr(addr, value, HALF);
2069  *ptr = value;
2070  return;
2071  }
2072  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2073  addr,
2074  reinterpret_cast<intptr_t>(instr));
2075  base::OS::Abort();
2076 }
2077 
2078 
2079 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
2080  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2081  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2082  TraceMemWr(addr, value, HALF);
2083  *ptr = value;
2084  return;
2085  }
2086  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2087  addr,
2088  reinterpret_cast<intptr_t>(instr));
2089  base::OS::Abort();
2090 }
2091 
2092 
2093 uint32_t Simulator::ReadBU(int32_t addr) {
2094  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2095  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2096  return *ptr & 0xFF;
2097 }
2098 
2099 
2100 int32_t Simulator::ReadB(int32_t addr) {
2101  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2102  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2103  return *ptr;
2104 }
2105 
2106 
2107 void Simulator::WriteB(int32_t addr, uint8_t value) {
2108  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2109  TraceMemWr(addr, value, BYTE);
2110  *ptr = value;
2111 }
2112 
2113 
2114 void Simulator::WriteB(int32_t addr, int8_t value) {
2115  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2116  TraceMemWr(addr, value, BYTE);
2117  *ptr = value;
2118 }
2119 
2120 template <typename T>
2121 T Simulator::ReadMem(int32_t addr, Instruction* instr) {
2122  int alignment_mask = (1 << sizeof(T)) - 1;
2123  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
2124  T* ptr = reinterpret_cast<T*>(addr);
2125  TraceMemRd(addr, *ptr);
2126  return *ptr;
2127  }
2128  PrintF("Unaligned read of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2129  sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2130  base::OS::Abort();
2131  return 0;
2132 }
2133 
2134 template <typename T>
2135 void Simulator::WriteMem(int32_t addr, T value, Instruction* instr) {
2136  int alignment_mask = (1 << sizeof(T)) - 1;
2137  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
2138  T* ptr = reinterpret_cast<T*>(addr);
2139  *ptr = value;
2140  TraceMemWr(addr, value);
2141  return;
2142  }
2143  PrintF("Unaligned write of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR
2144  "\n",
2145  sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2146  base::OS::Abort();
2147 }
2148 
2149 // Returns the limit of the stack area to enable checking for stack overflows.
2150 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
2151  // The simulator uses a separate JS stack. If we have exhausted the C stack,
2152  // we also drop down the JS limit to reflect the exhaustion on the JS stack.
2153  if (GetCurrentStackPosition() < c_limit) {
2154  return reinterpret_cast<uintptr_t>(get_sp());
2155  }
2156 
2157  // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
2158  // to prevent overrunning the stack when pushing values.
2159  return reinterpret_cast<uintptr_t>(stack_) + 1024;
2160 }
2161 
2162 
2163 // Unsupported instructions use Format to print an error and stop execution.
2164 void Simulator::Format(Instruction* instr, const char* format) {
2165  PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
2166  reinterpret_cast<intptr_t>(instr), format);
2167  UNIMPLEMENTED_MIPS();
2168 }
2169 
2170 
2171 // Calls into the V8 runtime are based on this very simple interface.
2172 // Note: To be able to return two values from some calls the code in runtime.cc
2173 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
2174 // 64-bit value. With the code below we assume that all runtime calls return
2175 // 64 bits of result. If they don't, the v1 result register contains a bogus
2176 // value, which is fine because it is caller-saved.
2177 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1,
2178  int32_t arg2, int32_t arg3,
2179  int32_t arg4, int32_t arg5,
2180  int32_t arg6, int32_t arg7,
2181  int32_t arg8);
2182 
2183 // These prototypes handle the four types of FP calls.
2184 typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
2185 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
2186 typedef double (*SimulatorRuntimeFPCall)(double darg0);
2187 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
2188 
2189 // This signature supports direct call in to API function native callback
2190 // (refer to InvocationCallback in v8.h).
2191 typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
2192 typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
2193 
2194 // This signature supports direct call to accessor getter callback.
2195 typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
2196 typedef void (*SimulatorRuntimeProfilingGetterCall)(
2197  int32_t arg0, int32_t arg1, void* arg2);
2198 
2199 // Software interrupt instructions are used by the simulator to call into the
2200 // C-based V8 runtime. They are also used for debugging with simulator.
2201 void Simulator::SoftwareInterrupt() {
2202  // There are several instructions that could get us here,
2203  // the break_ instruction, or several variants of traps. All
2204  // Are "SPECIAL" class opcode, and are distinuished by function.
2205  int32_t func = instr_.FunctionFieldRaw();
2206  uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
2207 
2208  // We first check if we met a call_rt_redirected.
2209  if (instr_.InstructionBits() == rtCallRedirInstr) {
2210  Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2211  int32_t arg0 = get_register(a0);
2212  int32_t arg1 = get_register(a1);
2213  int32_t arg2 = get_register(a2);
2214  int32_t arg3 = get_register(a3);
2215 
2216  int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
2217  // Args 4 and 5 are on the stack after the reserved space for args 0..3.
2218  int32_t arg4 = stack_pointer[4];
2219  int32_t arg5 = stack_pointer[5];
2220  int32_t arg6 = stack_pointer[6];
2221  int32_t arg7 = stack_pointer[7];
2222  int32_t arg8 = stack_pointer[8];
2223  STATIC_ASSERT(kMaxCParameters == 9);
2224 
2225  bool fp_call =
2226  (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2227  (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2228  (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2229  (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2230 
2231  if (!IsMipsSoftFloatABI) {
2232  // With the hard floating point calling convention, double
2233  // arguments are passed in FPU registers. Fetch the arguments
2234  // from there and call the builtin using soft floating point
2235  // convention.
2236  switch (redirection->type()) {
2237  case ExternalReference::BUILTIN_FP_FP_CALL:
2238  case ExternalReference::BUILTIN_COMPARE_CALL:
2239  if (IsFp64Mode()) {
2240  arg0 = get_fpu_register_word(f12);
2241  arg1 = get_fpu_register_hi_word(f12);
2242  arg2 = get_fpu_register_word(f14);
2243  arg3 = get_fpu_register_hi_word(f14);
2244  } else {
2245  arg0 = get_fpu_register_word(f12);
2246  arg1 = get_fpu_register_word(f13);
2247  arg2 = get_fpu_register_word(f14);
2248  arg3 = get_fpu_register_word(f15);
2249  }
2250  break;
2251  case ExternalReference::BUILTIN_FP_CALL:
2252  if (IsFp64Mode()) {
2253  arg0 = get_fpu_register_word(f12);
2254  arg1 = get_fpu_register_hi_word(f12);
2255  } else {
2256  arg0 = get_fpu_register_word(f12);
2257  arg1 = get_fpu_register_word(f13);
2258  }
2259  break;
2260  case ExternalReference::BUILTIN_FP_INT_CALL:
2261  if (IsFp64Mode()) {
2262  arg0 = get_fpu_register_word(f12);
2263  arg1 = get_fpu_register_hi_word(f12);
2264  } else {
2265  arg0 = get_fpu_register_word(f12);
2266  arg1 = get_fpu_register_word(f13);
2267  }
2268  arg2 = get_register(a2);
2269  break;
2270  default:
2271  break;
2272  }
2273  }
2274 
2275  // This is dodgy but it works because the C entry stubs are never moved.
2276  // See comment in codegen-arm.cc and bug 1242173.
2277  int32_t saved_ra = get_register(ra);
2278 
2279  intptr_t external =
2280  reinterpret_cast<intptr_t>(redirection->external_function());
2281 
2282  // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2283  // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2284  // simulator. Soft-float has additional abstraction of ExternalReference,
2285  // to support serialization.
2286  if (fp_call) {
2287  double dval0, dval1; // one or two double parameters
2288  int32_t ival; // zero or one integer parameters
2289  int64_t iresult = 0; // integer return value
2290  double dresult = 0; // double return value
2291  GetFpArgs(&dval0, &dval1, &ival);
2292  SimulatorRuntimeCall generic_target =
2293  reinterpret_cast<SimulatorRuntimeCall>(external);
2294  if (::v8::internal::FLAG_trace_sim) {
2295  switch (redirection->type()) {
2296  case ExternalReference::BUILTIN_FP_FP_CALL:
2297  case ExternalReference::BUILTIN_COMPARE_CALL:
2298  PrintF("Call to host function at %p with args %f, %f",
2299  reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2300  dval0, dval1);
2301  break;
2302  case ExternalReference::BUILTIN_FP_CALL:
2303  PrintF("Call to host function at %p with arg %f",
2304  reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2305  dval0);
2306  break;
2307  case ExternalReference::BUILTIN_FP_INT_CALL:
2308  PrintF("Call to host function at %p with args %f, %d",
2309  reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2310  dval0, ival);
2311  break;
2312  default:
2313  UNREACHABLE();
2314  break;
2315  }
2316  }
2317  switch (redirection->type()) {
2318  case ExternalReference::BUILTIN_COMPARE_CALL: {
2319  SimulatorRuntimeCompareCall target =
2320  reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2321  iresult = target(dval0, dval1);
2322  set_register(v0, static_cast<int32_t>(iresult));
2323  set_register(v1, static_cast<int32_t>(iresult >> 32));
2324  break;
2325  }
2326  case ExternalReference::BUILTIN_FP_FP_CALL: {
2327  SimulatorRuntimeFPFPCall target =
2328  reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2329  dresult = target(dval0, dval1);
2330  SetFpResult(dresult);
2331  break;
2332  }
2333  case ExternalReference::BUILTIN_FP_CALL: {
2334  SimulatorRuntimeFPCall target =
2335  reinterpret_cast<SimulatorRuntimeFPCall>(external);
2336  dresult = target(dval0);
2337  SetFpResult(dresult);
2338  break;
2339  }
2340  case ExternalReference::BUILTIN_FP_INT_CALL: {
2341  SimulatorRuntimeFPIntCall target =
2342  reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2343  dresult = target(dval0, ival);
2344  SetFpResult(dresult);
2345  break;
2346  }
2347  default:
2348  UNREACHABLE();
2349  break;
2350  }
2351  if (::v8::internal::FLAG_trace_sim) {
2352  switch (redirection->type()) {
2353  case ExternalReference::BUILTIN_COMPARE_CALL:
2354  PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2355  break;
2356  case ExternalReference::BUILTIN_FP_FP_CALL:
2357  case ExternalReference::BUILTIN_FP_CALL:
2358  case ExternalReference::BUILTIN_FP_INT_CALL:
2359  PrintF("Returned %f\n", dresult);
2360  break;
2361  default:
2362  UNREACHABLE();
2363  break;
2364  }
2365  }
2366  } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2367  if (::v8::internal::FLAG_trace_sim) {
2368  PrintF("Call to host function at %p args %08x\n",
2369  reinterpret_cast<void*>(external), arg0);
2370  }
2371  SimulatorRuntimeDirectApiCall target =
2372  reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2373  target(arg0);
2374  } else if (
2375  redirection->type() == ExternalReference::PROFILING_API_CALL) {
2376  if (::v8::internal::FLAG_trace_sim) {
2377  PrintF("Call to host function at %p args %08x %08x\n",
2378  reinterpret_cast<void*>(external), arg0, arg1);
2379  }
2380  SimulatorRuntimeProfilingApiCall target =
2381  reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2382  target(arg0, Redirection::ReverseRedirection(arg1));
2383  } else if (
2384  redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2385  if (::v8::internal::FLAG_trace_sim) {
2386  PrintF("Call to host function at %p args %08x %08x\n",
2387  reinterpret_cast<void*>(external), arg0, arg1);
2388  }
2389  SimulatorRuntimeDirectGetterCall target =
2390  reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2391  target(arg0, arg1);
2392  } else if (
2393  redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2394  if (::v8::internal::FLAG_trace_sim) {
2395  PrintF("Call to host function at %p args %08x %08x %08x\n",
2396  reinterpret_cast<void*>(external), arg0, arg1, arg2);
2397  }
2398  SimulatorRuntimeProfilingGetterCall target =
2399  reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2400  target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2401  } else {
2402  DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2403  redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2404  SimulatorRuntimeCall target =
2405  reinterpret_cast<SimulatorRuntimeCall>(external);
2406  if (::v8::internal::FLAG_trace_sim) {
2407  PrintF(
2408  "Call to host function at %p "
2409  "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
2410  reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
2411  arg3, arg4, arg5, arg6, arg7, arg8);
2412  }
2413  int64_t result =
2414  target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
2415  set_register(v0, static_cast<int32_t>(result));
2416  set_register(v1, static_cast<int32_t>(result >> 32));
2417  }
2418  if (::v8::internal::FLAG_trace_sim) {
2419  PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
2420  }
2421  set_register(ra, saved_ra);
2422  set_pc(get_register(ra));
2423 
2424  } else if (func == BREAK && code <= kMaxStopCode) {
2425  if (IsWatchpoint(code)) {
2426  PrintWatchpoint(code);
2427  } else {
2428  IncreaseStopCounter(code);
2429  HandleStop(code, instr_.instr());
2430  }
2431  } else {
2432  // All remaining break_ codes, and all traps are handled here.
2433  MipsDebugger dbg(this);
2434  dbg.Debug();
2435  }
2436 }
2437 
2438 
2439 // Stop helper functions.
2440 bool Simulator::IsWatchpoint(uint32_t code) {
2441  return (code <= kMaxWatchpointCode);
2442 }
2443 
2444 
2445 void Simulator::PrintWatchpoint(uint32_t code) {
2446  MipsDebugger dbg(this);
2447  ++break_count_;
2448  PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64
2449  ") ----------"
2450  "----------------------------------",
2451  code, break_count_, icount_);
2452  dbg.PrintAllRegs(); // Print registers and continue running.
2453 }
2454 
2455 
2456 void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2457  // Stop if it is enabled, otherwise go on jumping over the stop
2458  // and the message address.
2459  if (IsEnabledStop(code)) {
2460  MipsDebugger dbg(this);
2461  dbg.Stop(instr);
2462  }
2463 }
2464 
2465 
2466 bool Simulator::IsStopInstruction(Instruction* instr) {
2467  int32_t func = instr->FunctionFieldRaw();
2468  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2469  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2470 }
2471 
2472 
2473 bool Simulator::IsEnabledStop(uint32_t code) {
2474  DCHECK_LE(code, kMaxStopCode);
2475  DCHECK_GT(code, kMaxWatchpointCode);
2476  return !(watched_stops_[code].count & kStopDisabledBit);
2477 }
2478 
2479 
2480 void Simulator::EnableStop(uint32_t code) {
2481  if (!IsEnabledStop(code)) {
2482  watched_stops_[code].count &= ~kStopDisabledBit;
2483  }
2484 }
2485 
2486 
2487 void Simulator::DisableStop(uint32_t code) {
2488  if (IsEnabledStop(code)) {
2489  watched_stops_[code].count |= kStopDisabledBit;
2490  }
2491 }
2492 
2493 
2494 void Simulator::IncreaseStopCounter(uint32_t code) {
2495  DCHECK_LE(code, kMaxStopCode);
2496  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2497  PrintF("Stop counter for code %i has overflowed.\n"
2498  "Enabling this code and reseting the counter to 0.\n", code);
2499  watched_stops_[code].count = 0;
2500  EnableStop(code);
2501  } else {
2502  watched_stops_[code].count++;
2503  }
2504 }
2505 
2506 
2507 // Print a stop status.
2508 void Simulator::PrintStopInfo(uint32_t code) {
2509  if (code <= kMaxWatchpointCode) {
2510  PrintF("That is a watchpoint, not a stop.\n");
2511  return;
2512  } else if (code > kMaxStopCode) {
2513  PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2514  return;
2515  }
2516  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2517  int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2518  // Don't print the state of unused breakpoints.
2519  if (count != 0) {
2520  if (watched_stops_[code].desc) {
2521  PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
2522  code, code, state, count, watched_stops_[code].desc);
2523  } else {
2524  PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2525  code, code, state, count);
2526  }
2527  }
2528 }
2529 
2530 
2531 void Simulator::SignalException(Exception e) {
2532  FATAL("Error: Exception %i raised.", static_cast<int>(e));
2533 }
2534 
2535 // Min/Max template functions for Double and Single arguments.
2536 
2537 template <typename T>
2538 static T FPAbs(T a);
2539 
2540 template <>
2541 double FPAbs<double>(double a) {
2542  return fabs(a);
2543 }
2544 
2545 template <>
2546 float FPAbs<float>(float a) {
2547  return fabsf(a);
2548 }
2549 
2550 template <typename T>
2551 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2552  if (std::isnan(a) && std::isnan(b)) {
2553  result = a;
2554  } else if (std::isnan(a)) {
2555  result = b;
2556  } else if (std::isnan(b)) {
2557  result = a;
2558  } else if (b == a) {
2559  // Handle -0.0 == 0.0 case.
2560  // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2561  // negates the result.
2562  result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2563  } else {
2564  return false;
2565  }
2566  return true;
2567 }
2568 
2569 template <typename T>
2570 static T FPUMin(T a, T b) {
2571  T result;
2572  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2573  return result;
2574  } else {
2575  return b < a ? b : a;
2576  }
2577 }
2578 
2579 template <typename T>
2580 static T FPUMax(T a, T b) {
2581  T result;
2582  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2583  return result;
2584  } else {
2585  return b > a ? b : a;
2586  }
2587 }
2588 
2589 template <typename T>
2590 static T FPUMinA(T a, T b) {
2591  T result;
2592  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2593  if (FPAbs(a) < FPAbs(b)) {
2594  result = a;
2595  } else if (FPAbs(b) < FPAbs(a)) {
2596  result = b;
2597  } else {
2598  result = a < b ? a : b;
2599  }
2600  }
2601  return result;
2602 }
2603 
2604 template <typename T>
2605 static T FPUMaxA(T a, T b) {
2606  T result;
2607  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2608  if (FPAbs(a) > FPAbs(b)) {
2609  result = a;
2610  } else if (FPAbs(b) > FPAbs(a)) {
2611  result = b;
2612  } else {
2613  result = a > b ? a : b;
2614  }
2615  }
2616  return result;
2617 }
2618 
2619 enum class KeepSign : bool { no = false, yes };
2620 
2621 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2622  int>::type = 0>
2623 T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2624  DCHECK(std::isnan(arg));
2625  T qNaN = std::numeric_limits<T>::quiet_NaN();
2626  if (keepSign == KeepSign::yes) {
2627  return std::copysign(qNaN, result);
2628  }
2629  return qNaN;
2630 }
2631 
2632 template <typename T>
2633 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2634  if (std::isnan(first)) {
2635  return FPUCanonalizeNaNArg(result, first, keepSign);
2636  }
2637  return result;
2638 }
2639 
2640 template <typename T, typename... Args>
2641 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2642  if (std::isnan(first)) {
2643  return FPUCanonalizeNaNArg(result, first, keepSign);
2644  }
2645  return FPUCanonalizeNaNArgs(result, keepSign, args...);
2646 }
2647 
2648 template <typename Func, typename T, typename... Args>
2649 T FPUCanonalizeOperation(Func f, T first, Args... args) {
2650  return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2651 }
2652 
2653 template <typename Func, typename T, typename... Args>
2654 T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2655  T result = f(first, args...);
2656  if (std::isnan(result)) {
2657  result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2658  }
2659  return result;
2660 }
2661 
2662 // Handle execution based on instruction types.
2663 
2664 void Simulator::DecodeTypeRegisterDRsType() {
2665  double ft, fs, fd;
2666  uint32_t cc, fcsr_cc;
2667  int64_t i64;
2668  fs = get_fpu_register_double(fs_reg());
2669  ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
2670  : 0.0;
2671  fd = get_fpu_register_double(fd_reg());
2672  int64_t ft_int = bit_cast<int64_t>(ft);
2673  int64_t fd_int = bit_cast<int64_t>(fd);
2674  cc = instr_.FCccValue();
2675  fcsr_cc = get_fcsr_condition_bit(cc);
2676  switch (instr_.FunctionFieldRaw()) {
2677  case RINT: {
2678  DCHECK(IsMipsArchVariant(kMips32r6));
2679  double result, temp, temp_result;
2680  double upper = std::ceil(fs);
2681  double lower = std::floor(fs);
2682  switch (get_fcsr_rounding_mode()) {
2683  case kRoundToNearest:
2684  if (upper - fs < fs - lower) {
2685  result = upper;
2686  } else if (upper - fs > fs - lower) {
2687  result = lower;
2688  } else {
2689  temp_result = upper / 2;
2690  double reminder = modf(temp_result, &temp);
2691  if (reminder == 0) {
2692  result = upper;
2693  } else {
2694  result = lower;
2695  }
2696  }
2697  break;
2698  case kRoundToZero:
2699  result = (fs > 0 ? lower : upper);
2700  break;
2701  case kRoundToPlusInf:
2702  result = upper;
2703  break;
2704  case kRoundToMinusInf:
2705  result = lower;
2706  break;
2707  }
2708  SetFPUDoubleResult(fd_reg(), result);
2709  if (result != fs) {
2710  set_fcsr_bit(kFCSRInexactFlagBit, true);
2711  }
2712  break;
2713  }
2714  case SEL:
2715  DCHECK(IsMipsArchVariant(kMips32r6));
2716  SetFPUDoubleResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2717  break;
2718  case SELEQZ_C:
2719  DCHECK(IsMipsArchVariant(kMips32r6));
2720  SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2721  break;
2722  case SELNEZ_C:
2723  DCHECK(IsMipsArchVariant(kMips32r6));
2724  SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2725  break;
2726  case MOVZ_C: {
2727  DCHECK(IsMipsArchVariant(kMips32r2));
2728  if (rt() == 0) {
2729  SetFPUDoubleResult(fd_reg(), fs);
2730  }
2731  break;
2732  }
2733  case MOVN_C: {
2734  DCHECK(IsMipsArchVariant(kMips32r2));
2735  int32_t rt_reg = instr_.RtValue();
2736  int32_t rt = get_register(rt_reg);
2737  if (rt != 0) {
2738  SetFPUDoubleResult(fd_reg(), fs);
2739  }
2740  break;
2741  }
2742  case MOVF: {
2743  // Same function field for MOVT.D and MOVF.D
2744  uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2745  ft_cc = get_fcsr_condition_bit(ft_cc);
2746  if (instr_.Bit(16)) { // Read Tf bit.
2747  // MOVT.D
2748  if (test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2749  } else {
2750  // MOVF.D
2751  if (!test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2752  }
2753  break;
2754  }
2755  case MIN:
2756  DCHECK(IsMipsArchVariant(kMips32r6));
2757  SetFPUDoubleResult(fd_reg(), FPUMin(ft, fs));
2758  break;
2759  case MAX:
2760  DCHECK(IsMipsArchVariant(kMips32r6));
2761  SetFPUDoubleResult(fd_reg(), FPUMax(ft, fs));
2762  break;
2763  case MINA:
2764  DCHECK(IsMipsArchVariant(kMips32r6));
2765  SetFPUDoubleResult(fd_reg(), FPUMinA(ft, fs));
2766  break;
2767  case MAXA:
2768  DCHECK(IsMipsArchVariant(kMips32r6));
2769  SetFPUDoubleResult(fd_reg(), FPUMaxA(ft, fs));
2770  break;
2771  case ADD_D:
2772  SetFPUDoubleResult(
2773  fd_reg(),
2774  FPUCanonalizeOperation(
2775  [](double lhs, double rhs) { return lhs + rhs; }, fs, ft));
2776  break;
2777  case SUB_D:
2778  SetFPUDoubleResult(
2779  fd_reg(),
2780  FPUCanonalizeOperation(
2781  [](double lhs, double rhs) { return lhs - rhs; }, fs, ft));
2782  break;
2783  case MADDF_D:
2784  DCHECK(IsMipsArchVariant(kMips32r6));
2785  SetFPUDoubleResult(fd_reg(), std::fma(fs, ft, fd));
2786  break;
2787  case MSUBF_D:
2788  DCHECK(IsMipsArchVariant(kMips32r6));
2789  SetFPUDoubleResult(fd_reg(), std::fma(-fs, ft, fd));
2790  break;
2791  case MUL_D:
2792  SetFPUDoubleResult(
2793  fd_reg(),
2794  FPUCanonalizeOperation(
2795  [](double lhs, double rhs) { return lhs * rhs; }, fs, ft));
2796  break;
2797  case DIV_D:
2798  SetFPUDoubleResult(
2799  fd_reg(),
2800  FPUCanonalizeOperation(
2801  [](double lhs, double rhs) { return lhs / rhs; }, fs, ft));
2802  break;
2803  case ABS_D:
2804  SetFPUDoubleResult(
2805  fd_reg(),
2806  FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs));
2807  break;
2808  case MOV_D:
2809  SetFPUDoubleResult(fd_reg(), fs);
2810  break;
2811  case NEG_D:
2812  SetFPUDoubleResult(fd_reg(),
2813  FPUCanonalizeOperation([](double src) { return -src; },
2814  KeepSign::yes, fs));
2815  break;
2816  case SQRT_D:
2817  SetFPUDoubleResult(
2818  fd_reg(),
2819  FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs));
2820  break;
2821  case RSQRT_D:
2822  SetFPUDoubleResult(
2823  fd_reg(), FPUCanonalizeOperation(
2824  [](double fs) { return 1.0 / std::sqrt(fs); }, fs));
2825  break;
2826  case RECIP_D:
2827  SetFPUDoubleResult(fd_reg(), FPUCanonalizeOperation(
2828  [](double fs) { return 1.0 / fs; }, fs));
2829  break;
2830  case C_UN_D:
2831  set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2832  TraceRegWr(test_fcsr_bit(fcsr_cc));
2833  break;
2834  case C_EQ_D:
2835  set_fcsr_bit(fcsr_cc, (fs == ft));
2836  TraceRegWr(test_fcsr_bit(fcsr_cc));
2837  break;
2838  case C_UEQ_D:
2839  set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2840  TraceRegWr(test_fcsr_bit(fcsr_cc));
2841  break;
2842  case C_OLT_D:
2843  set_fcsr_bit(fcsr_cc, (fs < ft));
2844  TraceRegWr(test_fcsr_bit(fcsr_cc));
2845  break;
2846  case C_ULT_D:
2847  set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2848  TraceRegWr(test_fcsr_bit(fcsr_cc));
2849  break;
2850  case C_OLE_D:
2851  set_fcsr_bit(fcsr_cc, (fs <= ft));
2852  TraceRegWr(test_fcsr_bit(fcsr_cc));
2853  break;
2854  case C_ULE_D:
2855  set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2856  TraceRegWr(test_fcsr_bit(fcsr_cc));
2857  break;
2858  case CVT_W_D: { // Convert double to word.
2859  double rounded;
2860  int32_t result;
2861  round_according_to_fcsr(fs, rounded, result, fs);
2862  SetFPUWordResult(fd_reg(), result);
2863  if (set_fcsr_round_error(fs, rounded)) {
2864  set_fpu_register_word_invalid_result(fs, rounded);
2865  }
2866  } break;
2867  case ROUND_W_D: // Round double to word (round half to even).
2868  {
2869  double rounded = std::floor(fs + 0.5);
2870  int32_t result = static_cast<int32_t>(rounded);
2871  if ((result & 1) != 0 && result - fs == 0.5) {
2872  // If the number is halfway between two integers,
2873  // round to the even one.
2874  result--;
2875  }
2876  SetFPUWordResult(fd_reg(), result);
2877  if (set_fcsr_round_error(fs, rounded)) {
2878  set_fpu_register_word_invalid_result(fs, rounded);
2879  }
2880  } break;
2881  case TRUNC_W_D: // Truncate double to word (round towards 0).
2882  {
2883  double rounded = trunc(fs);
2884  int32_t result = static_cast<int32_t>(rounded);
2885  SetFPUWordResult(fd_reg(), result);
2886  if (set_fcsr_round_error(fs, rounded)) {
2887  set_fpu_register_word_invalid_result(fs, rounded);
2888  }
2889  } break;
2890  case FLOOR_W_D: // Round double to word towards negative infinity.
2891  {
2892  double rounded = std::floor(fs);
2893  int32_t result = static_cast<int32_t>(rounded);
2894  SetFPUWordResult(fd_reg(), result);
2895  if (set_fcsr_round_error(fs, rounded)) {
2896  set_fpu_register_word_invalid_result(fs, rounded);
2897  }
2898  } break;
2899  case CEIL_W_D: // Round double to word towards positive infinity.
2900  {
2901  double rounded = std::ceil(fs);
2902  int32_t result = static_cast<int32_t>(rounded);
2903  SetFPUWordResult(fd_reg(), result);
2904  if (set_fcsr_round_error(fs, rounded)) {
2905  set_fpu_register_word_invalid_result(fs, rounded);
2906  }
2907  } break;
2908  case CVT_S_D: // Convert double to float (single).
2909  SetFPUFloatResult(fd_reg(), static_cast<float>(fs));
2910  break;
2911  case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2912  if (IsFp64Mode()) {
2913  int64_t result;
2914  double rounded;
2915  round64_according_to_fcsr(fs, rounded, result, fs);
2916  SetFPUResult(fd_reg(), result);
2917  if (set_fcsr_round64_error(fs, rounded)) {
2918  set_fpu_register_invalid_result64(fs, rounded);
2919  }
2920  } else {
2921  UNSUPPORTED();
2922  }
2923  break;
2924  break;
2925  }
2926  case TRUNC_L_D: { // Mips32r2 instruction.
2927  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2928  double rounded = trunc(fs);
2929  i64 = static_cast<int64_t>(rounded);
2930  if (IsFp64Mode()) {
2931  SetFPUResult(fd_reg(), i64);
2932  if (set_fcsr_round64_error(fs, rounded)) {
2933  set_fpu_register_invalid_result64(fs, rounded);
2934  }
2935  } else {
2936  UNSUPPORTED();
2937  }
2938  break;
2939  }
2940  case ROUND_L_D: { // Mips32r2 instruction.
2941  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2942  double rounded = std::floor(fs + 0.5);
2943  int64_t result = static_cast<int64_t>(rounded);
2944  if ((result & 1) != 0 && result - fs == 0.5) {
2945  // If the number is halfway between two integers,
2946  // round to the even one.
2947  result--;
2948  }
2949  int64_t i64 = static_cast<int64_t>(result);
2950  if (IsFp64Mode()) {
2951  SetFPUResult(fd_reg(), i64);
2952  if (set_fcsr_round64_error(fs, rounded)) {
2953  set_fpu_register_invalid_result64(fs, rounded);
2954  }
2955  } else {
2956  UNSUPPORTED();
2957  }
2958  break;
2959  }
2960  case FLOOR_L_D: { // Mips32r2 instruction.
2961  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2962  double rounded = std::floor(fs);
2963  int64_t i64 = static_cast<int64_t>(rounded);
2964  if (IsFp64Mode()) {
2965  SetFPUResult(fd_reg(), i64);
2966  if (set_fcsr_round64_error(fs, rounded)) {
2967  set_fpu_register_invalid_result64(fs, rounded);
2968  }
2969  } else {
2970  UNSUPPORTED();
2971  }
2972  break;
2973  }
2974  case CEIL_L_D: { // Mips32r2 instruction.
2975  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2976  double rounded = std::ceil(fs);
2977  int64_t i64 = static_cast<int64_t>(rounded);
2978  if (IsFp64Mode()) {
2979  SetFPUResult(fd_reg(), i64);
2980  if (set_fcsr_round64_error(fs, rounded)) {
2981  set_fpu_register_invalid_result64(fs, rounded);
2982  }
2983  } else {
2984  UNSUPPORTED();
2985  }
2986  break;
2987  }
2988  case CLASS_D: { // Mips32r6 instruction
2989  // Convert double input to uint64_t for easier bit manipulation
2990  uint64_t classed = bit_cast<uint64_t>(fs);
2991 
2992  // Extracting sign, exponent and mantissa from the input double
2993  uint32_t sign = (classed >> 63) & 1;
2994  uint32_t exponent = (classed >> 52) & 0x00000000000007FF;
2995  uint64_t mantissa = classed & 0x000FFFFFFFFFFFFF;
2996  uint64_t result;
2997  double dResult;
2998 
2999  // Setting flags if input double is negative infinity,
3000  // positive infinity, negative zero or positive zero
3001  bool negInf = (classed == 0xFFF0000000000000);
3002  bool posInf = (classed == 0x7FF0000000000000);
3003  bool negZero = (classed == 0x8000000000000000);
3004  bool posZero = (classed == 0x0000000000000000);
3005 
3006  bool signalingNan;
3007  bool quietNan;
3008  bool negSubnorm;
3009  bool posSubnorm;
3010  bool negNorm;
3011  bool posNorm;
3012 
3013  // Setting flags if double is NaN
3014  signalingNan = false;
3015  quietNan = false;
3016  if (!negInf && !posInf && exponent == 0x7FF) {
3017  quietNan = ((mantissa & 0x0008000000000000) != 0) &&
3018  ((mantissa & (0x0008000000000000 - 1)) == 0);
3019  signalingNan = !quietNan;
3020  }
3021 
3022  // Setting flags if double is subnormal number
3023  posSubnorm = false;
3024  negSubnorm = false;
3025  if ((exponent == 0) && (mantissa != 0)) {
3026  DCHECK(sign == 0 || sign == 1);
3027  posSubnorm = (sign == 0);
3028  negSubnorm = (sign == 1);
3029  }
3030 
3031  // Setting flags if double is normal number
3032  posNorm = false;
3033  negNorm = false;
3034  if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3035  !quietNan && !negZero && !posZero) {
3036  DCHECK(sign == 0 || sign == 1);
3037  posNorm = (sign == 0);
3038  negNorm = (sign == 1);
3039  }
3040 
3041  // Calculating result according to description of CLASS.D instruction
3042  result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3043  (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3044  (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3045 
3046  DCHECK_NE(result, 0);
3047 
3048  dResult = bit_cast<double>(result);
3049  SetFPUDoubleResult(fd_reg(), dResult);
3050 
3051  break;
3052  }
3053  case C_F_D: {
3054  set_fcsr_bit(fcsr_cc, false);
3055  TraceRegWr(test_fcsr_bit(fcsr_cc));
3056  break;
3057  }
3058  default:
3059  UNREACHABLE();
3060  }
3061 }
3062 
3063 
3064 void Simulator::DecodeTypeRegisterWRsType() {
3065  float fs = get_fpu_register_float(fs_reg());
3066  float ft = get_fpu_register_float(ft_reg());
3067  int32_t alu_out = 0x12345678;
3068  switch (instr_.FunctionFieldRaw()) {
3069  case CVT_S_W: // Convert word to float (single).
3070  alu_out = get_fpu_register_signed_word(fs_reg());
3071  SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
3072  break;
3073  case CVT_D_W: // Convert word to double.
3074  alu_out = get_fpu_register_signed_word(fs_reg());
3075  SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
3076  break;
3077  case CMP_AF:
3078  SetFPUWordResult(fd_reg(), 0);
3079  break;
3080  case CMP_UN:
3081  if (std::isnan(fs) || std::isnan(ft)) {
3082  SetFPUWordResult(fd_reg(), -1);
3083  } else {
3084  SetFPUWordResult(fd_reg(), 0);
3085  }
3086  break;
3087  case CMP_EQ:
3088  if (fs == ft) {
3089  SetFPUWordResult(fd_reg(), -1);
3090  } else {
3091  SetFPUWordResult(fd_reg(), 0);
3092  }
3093  break;
3094  case CMP_UEQ:
3095  if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3096  SetFPUWordResult(fd_reg(), -1);
3097  } else {
3098  SetFPUWordResult(fd_reg(), 0);
3099  }
3100  break;
3101  case CMP_LT:
3102  if (fs < ft) {
3103  SetFPUWordResult(fd_reg(), -1);
3104  } else {
3105  SetFPUWordResult(fd_reg(), 0);
3106  }
3107  break;
3108  case CMP_ULT:
3109  if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3110  SetFPUWordResult(fd_reg(), -1);
3111  } else {
3112  SetFPUWordResult(fd_reg(), 0);
3113  }
3114  break;
3115  case CMP_LE:
3116  if (fs <= ft) {
3117  SetFPUWordResult(fd_reg(), -1);
3118  } else {
3119  SetFPUWordResult(fd_reg(), 0);
3120  }
3121  break;
3122  case CMP_ULE:
3123  if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3124  SetFPUWordResult(fd_reg(), -1);
3125  } else {
3126  SetFPUWordResult(fd_reg(), 0);
3127  }
3128  break;
3129  case CMP_OR:
3130  if (!std::isnan(fs) && !std::isnan(ft)) {
3131  SetFPUWordResult(fd_reg(), -1);
3132  } else {
3133  SetFPUWordResult(fd_reg(), 0);
3134  }
3135  break;
3136  case CMP_UNE:
3137  if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3138  SetFPUWordResult(fd_reg(), -1);
3139  } else {
3140  SetFPUWordResult(fd_reg(), 0);
3141  }
3142  break;
3143  case CMP_NE:
3144  if (fs != ft) {
3145  SetFPUWordResult(fd_reg(), -1);
3146  } else {
3147  SetFPUWordResult(fd_reg(), 0);
3148  }
3149  break;
3150  default:
3151  UNREACHABLE();
3152  }
3153 }
3154 
3155 
3156 void Simulator::DecodeTypeRegisterSRsType() {
3157  float fs, ft, fd;
3158  fs = get_fpu_register_float(fs_reg());
3159  ft = get_fpu_register_float(ft_reg());
3160  fd = get_fpu_register_float(fd_reg());
3161  int32_t ft_int = bit_cast<int32_t>(ft);
3162  int32_t fd_int = bit_cast<int32_t>(fd);
3163  uint32_t cc, fcsr_cc;
3164  cc = instr_.FCccValue();
3165  fcsr_cc = get_fcsr_condition_bit(cc);
3166  switch (instr_.FunctionFieldRaw()) {
3167  case RINT: {
3168  DCHECK(IsMipsArchVariant(kMips32r6));
3169  float result, temp_result;
3170  double temp;
3171  float upper = std::ceil(fs);
3172  float lower = std::floor(fs);
3173  switch (get_fcsr_rounding_mode()) {
3174  case kRoundToNearest:
3175  if (upper - fs < fs - lower) {
3176  result = upper;
3177  } else if (upper - fs > fs - lower) {
3178  result = lower;
3179  } else {
3180  temp_result = upper / 2;
3181  float reminder = modf(temp_result, &temp);
3182  if (reminder == 0) {
3183  result = upper;
3184  } else {
3185  result = lower;
3186  }
3187  }
3188  break;
3189  case kRoundToZero:
3190  result = (fs > 0 ? lower : upper);
3191  break;
3192  case kRoundToPlusInf:
3193  result = upper;
3194  break;
3195  case kRoundToMinusInf:
3196  result = lower;
3197  break;
3198  }
3199  SetFPUFloatResult(fd_reg(), result);
3200  if (result != fs) {
3201  set_fcsr_bit(kFCSRInexactFlagBit, true);
3202  }
3203  break;
3204  }
3205  case ADD_S:
3206  SetFPUFloatResult(
3207  fd_reg(),
3208  FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
3209  fs, ft));
3210  break;
3211  case SUB_S:
3212  SetFPUFloatResult(
3213  fd_reg(),
3214  FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
3215  fs, ft));
3216  break;
3217  case MADDF_S:
3218  DCHECK(IsMipsArchVariant(kMips32r6));
3219  SetFPUFloatResult(fd_reg(), std::fma(fs, ft, fd));
3220  break;
3221  case MSUBF_S:
3222  DCHECK(IsMipsArchVariant(kMips32r6));
3223  SetFPUFloatResult(fd_reg(), std::fma(-fs, ft, fd));
3224  break;
3225  case MUL_S:
3226  SetFPUFloatResult(
3227  fd_reg(),
3228  FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
3229  fs, ft));
3230  break;
3231  case DIV_S:
3232  SetFPUFloatResult(
3233  fd_reg(),
3234  FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
3235  fs, ft));
3236  break;
3237  case ABS_S:
3238  SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
3239  [](float fs) { return FPAbs(fs); }, fs));
3240  break;
3241  case MOV_S:
3242  SetFPUFloatResult(fd_reg(), fs);
3243  break;
3244  case NEG_S:
3245  SetFPUFloatResult(fd_reg(),
3246  FPUCanonalizeOperation([](float src) { return -src; },
3247  KeepSign::yes, fs));
3248  break;
3249  case SQRT_S:
3250  SetFPUFloatResult(
3251  fd_reg(),
3252  FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs));
3253  break;
3254  case RSQRT_S:
3255  SetFPUFloatResult(
3256  fd_reg(), FPUCanonalizeOperation(
3257  [](float src) { return 1.0 / std::sqrt(src); }, fs));
3258  break;
3259  case RECIP_S:
3260  SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
3261  [](float src) { return 1.0 / src; }, fs));
3262  break;
3263  case C_F_D:
3264  set_fcsr_bit(fcsr_cc, false);
3265  TraceRegWr(test_fcsr_bit(fcsr_cc));
3266  break;
3267  case C_UN_D:
3268  set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
3269  TraceRegWr(test_fcsr_bit(fcsr_cc));
3270  break;
3271  case C_EQ_D:
3272  set_fcsr_bit(fcsr_cc, (fs == ft));
3273  TraceRegWr(test_fcsr_bit(fcsr_cc));
3274  break;
3275  case C_UEQ_D:
3276  set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
3277  TraceRegWr(test_fcsr_bit(fcsr_cc));
3278  break;
3279  case C_OLT_D:
3280  set_fcsr_bit(fcsr_cc, (fs < ft));
3281  TraceRegWr(test_fcsr_bit(fcsr_cc));
3282  break;
3283  case C_ULT_D:
3284  set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3285  TraceRegWr(test_fcsr_bit(fcsr_cc));
3286  break;
3287  case C_OLE_D:
3288  set_fcsr_bit(fcsr_cc, (fs <= ft));
3289  TraceRegWr(test_fcsr_bit(fcsr_cc));
3290  break;
3291  case C_ULE_D:
3292  set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3293  TraceRegWr(test_fcsr_bit(fcsr_cc));
3294  break;
3295  case CVT_D_S:
3296  SetFPUDoubleResult(fd_reg(), static_cast<double>(fs));
3297  break;
3298  case SEL:
3299  DCHECK(IsMipsArchVariant(kMips32r6));
3300  SetFPUFloatResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3301  break;
3302  case CLASS_S: { // Mips32r6 instruction
3303  // Convert float input to uint32_t for easier bit manipulation
3304  float fs = get_fpu_register_float(fs_reg());
3305  uint32_t classed = bit_cast<uint32_t>(fs);
3306 
3307  // Extracting sign, exponent and mantissa from the input float
3308  uint32_t sign = (classed >> 31) & 1;
3309  uint32_t exponent = (classed >> 23) & 0x000000FF;
3310  uint32_t mantissa = classed & 0x007FFFFF;
3311  uint32_t result;
3312  float fResult;
3313 
3314  // Setting flags if input float is negative infinity,
3315  // positive infinity, negative zero or positive zero
3316  bool negInf = (classed == 0xFF800000);
3317  bool posInf = (classed == 0x7F800000);
3318  bool negZero = (classed == 0x80000000);
3319  bool posZero = (classed == 0x00000000);
3320 
3321  bool signalingNan;
3322  bool quietNan;
3323  bool negSubnorm;
3324  bool posSubnorm;
3325  bool negNorm;
3326  bool posNorm;
3327 
3328  // Setting flags if float is NaN
3329  signalingNan = false;
3330  quietNan = false;
3331  if (!negInf && !posInf && (exponent == 0xFF)) {
3332  quietNan = ((mantissa & 0x00200000) == 0) &&
3333  ((mantissa & (0x00200000 - 1)) == 0);
3334  signalingNan = !quietNan;
3335  }
3336 
3337  // Setting flags if float is subnormal number
3338  posSubnorm = false;
3339  negSubnorm = false;
3340  if ((exponent == 0) && (mantissa != 0)) {
3341  DCHECK(sign == 0 || sign == 1);
3342  posSubnorm = (sign == 0);
3343  negSubnorm = (sign == 1);
3344  }
3345 
3346  // Setting flags if float is normal number
3347  posNorm = false;
3348  negNorm = false;
3349  if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3350  !quietNan && !negZero && !posZero) {
3351  DCHECK(sign == 0 || sign == 1);
3352  posNorm = (sign == 0);
3353  negNorm = (sign == 1);
3354  }
3355 
3356  // Calculating result according to description of CLASS.S instruction
3357  result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3358  (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3359  (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3360 
3361  DCHECK_NE(result, 0);
3362 
3363  fResult = bit_cast<float>(result);
3364  SetFPUFloatResult(fd_reg(), fResult);
3365 
3366  break;
3367  }
3368  case SELEQZ_C:
3369  DCHECK(IsMipsArchVariant(kMips32r6));
3370  SetFPUFloatResult(
3371  fd_reg(),
3372  (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg()) : 0.0);
3373  break;
3374  case SELNEZ_C:
3375  DCHECK(IsMipsArchVariant(kMips32r6));
3376  SetFPUFloatResult(
3377  fd_reg(),
3378  (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg()) : 0.0);
3379  break;
3380  case MOVZ_C: {
3381  DCHECK(IsMipsArchVariant(kMips32r2));
3382  if (rt() == 0) {
3383  SetFPUFloatResult(fd_reg(), fs);
3384  }
3385  break;
3386  }
3387  case MOVN_C: {
3388  DCHECK(IsMipsArchVariant(kMips32r2));
3389  if (rt() != 0) {
3390  SetFPUFloatResult(fd_reg(), fs);
3391  }
3392  break;
3393  }
3394  case MOVF: {
3395  // Same function field for MOVT.D and MOVF.D
3396  uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3397  ft_cc = get_fcsr_condition_bit(ft_cc);
3398 
3399  if (instr_.Bit(16)) { // Read Tf bit.
3400  // MOVT.D
3401  if (test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3402  } else {
3403  // MOVF.D
3404  if (!test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3405  }
3406  break;
3407  }
3408  case TRUNC_W_S: { // Truncate single to word (round towards 0).
3409  float rounded = trunc(fs);
3410  int32_t result = static_cast<int32_t>(rounded);
3411  SetFPUWordResult(fd_reg(), result);
3412  if (set_fcsr_round_error(fs, rounded)) {
3413  set_fpu_register_word_invalid_result(fs, rounded);
3414  }
3415  } break;
3416  case TRUNC_L_S: { // Mips32r2 instruction.
3417  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3418  float rounded = trunc(fs);
3419  int64_t i64 = static_cast<int64_t>(rounded);
3420  if (IsFp64Mode()) {
3421  SetFPUResult(fd_reg(), i64);
3422  if (set_fcsr_round64_error(fs, rounded)) {
3423  set_fpu_register_invalid_result64(fs, rounded);
3424  }
3425  } else {
3426  UNSUPPORTED();
3427  }
3428  break;
3429  }
3430  case FLOOR_W_S: // Round double to word towards negative infinity.
3431  {
3432  float rounded = std::floor(fs);
3433  int32_t result = static_cast<int32_t>(rounded);
3434  SetFPUWordResult(fd_reg(), result);
3435  if (set_fcsr_round_error(fs, rounded)) {
3436  set_fpu_register_word_invalid_result(fs, rounded);
3437  }
3438  } break;
3439  case FLOOR_L_S: { // Mips32r2 instruction.
3440  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3441  float rounded = std::floor(fs);
3442  int64_t i64 = static_cast<int64_t>(rounded);
3443  if (IsFp64Mode()) {
3444  SetFPUResult(fd_reg(), i64);
3445  if (set_fcsr_round64_error(fs, rounded)) {
3446  set_fpu_register_invalid_result64(fs, rounded);
3447  }
3448  } else {
3449  UNSUPPORTED();
3450  }
3451  break;
3452  }
3453  case ROUND_W_S: {
3454  float rounded = std::floor(fs + 0.5);
3455  int32_t result = static_cast<int32_t>(rounded);
3456  if ((result & 1) != 0 && result - fs == 0.5) {
3457  // If the number is halfway between two integers,
3458  // round to the even one.
3459  result--;
3460  }
3461  SetFPUWordResult(fd_reg(), result);
3462  if (set_fcsr_round_error(fs, rounded)) {
3463  set_fpu_register_word_invalid_result(fs, rounded);
3464  }
3465  break;
3466  }
3467  case ROUND_L_S: { // Mips32r2 instruction.
3468  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3469  float rounded = std::floor(fs + 0.5);
3470  int64_t result = static_cast<int64_t>(rounded);
3471  if ((result & 1) != 0 && result - fs == 0.5) {
3472  // If the number is halfway between two integers,
3473  // round to the even one.
3474  result--;
3475  }
3476  int64_t i64 = static_cast<int64_t>(result);
3477  if (IsFp64Mode()) {
3478  SetFPUResult(fd_reg(), i64);
3479  if (set_fcsr_round64_error(fs, rounded)) {
3480  set_fpu_register_invalid_result64(fs, rounded);
3481  }
3482  } else {
3483  UNSUPPORTED();
3484  }
3485  break;
3486  }
3487  case CEIL_W_S: // Round double to word towards positive infinity.
3488  {
3489  float rounded = std::ceil(fs);
3490  int32_t result = static_cast<int32_t>(rounded);
3491  SetFPUWordResult(fd_reg(), result);
3492  if (set_fcsr_round_error(fs, rounded)) {
3493  set_fpu_register_word_invalid_result(fs, rounded);
3494  }
3495  } break;
3496  case CEIL_L_S: { // Mips32r2 instruction.
3497  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3498  float rounded = std::ceil(fs);
3499  int64_t i64 = static_cast<int64_t>(rounded);
3500  if (IsFp64Mode()) {
3501  SetFPUResult(fd_reg(), i64);
3502  if (set_fcsr_round64_error(fs, rounded)) {
3503  set_fpu_register_invalid_result64(fs, rounded);
3504  }
3505  } else {
3506  UNSUPPORTED();
3507  }
3508  break;
3509  }
3510  case MIN:
3511  DCHECK(IsMipsArchVariant(kMips32r6));
3512  SetFPUFloatResult(fd_reg(), FPUMin(ft, fs));
3513  break;
3514  case MAX:
3515  DCHECK(IsMipsArchVariant(kMips32r6));
3516  SetFPUFloatResult(fd_reg(), FPUMax(ft, fs));
3517  break;
3518  case MINA:
3519  DCHECK(IsMipsArchVariant(kMips32r6));
3520  SetFPUFloatResult(fd_reg(), FPUMinA(ft, fs));
3521  break;
3522  case MAXA:
3523  DCHECK(IsMipsArchVariant(kMips32r6));
3524  SetFPUFloatResult(fd_reg(), FPUMaxA(ft, fs));
3525  break;
3526  case CVT_L_S: {
3527  if (IsFp64Mode()) {
3528  int64_t result;
3529  float rounded;
3530  round64_according_to_fcsr(fs, rounded, result, fs);
3531  SetFPUResult(fd_reg(), result);
3532  if (set_fcsr_round64_error(fs, rounded)) {
3533  set_fpu_register_invalid_result64(fs, rounded);
3534  }
3535  } else {
3536  UNSUPPORTED();
3537  }
3538  break;
3539  }
3540  case CVT_W_S: {
3541  float rounded;
3542  int32_t result;
3543  round_according_to_fcsr(fs, rounded, result, fs);
3544  SetFPUWordResult(fd_reg(), result);
3545  if (set_fcsr_round_error(fs, rounded)) {
3546  set_fpu_register_word_invalid_result(fs, rounded);
3547  }
3548  break;
3549  }
3550  default:
3551  // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3552  // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3553  UNREACHABLE();
3554  }
3555 }
3556 
3557 
3558 void Simulator::DecodeTypeRegisterLRsType() {
3559  double fs = get_fpu_register_double(fs_reg());
3560  double ft = get_fpu_register_double(ft_reg());
3561  switch (instr_.FunctionFieldRaw()) {
3562  case CVT_D_L: // Mips32r2 instruction.
3563  // Watch the signs here, we want 2 32-bit vals
3564  // to make a sign-64.
3565  int64_t i64;
3566  if (IsFp64Mode()) {
3567  i64 = get_fpu_register(fs_reg());
3568  } else {
3569  i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3570  i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3571  }
3572  SetFPUDoubleResult(fd_reg(), static_cast<double>(i64));
3573  break;
3574  case CVT_S_L:
3575  if (IsFp64Mode()) {
3576  i64 = get_fpu_register(fs_reg());
3577  } else {
3578  i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3579  i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3580  }
3581  SetFPUFloatResult(fd_reg(), static_cast<float>(i64));
3582  break;
3583  case CMP_AF: // Mips64r6 CMP.D instructions.
3584  SetFPUResult(fd_reg(), 0);
3585  break;
3586  case CMP_UN:
3587  if (std::isnan(fs) || std::isnan(ft)) {
3588  SetFPUResult(fd_reg(), -1);
3589  } else {
3590  SetFPUResult(fd_reg(), 0);
3591  }
3592  break;
3593  case CMP_EQ:
3594  if (fs == ft) {
3595  SetFPUResult(fd_reg(), -1);
3596  } else {
3597  SetFPUResult(fd_reg(), 0);
3598  }
3599  break;
3600  case CMP_UEQ:
3601  if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3602  SetFPUResult(fd_reg(), -1);
3603  } else {
3604  SetFPUResult(fd_reg(), 0);
3605  }
3606  break;
3607  case CMP_LT:
3608  if (fs < ft) {
3609  SetFPUResult(fd_reg(), -1);
3610  } else {
3611  SetFPUResult(fd_reg(), 0);
3612  }
3613  break;
3614  case CMP_ULT:
3615  if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3616  SetFPUResult(fd_reg(), -1);
3617  } else {
3618  SetFPUResult(fd_reg(), 0);
3619  }
3620  break;
3621  case CMP_LE:
3622  if (fs <= ft) {
3623  SetFPUResult(fd_reg(), -1);
3624  } else {
3625  SetFPUResult(fd_reg(), 0);
3626  }
3627  break;
3628  case CMP_ULE:
3629  if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3630  SetFPUResult(fd_reg(), -1);
3631  } else {
3632  SetFPUResult(fd_reg(), 0);
3633  }
3634  break;
3635  case CMP_OR:
3636  if (!std::isnan(fs) && !std::isnan(ft)) {
3637  SetFPUResult(fd_reg(), -1);
3638  } else {
3639  SetFPUResult(fd_reg(), 0);
3640  }
3641  break;
3642  case CMP_UNE:
3643  if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3644  SetFPUResult(fd_reg(), -1);
3645  } else {
3646  SetFPUResult(fd_reg(), 0);
3647  }
3648  break;
3649  case CMP_NE:
3650  if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3651  SetFPUResult(fd_reg(), -1);
3652  } else {
3653  SetFPUResult(fd_reg(), 0);
3654  }
3655  break;
3656  default:
3657  UNREACHABLE();
3658  }
3659 }
3660 
3661 
3662 void Simulator::DecodeTypeRegisterCOP1() {
3663  switch (instr_.RsFieldRaw()) {
3664  case CFC1:
3665  // At the moment only FCSR is supported.
3666  DCHECK_EQ(fs_reg(), kFCSRRegister);
3667  SetResult(rt_reg(), FCSR_);
3668  break;
3669  case MFC1:
3670  SetResult(rt_reg(), get_fpu_register_word(fs_reg()));
3671  break;
3672  case MFHC1:
3673  if (IsFp64Mode()) {
3674  SetResult(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3675  } else {
3676  SetResult(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3677  }
3678  break;
3679  case CTC1: {
3680  // At the moment only FCSR is supported.
3681  DCHECK_EQ(fs_reg(), kFCSRRegister);
3682  int32_t reg = registers_[rt_reg()];
3683  if (IsMipsArchVariant(kMips32r6)) {
3684  FCSR_ = reg | kFCSRNaN2008FlagMask;
3685  } else {
3686  DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3687  FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3688  }
3689  TraceRegWr(static_cast<int32_t>(FCSR_));
3690  break;
3691  }
3692  case MTC1:
3693  // Hardware writes upper 32-bits to zero on mtc1.
3694  set_fpu_register_hi_word(fs_reg(), 0);
3695  set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3696  TraceRegWr(get_fpu_register_word(fs_reg()), FLOAT);
3697  break;
3698  case MTHC1:
3699  if (IsFp64Mode()) {
3700  set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3701  TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3702  } else {
3703  set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3704  if (fs_reg() % 2) {
3705  TraceRegWr(get_fpu_register_word(fs_reg() + 1), FLOAT);
3706  } else {
3707  TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3708  }
3709  }
3710  break;
3711  case S: {
3712  DecodeTypeRegisterSRsType();
3713  break;
3714  }
3715  case D:
3716  DecodeTypeRegisterDRsType();
3717  break;
3718  case W:
3719  DecodeTypeRegisterWRsType();
3720  break;
3721  case L:
3722  DecodeTypeRegisterLRsType();
3723  break;
3724  case PS:
3725  // Not implemented.
3726  UNREACHABLE();
3727  default:
3728  UNREACHABLE();
3729  }
3730 }
3731 
3732 
3733 void Simulator::DecodeTypeRegisterCOP1X() {
3734  switch (instr_.FunctionFieldRaw()) {
3735  case MADD_S: {
3736  DCHECK(IsMipsArchVariant(kMips32r2));
3737  float fr, ft, fs;
3738  fr = get_fpu_register_float(fr_reg());
3739  fs = get_fpu_register_float(fs_reg());
3740  ft = get_fpu_register_float(ft_reg());
3741  SetFPUFloatResult(fd_reg(), fs * ft + fr);
3742  break;
3743  }
3744  case MSUB_S: {
3745  DCHECK(IsMipsArchVariant(kMips32r2));
3746  float fr, ft, fs;
3747  fr = get_fpu_register_float(fr_reg());
3748  fs = get_fpu_register_float(fs_reg());
3749  ft = get_fpu_register_float(ft_reg());
3750  SetFPUFloatResult(fd_reg(), fs * ft - fr);
3751  break;
3752  }
3753  case MADD_D: {
3754  DCHECK(IsMipsArchVariant(kMips32r2));
3755  double fr, ft, fs;
3756  fr = get_fpu_register_double(fr_reg());
3757  fs = get_fpu_register_double(fs_reg());
3758  ft = get_fpu_register_double(ft_reg());
3759  SetFPUDoubleResult(fd_reg(), fs * ft + fr);
3760  break;
3761  }
3762  case MSUB_D: {
3763  DCHECK(IsMipsArchVariant(kMips32r2));
3764  double fr, ft, fs;
3765  fr = get_fpu_register_double(fr_reg());
3766  fs = get_fpu_register_double(fs_reg());
3767  ft = get_fpu_register_double(ft_reg());
3768  SetFPUDoubleResult(fd_reg(), fs * ft - fr);
3769  break;
3770  }
3771  default:
3772  UNREACHABLE();
3773  }
3774 }
3775 
3776 
3777 void Simulator::DecodeTypeRegisterSPECIAL() {
3778  int64_t alu_out = 0x12345678;
3779  int64_t i64hilo = 0;
3780  uint64_t u64hilo = 0;
3781  bool do_interrupt = false;
3782 
3783  switch (instr_.FunctionFieldRaw()) {
3784  case SELEQZ_S:
3785  DCHECK(IsMipsArchVariant(kMips32r6));
3786  SetResult(rd_reg(), rt() == 0 ? rs() : 0);
3787  break;
3788  case SELNEZ_S:
3789  DCHECK(IsMipsArchVariant(kMips32r6));
3790  SetResult(rd_reg(), rt() != 0 ? rs() : 0);
3791  break;
3792  case JR: {
3793  int32_t next_pc = rs();
3794  int32_t current_pc = get_pc();
3795  Instruction* branch_delay_instr =
3796  reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3797  BranchDelayInstructionDecode(branch_delay_instr);
3798  set_pc(next_pc);
3799  pc_modified_ = true;
3800  break;
3801  }
3802  case JALR: {
3803  int32_t next_pc = rs();
3804  int32_t return_addr_reg = rd_reg();
3805  int32_t current_pc = get_pc();
3806  Instruction* branch_delay_instr =
3807  reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3808  BranchDelayInstructionDecode(branch_delay_instr);
3809  set_register(return_addr_reg, current_pc + 2 * kInstrSize);
3810  set_pc(next_pc);
3811  pc_modified_ = true;
3812  break;
3813  }
3814  case SLL:
3815  alu_out = rt() << sa();
3816  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3817  break;
3818  case SRL:
3819  if (rs_reg() == 0) {
3820  // Regular logical right shift of a word by a fixed number of
3821  // bits instruction. RS field is always equal to 0.
3822  alu_out = rt_u() >> sa();
3823  } else {
3824  // Logical right-rotate of a word by a fixed number of bits. This
3825  // is special case of SRL instruction, added in MIPS32 Release 2.
3826  // RS field is equal to 00001.
3827  alu_out = base::bits::RotateRight32(rt_u(), sa());
3828  }
3829  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3830  break;
3831  case SRA:
3832  alu_out = rt() >> sa();
3833  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3834  break;
3835  case SLLV:
3836  alu_out = rt() << rs();
3837  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3838  break;
3839  case SRLV:
3840  if (sa() == 0) {
3841  // Regular logical right-shift of a word by a variable number of
3842  // bits instruction. SA field is always equal to 0.
3843  alu_out = rt_u() >> rs();
3844  } else {
3845  // Logical right-rotate of a word by a variable number of bits.
3846  // This is special case od SRLV instruction, added in MIPS32
3847  // Release 2. SA field is equal to 00001.
3848  alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3849  }
3850  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3851  break;
3852  case SRAV:
3853  SetResult(rd_reg(), rt() >> rs());
3854  break;
3855  case LSA: {
3856  DCHECK(IsMipsArchVariant(kMips32r6));
3857  int8_t sa = lsa_sa() + 1;
3858  int32_t _rt = rt();
3859  int32_t _rs = rs();
3860  int32_t res = _rs << sa;
3861  res += _rt;
3862  DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3863  SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3864  break;
3865  }
3866  case MFHI: // MFHI == CLZ on R6.
3867  if (!IsMipsArchVariant(kMips32r6)) {
3868  DCHECK_EQ(sa(), 0);
3869  alu_out = get_register(HI);
3870  } else {
3871  // MIPS spec: If no bits were set in GPR rs, the result written to
3872  // GPR rd is 32.
3873  DCHECK_EQ(sa(), 1);
3874  alu_out = base::bits::CountLeadingZeros32(rs_u());
3875  }
3876  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3877  break;
3878  case MFLO:
3879  alu_out = get_register(LO);
3880  SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3881  break;
3882  // Instructions using HI and LO registers.
3883  case MULT:
3884  i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3885  if (!IsMipsArchVariant(kMips32r6)) {
3886  set_register(LO, static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3887  set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3888  } else {
3889  switch (sa()) {
3890  case MUL_OP:
3891  SetResult(rd_reg(), static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3892  break;
3893  case MUH_OP:
3894  SetResult(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3895  break;
3896  default:
3897  UNIMPLEMENTED_MIPS();
3898  break;
3899  }
3900  }
3901  break;
3902  case MULTU:
3903  u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3904  if (!IsMipsArchVariant(kMips32r6)) {
3905  set_register(LO, static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3906  set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3907  } else {
3908  switch (sa()) {
3909  case MUL_OP:
3910  SetResult(rd_reg(), static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3911  break;
3912  case MUH_OP:
3913  SetResult(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3914  break;
3915  default:
3916  UNIMPLEMENTED_MIPS();
3917  break;
3918  }
3919  }
3920  break;
3921  case DIV:
3922  if (IsMipsArchVariant(kMips32r6)) {
3923  switch (sa()) {
3924  case DIV_OP:
3925  if (rs() == INT_MIN && rt() == -1) {
3926  SetResult(rd_reg(), INT_MIN);
3927  } else if (rt() != 0) {
3928  SetResult(rd_reg(), rs() / rt());
3929  }
3930  break;
3931  case MOD_OP:
3932  if (rs() == INT_MIN && rt() == -1) {
3933  SetResult(rd_reg(), 0);
3934  } else if (rt() != 0) {
3935  SetResult(rd_reg(), rs() % rt());
3936  }
3937  break;
3938  default:
3939  UNIMPLEMENTED_MIPS();
3940  break;
3941  }
3942  } else {
3943  // Divide by zero and overflow was not checked in the
3944  // configuration step - div and divu do not raise exceptions. On
3945  // division by 0 the result will be UNPREDICTABLE. On overflow
3946  // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3947  if (rs() == INT_MIN && rt() == -1) {
3948  set_register(LO, INT_MIN);
3949  set_register(HI, 0);
3950  } else if (rt() != 0) {
3951  set_register(LO, rs() / rt());
3952  set_register(HI, rs() % rt());
3953  }
3954  }
3955  break;
3956  case DIVU:
3957  if (IsMipsArchVariant(kMips32r6)) {
3958  switch (sa()) {
3959  case DIV_OP:
3960  if (rt_u() != 0) {
3961  SetResult(rd_reg(), rs_u() / rt_u());
3962  }
3963  break;
3964  case MOD_OP:
3965  if (rt_u() != 0) {
3966  SetResult(rd_reg(), rs_u() % rt_u());
3967  }
3968  break;
3969  default:
3970  UNIMPLEMENTED_MIPS();
3971  break;
3972  }
3973  } else {
3974  if (rt_u() != 0) {
3975  set_register(LO, rs_u() / rt_u());
3976  set_register(HI, rs_u() % rt_u());
3977  }
3978  }
3979  break;
3980  case ADD:
3981  if (HaveSameSign(rs(), rt())) {
3982  if (rs() > 0) {
3983  if (rs() <= (Registers::kMaxValue - rt())) {
3984  SignalException(kIntegerOverflow);
3985  }
3986  } else if (rs() < 0) {
3987  if (rs() >= (Registers::kMinValue - rt())) {
3988  SignalException(kIntegerUnderflow);
3989  }
3990  }
3991  }
3992  SetResult(rd_reg(), rs() + rt());
3993  break;
3994  case ADDU:
3995  SetResult(rd_reg(), rs() + rt());
3996  break;
3997  case SUB:
3998  if (!HaveSameSign(rs(), rt())) {
3999  if (rs() > 0) {
4000  if (rs() <= (Registers::kMaxValue + rt())) {
4001  SignalException(kIntegerOverflow);
4002  }
4003  } else if (rs() < 0) {
4004  if (rs() >= (Registers::kMinValue + rt())) {
4005  SignalException(kIntegerUnderflow);
4006  }
4007  }
4008  }
4009  SetResult(rd_reg(), rs() - rt());
4010  break;
4011  case SUBU:
4012  SetResult(rd_reg(), rs() - rt());
4013  break;
4014  case AND:
4015  SetResult(rd_reg(), rs() & rt());
4016  break;
4017  case OR:
4018  SetResult(rd_reg(), rs() | rt());
4019  break;
4020  case XOR:
4021  SetResult(rd_reg(), rs() ^ rt());
4022  break;
4023  case NOR:
4024  SetResult(rd_reg(), ~(rs() | rt()));
4025  break;
4026  case SLT:
4027  SetResult(rd_reg(), rs() < rt() ? 1 : 0);
4028  break;
4029  case SLTU:
4030  SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
4031  break;
4032  // Break and trap instructions.
4033  case BREAK:
4034  do_interrupt = true;
4035  break;
4036  case TGE:
4037  do_interrupt = rs() >= rt();
4038  break;
4039  case TGEU:
4040  do_interrupt = rs_u() >= rt_u();
4041  break;
4042  case TLT:
4043  do_interrupt = rs() < rt();
4044  break;
4045  case TLTU:
4046  do_interrupt = rs_u() < rt_u();
4047  break;
4048  case TEQ:
4049  do_interrupt = rs() == rt();
4050  break;
4051  case TNE:
4052  do_interrupt = rs() != rt();
4053  break;
4054  case SYNC:
4055  // TODO(palfia): Ignore sync instruction for now.
4056  break;
4057  // Conditional moves.
4058  case MOVN:
4059  if (rt()) {
4060  SetResult(rd_reg(), rs());
4061  }
4062  break;
4063  case MOVCI: {
4064  uint32_t cc = instr_.FBccValue();
4065  uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4066  if (instr_.Bit(16)) { // Read Tf bit.
4067  if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
4068  } else {
4069  if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
4070  }
4071  break;
4072  }
4073  case MOVZ:
4074  if (!rt()) {
4075  SetResult(rd_reg(), rs());
4076  }
4077  break;
4078  default:
4079  UNREACHABLE();
4080  }
4081  if (do_interrupt) {
4082  SoftwareInterrupt();
4083  }
4084 }
4085 
4086 
4087 void Simulator::DecodeTypeRegisterSPECIAL2() {
4088  int32_t alu_out;
4089  switch (instr_.FunctionFieldRaw()) {
4090  case MUL:
4091  // Only the lower 32 bits are kept.
4092  alu_out = rs_u() * rt_u();
4093  // HI and LO are UNPREDICTABLE after the operation.
4094  set_register(LO, Unpredictable);
4095  set_register(HI, Unpredictable);
4096  break;
4097  case CLZ:
4098  // MIPS32 spec: If no bits were set in GPR rs, the result written to
4099  // GPR rd is 32.
4100  alu_out = base::bits::CountLeadingZeros32(rs_u());
4101  break;
4102  default:
4103  alu_out = 0x12345678;
4104  UNREACHABLE();
4105  }
4106  SetResult(rd_reg(), alu_out);
4107 }
4108 
4109 
4110 void Simulator::DecodeTypeRegisterSPECIAL3() {
4111  int32_t alu_out;
4112  switch (instr_.FunctionFieldRaw()) {
4113  case INS: { // Mips32r2 instruction.
4114  // Interpret rd field as 5-bit msb of insert.
4115  uint16_t msb = rd_reg();
4116  // Interpret sa field as 5-bit lsb of insert.
4117  uint16_t lsb = sa();
4118  uint16_t size = msb - lsb + 1;
4119  uint32_t mask;
4120  if (size < 32) {
4121  mask = (1 << size) - 1;
4122  } else {
4123  mask = std::numeric_limits<uint32_t>::max();
4124  }
4125  alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4126  // Ins instr leaves result in Rt, rather than Rd.
4127  SetResult(rt_reg(), alu_out);
4128  break;
4129  }
4130  case EXT: { // Mips32r2 instruction.
4131  // Interpret rd field as 5-bit msb of extract.
4132  uint16_t msb = rd_reg();
4133  // Interpret sa field as 5-bit lsb of extract.
4134  uint16_t lsb = sa();
4135  uint16_t size = msb + 1;
4136  uint32_t mask;
4137  if (size < 32) {
4138  mask = (1 << size) - 1;
4139  } else {
4140  mask = std::numeric_limits<uint32_t>::max();
4141  }
4142  alu_out = (rs_u() & (mask << lsb)) >> lsb;
4143  SetResult(rt_reg(), alu_out);
4144  break;
4145  }
4146  case BSHFL: {
4147  int sa = instr_.SaFieldRaw() >> kSaShift;
4148  switch (sa) {
4149  case BITSWAP: {
4150  uint32_t input = static_cast<uint32_t>(rt());
4151  uint32_t output = 0;
4152  uint8_t i_byte, o_byte;
4153 
4154  // Reverse the bit in byte for each individual byte
4155  for (int i = 0; i < 4; i++) {
4156  output = output >> 8;
4157  i_byte = input & 0xFF;
4158 
4159  // Fast way to reverse bits in byte
4160  // Devised by Sean Anderson, July 13, 2001
4161  o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4162  (i_byte * 0x8020LU & 0x88440LU)) *
4163  0x10101LU >>
4164  16);
4165 
4166  output = output | (static_cast<uint32_t>(o_byte << 24));
4167  input = input >> 8;
4168  }
4169 
4170  alu_out = static_cast<int32_t>(output);
4171  break;
4172  }
4173  case SEB: {
4174  uint8_t input = static_cast<uint8_t>(rt());
4175  uint32_t output = input;
4176  uint32_t mask = 0x00000080;
4177 
4178  // Extending sign
4179  if (mask & input) {
4180  output |= 0xFFFFFF00;
4181  }
4182 
4183  alu_out = static_cast<int32_t>(output);
4184  break;
4185  }
4186  case SEH: {
4187  uint16_t input = static_cast<uint16_t>(rt());
4188  uint32_t output = input;
4189  uint32_t mask = 0x00008000;
4190 
4191  // Extending sign
4192  if (mask & input) {
4193  output |= 0xFFFF0000;
4194  }
4195 
4196  alu_out = static_cast<int32_t>(output);
4197  break;
4198  }
4199  case WSBH: {
4200  uint32_t input = static_cast<uint32_t>(rt());
4201  uint32_t output = 0;
4202 
4203  uint32_t mask = 0xFF000000;
4204  for (int i = 0; i < 4; i++) {
4205  uint32_t tmp = mask & input;
4206  if (i % 2 == 0) {
4207  tmp = tmp >> 8;
4208  } else {
4209  tmp = tmp << 8;
4210  }
4211  output = output | tmp;
4212  mask = mask >> 8;
4213  }
4214 
4215  alu_out = static_cast<int32_t>(output);
4216  break;
4217  }
4218  default: {
4219  const uint8_t bp = instr_.Bp2Value();
4220  sa >>= kBp2Bits;
4221  switch (sa) {
4222  case ALIGN: {
4223  if (bp == 0) {
4224  alu_out = static_cast<int32_t>(rt());
4225  } else {
4226  uint32_t rt_hi = rt() << (8 * bp);
4227  uint32_t rs_lo = rs() >> (8 * (4 - bp));
4228  alu_out = static_cast<int32_t>(rt_hi | rs_lo);
4229  }
4230  break;
4231  }
4232  default:
4233  alu_out = 0x12345678;
4234  UNREACHABLE();
4235  break;
4236  }
4237  }
4238  }
4239  SetResult(rd_reg(), alu_out);
4240  break;
4241  }
4242  default:
4243  UNREACHABLE();
4244  }
4245 }
4246 
4247 int Simulator::DecodeMsaDataFormat() {
4248  int df = -1;
4249  if (instr_.IsMSABranchInstr()) {
4250  switch (instr_.RsFieldRaw()) {
4251  case BZ_V:
4252  case BNZ_V:
4253  df = MSA_VECT;
4254  break;
4255  case BZ_B:
4256  case BNZ_B:
4257  df = MSA_BYTE;
4258  break;
4259  case BZ_H:
4260  case BNZ_H:
4261  df = MSA_HALF;
4262  break;
4263  case BZ_W:
4264  case BNZ_W:
4265  df = MSA_WORD;
4266  break;
4267  case BZ_D:
4268  case BNZ_D:
4269  df = MSA_DWORD;
4270  break;
4271  default:
4272  UNREACHABLE();
4273  break;
4274  }
4275  } else {
4276  int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
4277  switch (instr_.MSAMinorOpcodeField()) {
4278  case kMsaMinorI5:
4279  case kMsaMinorI10:
4280  case kMsaMinor3R:
4281  df = DF[instr_.Bits(22, 21)];
4282  break;
4283  case kMsaMinorMI10:
4284  df = DF[instr_.Bits(1, 0)];
4285  break;
4286  case kMsaMinorBIT:
4287  df = DF[instr_.MsaBitDf()];
4288  break;
4289  case kMsaMinorELM:
4290  df = DF[instr_.MsaElmDf()];
4291  break;
4292  case kMsaMinor3RF: {
4293  uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
4294  switch (opcode) {
4295  case FEXDO:
4296  case FTQ:
4297  case MUL_Q:
4298  case MADD_Q:
4299  case MSUB_Q:
4300  case MULR_Q:
4301  case MADDR_Q:
4302  case MSUBR_Q:
4303  df = DF[1 + instr_.Bit(21)];
4304  break;
4305  default:
4306  df = DF[2 + instr_.Bit(21)];
4307  break;
4308  }
4309  } break;
4310  case kMsaMinor2R:
4311  df = DF[instr_.Bits(17, 16)];
4312  break;
4313  case kMsaMinor2RF:
4314  df = DF[2 + instr_.Bit(16)];
4315  break;
4316  default:
4317  UNREACHABLE();
4318  break;
4319  }
4320  }
4321  return df;
4322 }
4323 
4324 void Simulator::DecodeTypeMsaI8() {
4325  DCHECK(IsMipsArchVariant(kMips32r6));
4326  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4327  uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
4328  int8_t i8 = instr_.MsaImm8Value();
4329  msa_reg_t ws, wd;
4330 
4331  switch (opcode) {
4332  case ANDI_B:
4333  get_msa_register(instr_.WsValue(), ws.b);
4334  for (int i = 0; i < kMSALanesByte; i++) {
4335  wd.b[i] = ws.b[i] & i8;
4336  }
4337  set_msa_register(instr_.WdValue(), wd.b);
4338  TraceMSARegWr(wd.b);
4339  break;
4340  case ORI_B:
4341  get_msa_register(instr_.WsValue(), ws.b);
4342  for (int i = 0; i < kMSALanesByte; i++) {
4343  wd.b[i] = ws.b[i] | i8;
4344  }
4345  set_msa_register(instr_.WdValue(), wd.b);
4346  TraceMSARegWr(wd.b);
4347  break;
4348  case NORI_B:
4349  get_msa_register(instr_.WsValue(), ws.b);
4350  for (int i = 0; i < kMSALanesByte; i++) {
4351  wd.b[i] = ~(ws.b[i] | i8);
4352  }
4353  set_msa_register(instr_.WdValue(), wd.b);
4354  TraceMSARegWr(wd.b);
4355  break;
4356  case XORI_B:
4357  get_msa_register(instr_.WsValue(), ws.b);
4358  for (int i = 0; i < kMSALanesByte; i++) {
4359  wd.b[i] = ws.b[i] ^ i8;
4360  }
4361  set_msa_register(instr_.WdValue(), wd.b);
4362  TraceMSARegWr(wd.b);
4363  break;
4364  case BMNZI_B:
4365  get_msa_register(instr_.WsValue(), ws.b);
4366  get_msa_register(instr_.WdValue(), wd.b);
4367  for (int i = 0; i < kMSALanesByte; i++) {
4368  wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
4369  }
4370  set_msa_register(instr_.WdValue(), wd.b);
4371  TraceMSARegWr(wd.b);
4372  break;
4373  case BMZI_B:
4374  get_msa_register(instr_.WsValue(), ws.b);
4375  get_msa_register(instr_.WdValue(), wd.b);
4376  for (int i = 0; i < kMSALanesByte; i++) {
4377  wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
4378  }
4379  set_msa_register(instr_.WdValue(), wd.b);
4380  TraceMSARegWr(wd.b);
4381  break;
4382  case BSELI_B:
4383  get_msa_register(instr_.WsValue(), ws.b);
4384  get_msa_register(instr_.WdValue(), wd.b);
4385  for (int i = 0; i < kMSALanesByte; i++) {
4386  wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
4387  }
4388  set_msa_register(instr_.WdValue(), wd.b);
4389  TraceMSARegWr(wd.b);
4390  break;
4391  case SHF_B:
4392  get_msa_register(instr_.WsValue(), ws.b);
4393  for (int i = 0; i < kMSALanesByte; i++) {
4394  int j = i % 4;
4395  int k = (i8 >> (2 * j)) & 0x3;
4396  wd.b[i] = ws.b[i - j + k];
4397  }
4398  set_msa_register(instr_.WdValue(), wd.b);
4399  TraceMSARegWr(wd.b);
4400  break;
4401  case SHF_H:
4402  get_msa_register(instr_.WsValue(), ws.h);
4403  for (int i = 0; i < kMSALanesHalf; i++) {
4404  int j = i % 4;
4405  int k = (i8 >> (2 * j)) & 0x3;
4406  wd.h[i] = ws.h[i - j + k];
4407  }
4408  set_msa_register(instr_.WdValue(), wd.h);
4409  TraceMSARegWr(wd.h);
4410  break;
4411  case SHF_W:
4412  get_msa_register(instr_.WsValue(), ws.w);
4413  for (int i = 0; i < kMSALanesWord; i++) {
4414  int j = (i8 >> (2 * i)) & 0x3;
4415  wd.w[i] = ws.w[j];
4416  }
4417  set_msa_register(instr_.WdValue(), wd.w);
4418  TraceMSARegWr(wd.w);
4419  break;
4420  default:
4421  UNREACHABLE();
4422  }
4423 }
4424 
4425 template <typename T>
4426 T Simulator::MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5) {
4427  T res;
4428  uint32_t ui5 = i5 & 0x1Fu;
4429  uint64_t ws_u64 = static_cast<uint64_t>(ws);
4430  uint64_t ui5_u64 = static_cast<uint64_t>(ui5);
4431 
4432  switch (opcode) {
4433  case ADDVI:
4434  res = static_cast<T>(ws + ui5);
4435  break;
4436  case SUBVI:
4437  res = static_cast<T>(ws - ui5);
4438  break;
4439  case MAXI_S:
4440  res = static_cast<T>(Max(ws, static_cast<T>(i5)));
4441  break;
4442  case MINI_S:
4443  res = static_cast<T>(Min(ws, static_cast<T>(i5)));
4444  break;
4445  case MAXI_U:
4446  res = static_cast<T>(Max(ws_u64, ui5_u64));
4447  break;
4448  case MINI_U:
4449  res = static_cast<T>(Min(ws_u64, ui5_u64));
4450  break;
4451  case CEQI:
4452  res = static_cast<T>(!Compare(ws, static_cast<T>(i5)) ? -1ull : 0ull);
4453  break;
4454  case CLTI_S:
4455  res = static_cast<T>((Compare(ws, static_cast<T>(i5)) == -1) ? -1ull
4456  : 0ull);
4457  break;
4458  case CLTI_U:
4459  res = static_cast<T>((Compare(ws_u64, ui5_u64) == -1) ? -1ull : 0ull);
4460  break;
4461  case CLEI_S:
4462  res =
4463  static_cast<T>((Compare(ws, static_cast<T>(i5)) != 1) ? -1ull : 0ull);
4464  break;
4465  case CLEI_U:
4466  res = static_cast<T>((Compare(ws_u64, ui5_u64) != 1) ? -1ull : 0ull);
4467  break;
4468  default:
4469  UNREACHABLE();
4470  }
4471  return res;
4472 }
4473 
4474 void Simulator::DecodeTypeMsaI5() {
4475  DCHECK(IsMipsArchVariant(kMips32r6));
4476  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4477  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4478  msa_reg_t ws, wd;
4479 
4480  // sign extend 5bit value to int32_t
4481  int32_t i5 = static_cast<int32_t>(instr_.MsaImm5Value() << 27) >> 27;
4482 
4483 #define MSA_I5_DF(elem, num_of_lanes) \
4484  get_msa_register(instr_.WsValue(), ws.elem); \
4485  for (int i = 0; i < num_of_lanes; i++) { \
4486  wd.elem[i] = MsaI5InstrHelper(opcode, ws.elem[i], i5); \
4487  } \
4488  set_msa_register(instr_.WdValue(), wd.elem); \
4489  TraceMSARegWr(wd.elem)
4490 
4491  switch (DecodeMsaDataFormat()) {
4492  case MSA_BYTE:
4493  MSA_I5_DF(b, kMSALanesByte);
4494  break;
4495  case MSA_HALF:
4496  MSA_I5_DF(h, kMSALanesHalf);
4497  break;
4498  case MSA_WORD:
4499  MSA_I5_DF(w, kMSALanesWord);
4500  break;
4501  case MSA_DWORD:
4502  MSA_I5_DF(d, kMSALanesDword);
4503  break;
4504  default:
4505  UNREACHABLE();
4506  }
4507 #undef MSA_I5_DF
4508 }
4509 
4510 void Simulator::DecodeTypeMsaI10() {
4511  DCHECK(IsMipsArchVariant(kMips32r6));
4512  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4513  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4514  int64_t s10 = (static_cast<int64_t>(instr_.MsaImm10Value()) << 54) >> 54;
4515  msa_reg_t wd;
4516 
4517 #define MSA_I10_DF(elem, num_of_lanes, T) \
4518  for (int i = 0; i < num_of_lanes; ++i) { \
4519  wd.elem[i] = static_cast<T>(s10); \
4520  } \
4521  set_msa_register(instr_.WdValue(), wd.elem); \
4522  TraceMSARegWr(wd.elem)
4523 
4524  if (opcode == LDI) {
4525  switch (DecodeMsaDataFormat()) {
4526  case MSA_BYTE:
4527  MSA_I10_DF(b, kMSALanesByte, int8_t);
4528  break;
4529  case MSA_HALF:
4530  MSA_I10_DF(h, kMSALanesHalf, int16_t);
4531  break;
4532  case MSA_WORD:
4533  MSA_I10_DF(w, kMSALanesWord, int32_t);
4534  break;
4535  case MSA_DWORD:
4536  MSA_I10_DF(d, kMSALanesDword, int64_t);
4537  break;
4538  default:
4539  UNREACHABLE();
4540  }
4541  } else {
4542  UNREACHABLE();
4543  }
4544 #undef MSA_I10_DF
4545 }
4546 
4547 void Simulator::DecodeTypeMsaELM() {
4548  DCHECK(IsMipsArchVariant(kMips32r6));
4549  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4550  uint32_t opcode = instr_.InstructionBits() & kMsaLongerELMMask;
4551  int32_t n = instr_.MsaElmNValue();
4552  int32_t alu_out;
4553  switch (opcode) {
4554  case CTCMSA:
4555  DCHECK_EQ(sa(), kMSACSRRegister);
4556  MSACSR_ = bit_cast<uint32_t>(registers_[rd_reg()]);
4557  TraceRegWr(static_cast<int32_t>(MSACSR_));
4558  break;
4559  case CFCMSA:
4560  DCHECK_EQ(rd_reg(), kMSACSRRegister);
4561  SetResult(sa(), bit_cast<int32_t>(MSACSR_));
4562  break;
4563  case MOVE_V: {
4564  msa_reg_t ws;
4565  get_msa_register(ws_reg(), &ws);
4566  set_msa_register(wd_reg(), &ws);
4567  TraceMSARegWr(&ws);
4568  } break;
4569  default:
4570  opcode &= kMsaELMMask;
4571  switch (opcode) {
4572  case COPY_S:
4573  case COPY_U: {
4574  msa_reg_t ws;
4575  switch (DecodeMsaDataFormat()) {
4576  case MSA_BYTE: {
4577  DCHECK_LT(n, kMSALanesByte);
4578  get_msa_register(instr_.WsValue(), ws.b);
4579  alu_out = static_cast<int32_t>(ws.b[n]);
4580  SetResult(wd_reg(),
4581  (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
4582  break;
4583  }
4584  case MSA_HALF: {
4585  DCHECK_LT(n, kMSALanesHalf);
4586  get_msa_register(instr_.WsValue(), ws.h);
4587  alu_out = static_cast<int32_t>(ws.h[n]);
4588  SetResult(wd_reg(),
4589  (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
4590  break;
4591  }
4592  case MSA_WORD: {
4593  DCHECK_LT(n, kMSALanesWord);
4594  get_msa_register(instr_.WsValue(), ws.w);
4595  alu_out = static_cast<int32_t>(ws.w[n]);
4596  SetResult(wd_reg(), alu_out);
4597  break;
4598  }
4599  default:
4600  UNREACHABLE();
4601  }
4602  } break;
4603  case INSERT: {
4604  msa_reg_t wd;
4605  switch (DecodeMsaDataFormat()) {
4606  case MSA_BYTE: {
4607  DCHECK_LT(n, kMSALanesByte);
4608  int32_t rs = get_register(instr_.WsValue());
4609  get_msa_register(instr_.WdValue(), wd.b);
4610  wd.b[n] = rs & 0xFFu;
4611  set_msa_register(instr_.WdValue(), wd.b);
4612  TraceMSARegWr(wd.b);
4613  break;
4614  }
4615  case MSA_HALF: {
4616  DCHECK_LT(n, kMSALanesHalf);
4617  int32_t rs = get_register(instr_.WsValue());
4618  get_msa_register(instr_.WdValue(), wd.h);
4619  wd.h[n] = rs & 0xFFFFu;
4620  set_msa_register(instr_.WdValue(), wd.h);
4621  TraceMSARegWr(wd.h);
4622  break;
4623  }
4624  case MSA_WORD: {
4625  DCHECK_LT(n, kMSALanesWord);
4626  int32_t rs = get_register(instr_.WsValue());
4627  get_msa_register(instr_.WdValue(), wd.w);
4628  wd.w[n] = rs;
4629  set_msa_register(instr_.WdValue(), wd.w);
4630  TraceMSARegWr(wd.w);
4631  break;
4632  }
4633  default:
4634  UNREACHABLE();
4635  }
4636  } break;
4637  case SLDI: {
4638  uint8_t v[32];
4639  msa_reg_t ws;
4640  msa_reg_t wd;
4641  get_msa_register(ws_reg(), &ws);
4642  get_msa_register(wd_reg(), &wd);
4643 #define SLDI_DF(s, k) \
4644  for (unsigned i = 0; i < s; i++) { \
4645  v[i] = ws.b[s * k + i]; \
4646  v[i + s] = wd.b[s * k + i]; \
4647  } \
4648  for (unsigned i = 0; i < s; i++) { \
4649  wd.b[s * k + i] = v[i + n]; \
4650  }
4651  switch (DecodeMsaDataFormat()) {
4652  case MSA_BYTE:
4653  DCHECK(n < kMSALanesByte);
4654  SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
4655  break;
4656  case MSA_HALF:
4657  DCHECK(n < kMSALanesHalf);
4658  for (int k = 0; k < 2; ++k) {
4659  SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
4660  }
4661  break;
4662  case MSA_WORD:
4663  DCHECK(n < kMSALanesWord);
4664  for (int k = 0; k < 4; ++k) {
4665  SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
4666  }
4667  break;
4668  case MSA_DWORD:
4669  DCHECK(n < kMSALanesDword);
4670  for (int k = 0; k < 8; ++k) {
4671  SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
4672  }
4673  break;
4674  default:
4675  UNREACHABLE();
4676  }
4677  set_msa_register(wd_reg(), &wd);
4678  TraceMSARegWr(&wd);
4679  } break;
4680 #undef SLDI_DF
4681  case SPLATI:
4682  case INSVE:
4683  UNIMPLEMENTED();
4684  break;
4685  default:
4686  UNREACHABLE();
4687  }
4688  break;
4689  }
4690 }
4691 
4692 template <typename T>
4693 T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
4694  typedef typename std::make_unsigned<T>::type uT;
4695  T res;
4696  switch (opcode) {
4697  case SLLI:
4698  res = static_cast<T>(ws << m);
4699  break;
4700  case SRAI:
4701  res = static_cast<T>(ArithmeticShiftRight(ws, m));
4702  break;
4703  case SRLI:
4704  res = static_cast<T>(static_cast<uT>(ws) >> m);
4705  break;
4706  case BCLRI:
4707  res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
4708  break;
4709  case BSETI:
4710  res = static_cast<T>(static_cast<T>(1ull << m) | ws);
4711  break;
4712  case BNEGI:
4713  res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
4714  break;
4715  case BINSLI: {
4716  int elem_size = 8 * sizeof(T);
4717  int bits = m + 1;
4718  if (bits == elem_size) {
4719  res = static_cast<T>(ws);
4720  } else {
4721  uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
4722  res = static_cast<T>((static_cast<T>(mask) & ws) |
4723  (static_cast<T>(~mask) & wd));
4724  }
4725  } break;
4726  case BINSRI: {
4727  int elem_size = 8 * sizeof(T);
4728  int bits = m + 1;
4729  if (bits == elem_size) {
4730  res = static_cast<T>(ws);
4731  } else {
4732  uint64_t mask = (1ull << bits) - 1;
4733  res = static_cast<T>((static_cast<T>(mask) & ws) |
4734  (static_cast<T>(~mask) & wd));
4735  }
4736  } break;
4737  case SAT_S: {
4738 #define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
4739 #define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
4740  int shift = 64 - 8 * sizeof(T);
4741  int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
4742  res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
4743  ? M_MIN_INT(m + 1)
4744  : ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
4745  : ws_i64);
4746 #undef M_MAX_INT
4747 #undef M_MIN_INT
4748  } break;
4749  case SAT_U: {
4750 #define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
4751  uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
4752  uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
4753  res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
4754  : M_MAX_UINT(m + 1));
4755 #undef M_MAX_UINT
4756  } break;
4757  case SRARI:
4758  if (!m) {
4759  res = static_cast<T>(ws);
4760  } else {
4761  res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
4762  static_cast<T>((ws >> (m - 1)) & 0x1);
4763  }
4764  break;
4765  case SRLRI:
4766  if (!m) {
4767  res = static_cast<T>(ws);
4768  } else {
4769  res = static_cast<T>(static_cast<uT>(ws) >> m) +
4770  static_cast<T>((ws >> (m - 1)) & 0x1);
4771  }
4772  break;
4773  default:
4774  UNREACHABLE();
4775  }
4776  return res;
4777 }
4778 
4779 void Simulator::DecodeTypeMsaBIT() {
4780  DCHECK(IsMipsArchVariant(kMips32r6));
4781  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4782  uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
4783  int32_t m = instr_.MsaBitMValue();
4784  msa_reg_t wd, ws;
4785 
4786 #define MSA_BIT_DF(elem, num_of_lanes) \
4787  get_msa_register(instr_.WsValue(), ws.elem); \
4788  if (opcode == BINSLI || opcode == BINSRI) { \
4789  get_msa_register(instr_.WdValue(), wd.elem); \
4790  } \
4791  for (int i = 0; i < num_of_lanes; i++) { \
4792  wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
4793  } \
4794  set_msa_register(instr_.WdValue(), wd.elem); \
4795  TraceMSARegWr(wd.elem)
4796 
4797  switch (DecodeMsaDataFormat()) {
4798  case MSA_BYTE:
4799  DCHECK(m < kMSARegSize / kMSALanesByte);
4800  MSA_BIT_DF(b, kMSALanesByte);
4801  break;
4802  case MSA_HALF:
4803  DCHECK(m < kMSARegSize / kMSALanesHalf);
4804  MSA_BIT_DF(h, kMSALanesHalf);
4805  break;
4806  case MSA_WORD:
4807  DCHECK(m < kMSARegSize / kMSALanesWord);
4808  MSA_BIT_DF(w, kMSALanesWord);
4809  break;
4810  case MSA_DWORD:
4811  DCHECK(m < kMSARegSize / kMSALanesDword);
4812  MSA_BIT_DF(d, kMSALanesDword);
4813  break;
4814  default:
4815  UNREACHABLE();
4816  }
4817 #undef MSA_BIT_DF
4818 }
4819 
4820 void Simulator::DecodeTypeMsaMI10() {
4821  DCHECK(IsMipsArchVariant(kMips32r6));
4822  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4823  uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
4824  int32_t s10 = (static_cast<int32_t>(instr_.MsaImmMI10Value()) << 22) >> 22;
4825  int32_t rs = get_register(instr_.WsValue());
4826  int32_t addr;
4827  msa_reg_t wd;
4828 
4829 #define MSA_MI10_LOAD(elem, num_of_lanes, T) \
4830  for (int i = 0; i < num_of_lanes; ++i) { \
4831  addr = rs + (s10 + i) * sizeof(T); \
4832  wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
4833  } \
4834  set_msa_register(instr_.WdValue(), wd.elem);
4835 
4836 #define MSA_MI10_STORE(elem, num_of_lanes, T) \
4837  get_msa_register(instr_.WdValue(), wd.elem); \
4838  for (int i = 0; i < num_of_lanes; ++i) { \
4839  addr = rs + (s10 + i) * sizeof(T); \
4840  WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
4841  }
4842 
4843  if (opcode == MSA_LD) {
4844  switch (DecodeMsaDataFormat()) {
4845  case MSA_BYTE:
4846  MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
4847  break;
4848  case MSA_HALF:
4849  MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
4850  break;
4851  case MSA_WORD:
4852  MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
4853  break;
4854  case MSA_DWORD:
4855  MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
4856  break;
4857  default:
4858  UNREACHABLE();
4859  }
4860  } else if (opcode == MSA_ST) {
4861  switch (DecodeMsaDataFormat()) {
4862  case MSA_BYTE:
4863  MSA_MI10_STORE(b, kMSALanesByte, int8_t);
4864  break;
4865  case MSA_HALF:
4866  MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
4867  break;
4868  case MSA_WORD:
4869  MSA_MI10_STORE(w, kMSALanesWord, int32_t);
4870  break;
4871  case MSA_DWORD:
4872  MSA_MI10_STORE(d, kMSALanesDword, int64_t);
4873  break;
4874  default:
4875  UNREACHABLE();
4876  }
4877  } else {
4878  UNREACHABLE();
4879  }
4880 
4881 #undef MSA_MI10_LOAD
4882 #undef MSA_MI10_STORE
4883 }
4884 
4885 template <typename T>
4886 T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
4887  typedef typename std::make_unsigned<T>::type uT;
4888  T res;
4889  T wt_modulo = wt % (sizeof(T) * 8);
4890  switch (opcode) {
4891  case SLL_MSA:
4892  res = static_cast<T>(ws << wt_modulo);
4893  break;
4894  case SRA_MSA:
4895  res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo));
4896  break;
4897  case SRL_MSA:
4898  res = static_cast<T>(static_cast<uT>(ws) >> wt_modulo);
4899  break;
4900  case BCLR:
4901  res = static_cast<T>(static_cast<T>(~(1ull << wt_modulo)) & ws);
4902  break;
4903  case BSET:
4904  res = static_cast<T>(static_cast<T>(1ull << wt_modulo) | ws);
4905  break;
4906  case BNEG:
4907  res = static_cast<T>(static_cast<T>(1ull << wt_modulo) ^ ws);
4908  break;
4909  case BINSL: {
4910  int elem_size = 8 * sizeof(T);
4911  int bits = wt_modulo + 1;
4912  if (bits == elem_size) {
4913  res = static_cast<T>(ws);
4914  } else {
4915  uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
4916  res = static_cast<T>((static_cast<T>(mask) & ws) |
4917  (static_cast<T>(~mask) & wd));
4918  }
4919  } break;
4920  case BINSR: {
4921  int elem_size = 8 * sizeof(T);
4922  int bits = wt_modulo + 1;
4923  if (bits == elem_size) {
4924  res = static_cast<T>(ws);
4925  } else {
4926  uint64_t mask = (1ull << bits) - 1;
4927  res = static_cast<T>((static_cast<T>(mask) & ws) |
4928  (static_cast<T>(~mask) & wd));
4929  }
4930  } break;
4931  case ADDV:
4932  res = ws + wt;
4933  break;
4934  case SUBV:
4935  res = ws - wt;
4936  break;
4937  case MAX_S:
4938  res = Max(ws, wt);
4939  break;
4940  case MAX_U:
4941  res = static_cast<T>(Max(static_cast<uT>(ws), static_cast<uT>(wt)));
4942  break;
4943  case MIN_S:
4944  res = Min(ws, wt);
4945  break;
4946  case MIN_U:
4947  res = static_cast<T>(Min(static_cast<uT>(ws), static_cast<uT>(wt)));
4948  break;
4949  case MAX_A:
4950  // We use negative abs in order to avoid problems
4951  // with corner case for MIN_INT
4952  res = Nabs(ws) < Nabs(wt) ? ws : wt;
4953  break;
4954  case MIN_A:
4955  // We use negative abs in order to avoid problems
4956  // with corner case for MIN_INT
4957  res = Nabs(ws) > Nabs(wt) ? ws : wt;
4958  break;
4959  case CEQ:
4960  res = static_cast<T>(!Compare(ws, wt) ? -1ull : 0ull);
4961  break;
4962  case CLT_S:
4963  res = static_cast<T>((Compare(ws, wt) == -1) ? -1ull : 0ull);
4964  break;
4965  case CLT_U:
4966  res = static_cast<T>(
4967  (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) == -1) ? -1ull
4968  : 0ull);
4969  break;
4970  case CLE_S:
4971  res = static_cast<T>((Compare(ws, wt) != 1) ? -1ull : 0ull);
4972  break;
4973  case CLE_U:
4974  res = static_cast<T>(
4975  (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) != 1) ? -1ull
4976  : 0ull);
4977  break;
4978  case ADD_A:
4979  res = static_cast<T>(Abs(ws) + Abs(wt));
4980  break;
4981  case ADDS_A: {
4982  T ws_nabs = Nabs(ws);
4983  T wt_nabs = Nabs(wt);
4984  if (ws_nabs < -std::numeric_limits<T>::max() - wt_nabs) {
4985  res = std::numeric_limits<T>::max();
4986  } else {
4987  res = -(ws_nabs + wt_nabs);
4988  }
4989  } break;
4990  case ADDS_S:
4991  res = SaturateAdd(ws, wt);
4992  break;
4993  case ADDS_U: {
4994  uT ws_u = static_cast<uT>(ws);
4995  uT wt_u = static_cast<uT>(wt);
4996  res = static_cast<T>(SaturateAdd(ws_u, wt_u));
4997  } break;
4998  case AVE_S:
4999  res = static_cast<T>((wt & ws) + ((wt ^ ws) >> 1));
5000  break;
5001  case AVE_U: {
5002  uT ws_u = static_cast<uT>(ws);
5003  uT wt_u = static_cast<uT>(wt);
5004  res = static_cast<T>((wt_u & ws_u) + ((wt_u ^ ws_u) >> 1));
5005  } break;
5006  case AVER_S:
5007  res = static_cast<T>((wt | ws) - ((wt ^ ws) >> 1));
5008  break;
5009  case AVER_U: {
5010  uT ws_u = static_cast<uT>(ws);
5011  uT wt_u = static_cast<uT>(wt);
5012  res = static_cast<T>((wt_u | ws_u) - ((wt_u ^ ws_u) >> 1));
5013  } break;
5014  case SUBS_S:
5015  res = SaturateSub(ws, wt);
5016  break;
5017  case SUBS_U: {
5018  uT ws_u = static_cast<uT>(ws);
5019  uT wt_u = static_cast<uT>(wt);
5020  res = static_cast<T>(SaturateSub(ws_u, wt_u));
5021  } break;
5022  case SUBSUS_U: {
5023  uT wsu = static_cast<uT>(ws);
5024  if (wt > 0) {
5025  uT wtu = static_cast<uT>(wt);
5026  if (wtu > wsu) {
5027  res = 0;
5028  } else {
5029  res = static_cast<T>(wsu - wtu);
5030  }
5031  } else {
5032  if (wsu > std::numeric_limits<uT>::max() + wt) {
5033  res = static_cast<T>(std::numeric_limits<uT>::max());
5034  } else {
5035  res = static_cast<T>(wsu - wt);
5036  }
5037  }
5038  } break;
5039  case SUBSUU_S: {
5040  uT wsu = static_cast<uT>(ws);
5041  uT wtu = static_cast<uT>(wt);
5042  uT wdu;
5043  if (wsu > wtu) {
5044  wdu = wsu - wtu;
5045  if (wdu > std::numeric_limits<T>::max()) {
5046  res = std::numeric_limits<T>::max();
5047  } else {
5048  res = static_cast<T>(wdu);
5049  }
5050  } else {
5051  wdu = wtu - wsu;
5052  CHECK(-std::numeric_limits<T>::max() ==
5053  std::numeric_limits<T>::min() + 1);
5054  if (wdu <= std::numeric_limits<T>::max()) {
5055  res = -static_cast<T>(wdu);
5056  } else {
5057  res = std::numeric_limits<T>::min();
5058  }
5059  }
5060  } break;
5061  case ASUB_S:
5062  res = static_cast<T>(Abs(ws - wt));
5063  break;
5064  case ASUB_U: {
5065  uT wsu = static_cast<uT>(ws);
5066  uT wtu = static_cast<uT>(wt);
5067  res = static_cast<T>(wsu > wtu ? wsu - wtu : wtu - wsu);
5068  } break;
5069  case MULV:
5070  res = ws * wt;
5071  break;
5072  case MADDV:
5073  res = wd + ws * wt;
5074  break;
5075  case MSUBV:
5076  res = wd - ws * wt;
5077  break;
5078  case DIV_S_MSA:
5079  res = wt != 0 ? ws / wt : static_cast<T>(Unpredictable);
5080  break;
5081  case DIV_U:
5082  res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) / static_cast<uT>(wt))
5083  : static_cast<T>(Unpredictable);
5084  break;
5085  case MOD_S:
5086  res = wt != 0 ? ws % wt : static_cast<T>(Unpredictable);
5087  break;
5088  case MOD_U:
5089  res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) % static_cast<uT>(wt))
5090  : static_cast<T>(Unpredictable);
5091  break;
5092  case DOTP_S:
5093  case DOTP_U:
5094  case DPADD_S:
5095  case DPADD_U:
5096  case DPSUB_S:
5097  case DPSUB_U:
5098  case SLD:
5099  case SPLAT:
5100  UNIMPLEMENTED();
5101  break;
5102  case SRAR: {
5103  int bit = wt_modulo == 0 ? 0 : (ws >> (wt_modulo - 1)) & 1;
5104  res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo) + bit);
5105  } break;
5106  case SRLR: {
5107  uT wsu = static_cast<uT>(ws);
5108  int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
5109  res = static_cast<T>((wsu >> wt_modulo) + bit);
5110  } break;
5111  default:
5112  UNREACHABLE();
5113  }
5114  return res;
5115 }
5116 
5117 template <typename T_int, typename T_reg>
5118 void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
5119  T_reg wd, const int i, const int num_of_lanes) {
5120  T_int *ws_p, *wt_p, *wd_p;
5121  ws_p = reinterpret_cast<T_int*>(ws);
5122  wt_p = reinterpret_cast<T_int*>(wt);
5123  wd_p = reinterpret_cast<T_int*>(wd);
5124  switch (opcode) {
5125  case PCKEV:
5126  wd_p[i] = wt_p[2 * i];
5127  wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
5128  break;
5129  case PCKOD:
5130  wd_p[i] = wt_p[2 * i + 1];
5131  wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
5132  break;
5133  case ILVL:
5134  wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
5135  wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
5136  break;
5137  case ILVR:
5138  wd_p[2 * i] = wt_p[i];
5139  wd_p[2 * i + 1] = ws_p[i];
5140  break;
5141  case ILVEV:
5142  wd_p[2 * i] = wt_p[2 * i];
5143  wd_p[2 * i + 1] = ws_p[2 * i];
5144  break;
5145  case ILVOD:
5146  wd_p[2 * i] = wt_p[2 * i + 1];
5147  wd_p[2 * i + 1] = ws_p[2 * i + 1];
5148  break;
5149  case VSHF: {
5150  const int mask_not_valid = 0xC0;
5151  const int mask_6_bits = 0x3F;
5152  if ((wd_p[i] & mask_not_valid)) {
5153  wd_p[i] = 0;
5154  } else {
5155  int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
5156  wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
5157  }
5158  } break;
5159  default:
5160  UNREACHABLE();
5161  }
5162 }
5163 
5164 template <typename T_int, typename T_smaller_int, typename T_reg>
5165 void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
5166  T_reg wd, const int i,
5167  const int num_of_lanes) {
5168  typedef typename std::make_unsigned<T_int>::type T_uint;
5169  typedef typename std::make_unsigned<T_smaller_int>::type T_smaller_uint;
5170  T_int* wd_p;
5171  T_smaller_int *ws_p, *wt_p;
5172  ws_p = reinterpret_cast<T_smaller_int*>(ws);
5173  wt_p = reinterpret_cast<T_smaller_int*>(wt);
5174  wd_p = reinterpret_cast<T_int*>(wd);
5175  T_uint* wd_pu;
5176  T_smaller_uint *ws_pu, *wt_pu;
5177  ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
5178  wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
5179  wd_pu = reinterpret_cast<T_uint*>(wd);
5180  switch (opcode) {
5181  case HADD_S:
5182  wd_p[i] =
5183  static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
5184  break;
5185  case HADD_U:
5186  wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
5187  static_cast<T_uint>(wt_pu[2 * i]);
5188  break;
5189  case HSUB_S:
5190  wd_p[i] =
5191  static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
5192  break;
5193  case HSUB_U:
5194  wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
5195  static_cast<T_uint>(wt_pu[2 * i]);
5196  break;
5197  default:
5198  UNREACHABLE();
5199  }
5200 }
5201 
5202 void Simulator::DecodeTypeMsa3R() {
5203  DCHECK(IsMipsArchVariant(kMips32r6));
5204  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5205  uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
5206  msa_reg_t ws, wd, wt;
5207  get_msa_register(ws_reg(), &ws);
5208  get_msa_register(wt_reg(), &wt);
5209  get_msa_register(wd_reg(), &wd);
5210  switch (opcode) {
5211  case HADD_S:
5212  case HADD_U:
5213  case HSUB_S:
5214  case HSUB_U:
5215 #define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
5216  for (int i = 0; i < num_of_lanes; ++i) { \
5217  Msa3RInstrHelper_horizontal<int_type, lesser_int_type>( \
5218  opcode, &ws, &wt, &wd, i, num_of_lanes); \
5219  }
5220  switch (DecodeMsaDataFormat()) {
5221  case MSA_HALF:
5222  HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
5223  break;
5224  case MSA_WORD:
5225  HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
5226  break;
5227  case MSA_DWORD:
5228  HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
5229  break;
5230  default:
5231  UNREACHABLE();
5232  }
5233  break;
5234 #undef HORIZONTAL_ARITHMETIC_DF
5235  case VSHF:
5236 #define VSHF_DF(num_of_lanes, int_type) \
5237  for (int i = 0; i < num_of_lanes; ++i) { \
5238  Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5239  num_of_lanes); \
5240  }
5241  switch (DecodeMsaDataFormat()) {
5242  case MSA_BYTE:
5243  VSHF_DF(kMSALanesByte, int8_t);
5244  break;
5245  case MSA_HALF:
5246  VSHF_DF(kMSALanesHalf, int16_t);
5247  break;
5248  case MSA_WORD:
5249  VSHF_DF(kMSALanesWord, int32_t);
5250  break;
5251  case MSA_DWORD:
5252  VSHF_DF(kMSALanesDword, int64_t);
5253  break;
5254  default:
5255  UNREACHABLE();
5256  }
5257 #undef VSHF_DF
5258  break;
5259  case PCKEV:
5260  case PCKOD:
5261  case ILVL:
5262  case ILVR:
5263  case ILVEV:
5264  case ILVOD:
5265 #define INTERLEAVE_PACK_DF(num_of_lanes, int_type) \
5266  for (int i = 0; i < num_of_lanes / 2; ++i) { \
5267  Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5268  num_of_lanes); \
5269  }
5270  switch (DecodeMsaDataFormat()) {
5271  case MSA_BYTE:
5272  INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
5273  break;
5274  case MSA_HALF:
5275  INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
5276  break;
5277  case MSA_WORD:
5278  INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
5279  break;
5280  case MSA_DWORD:
5281  INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
5282  break;
5283  default:
5284  UNREACHABLE();
5285  }
5286  break;
5287 #undef INTERLEAVE_PACK_DF
5288  default:
5289 #define MSA_3R_DF(elem, num_of_lanes) \
5290  for (int i = 0; i < num_of_lanes; i++) { \
5291  wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
5292  }
5293 
5294  switch (DecodeMsaDataFormat()) {
5295  case MSA_BYTE:
5296  MSA_3R_DF(b, kMSALanesByte);
5297  break;
5298  case MSA_HALF:
5299  MSA_3R_DF(h, kMSALanesHalf);
5300  break;
5301  case MSA_WORD:
5302  MSA_3R_DF(w, kMSALanesWord);
5303  break;
5304  case MSA_DWORD:
5305  MSA_3R_DF(d, kMSALanesDword);
5306  break;
5307  default:
5308  UNREACHABLE();
5309  }
5310 #undef MSA_3R_DF
5311  break;
5312  }
5313  set_msa_register(wd_reg(), &wd);
5314  TraceMSARegWr(&wd);
5315 }
5316 
5317 template <typename T_int, typename T_fp, typename T_reg>
5318 void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
5319  const T_int all_ones = static_cast<T_int>(-1);
5320  const T_fp s_element = *reinterpret_cast<T_fp*>(&ws);
5321  const T_fp t_element = *reinterpret_cast<T_fp*>(&wt);
5322  switch (opcode) {
5323  case FCUN: {
5324  if (std::isnan(s_element) || std::isnan(t_element)) {
5325  wd = all_ones;
5326  } else {
5327  wd = 0;
5328  }
5329  } break;
5330  case FCEQ: {
5331  if (s_element != t_element || std::isnan(s_element) ||
5332  std::isnan(t_element)) {
5333  wd = 0;
5334  } else {
5335  wd = all_ones;
5336  }
5337  } break;
5338  case FCUEQ: {
5339  if (s_element == t_element || std::isnan(s_element) ||
5340  std::isnan(t_element)) {
5341  wd = all_ones;
5342  } else {
5343  wd = 0;
5344  }
5345  } break;
5346  case FCLT: {
5347  if (s_element >= t_element || std::isnan(s_element) ||
5348  std::isnan(t_element)) {
5349  wd = 0;
5350  } else {
5351  wd = all_ones;
5352  }
5353  } break;
5354  case FCULT: {
5355  if (s_element < t_element || std::isnan(s_element) ||
5356  std::isnan(t_element)) {
5357  wd = all_ones;
5358  } else {
5359  wd = 0;
5360  }
5361  } break;
5362  case FCLE: {
5363  if (s_element > t_element || std::isnan(s_element) ||
5364  std::isnan(t_element)) {
5365  wd = 0;
5366  } else {
5367  wd = all_ones;
5368  }
5369  } break;
5370  case FCULE: {
5371  if (s_element <= t_element || std::isnan(s_element) ||
5372  std::isnan(t_element)) {
5373  wd = all_ones;
5374  } else {
5375  wd = 0;
5376  }
5377  } break;
5378  case FCOR: {
5379  if (std::isnan(s_element) || std::isnan(t_element)) {
5380  wd = 0;
5381  } else {
5382  wd = all_ones;
5383  }
5384  } break;
5385  case FCUNE: {
5386  if (s_element != t_element || std::isnan(s_element) ||
5387  std::isnan(t_element)) {
5388  wd = all_ones;
5389  } else {
5390  wd = 0;
5391  }
5392  } break;
5393  case FCNE: {
5394  if (s_element == t_element || std::isnan(s_element) ||
5395  std::isnan(t_element)) {
5396  wd = 0;
5397  } else {
5398  wd = all_ones;
5399  }
5400  } break;
5401  case FADD:
5402  wd = bit_cast<T_int>(s_element + t_element);
5403  break;
5404  case FSUB:
5405  wd = bit_cast<T_int>(s_element - t_element);
5406  break;
5407  case FMUL:
5408  wd = bit_cast<T_int>(s_element * t_element);
5409  break;
5410  case FDIV: {
5411  if (t_element == 0) {
5412  wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
5413  } else {
5414  wd = bit_cast<T_int>(s_element / t_element);
5415  }
5416  } break;
5417  case FMADD:
5418  wd = bit_cast<T_int>(
5419  std::fma(s_element, t_element, *reinterpret_cast<T_fp*>(&wd)));
5420  break;
5421  case FMSUB:
5422  wd = bit_cast<T_int>(
5423  std::fma(s_element, -t_element, *reinterpret_cast<T_fp*>(&wd)));
5424  break;
5425  case FEXP2:
5426  wd = bit_cast<T_int>(std::ldexp(s_element, static_cast<int>(wt)));
5427  break;
5428  case FMIN:
5429  wd = bit_cast<T_int>(std::min(s_element, t_element));
5430  break;
5431  case FMAX:
5432  wd = bit_cast<T_int>(std::max(s_element, t_element));
5433  break;
5434  case FMIN_A: {
5435  wd = bit_cast<T_int>(
5436  std::fabs(s_element) < std::fabs(t_element) ? s_element : t_element);
5437  } break;
5438  case FMAX_A: {
5439  wd = bit_cast<T_int>(
5440  std::fabs(s_element) > std::fabs(t_element) ? s_element : t_element);
5441  } break;
5442  case FSOR:
5443  case FSUNE:
5444  case FSNE:
5445  case FSAF:
5446  case FSUN:
5447  case FSEQ:
5448  case FSUEQ:
5449  case FSLT:
5450  case FSULT:
5451  case FSLE:
5452  case FSULE:
5453  UNIMPLEMENTED();
5454  break;
5455  default:
5456  UNREACHABLE();
5457  }
5458 }
5459 
5460 template <typename T_int, typename T_int_dbl, typename T_reg>
5461 void Msa3RFInstrHelper2(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
5462  // typedef typename std::make_unsigned<T_int>::type T_uint;
5463  typedef typename std::make_unsigned<T_int_dbl>::type T_uint_dbl;
5464  const T_int max_int = std::numeric_limits<T_int>::max();
5465  const T_int min_int = std::numeric_limits<T_int>::min();
5466  const int shift = kBitsPerByte * sizeof(T_int) - 1;
5467  const T_int_dbl reg_s = ws;
5468  const T_int_dbl reg_t = wt;
5469  T_int_dbl product, result;
5470  product = reg_s * reg_t;
5471  switch (opcode) {
5472  case MUL_Q: {
5473  const T_int_dbl min_fix_dbl =
5474  bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5475  const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5476  if (product == min_fix_dbl) {
5477  product = max_fix_dbl;
5478  }
5479  wd = static_cast<T_int>(product >> shift);
5480  } break;
5481  case MADD_Q: {
5482  result = (product + (static_cast<T_int_dbl>(wd) << shift)) >> shift;
5483  wd = static_cast<T_int>(
5484  result > max_int ? max_int : result < min_int ? min_int : result);
5485  } break;
5486  case MSUB_Q: {
5487  result = (-product + (static_cast<T_int_dbl>(wd) << shift)) >> shift;
5488  wd = static_cast<T_int>(
5489  result > max_int ? max_int : result < min_int ? min_int : result);
5490  } break;
5491  case MULR_Q: {
5492  const T_int_dbl min_fix_dbl =
5493  bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5494  const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5495  if (product == min_fix_dbl) {
5496  wd = static_cast<T_int>(max_fix_dbl >> shift);
5497  break;
5498  }
5499  wd = static_cast<T_int>((product + (1 << (shift - 1))) >> shift);
5500  } break;
5501  case MADDR_Q: {
5502  result = (product + (static_cast<T_int_dbl>(wd) << shift) +
5503  (1 << (shift - 1))) >>
5504  shift;
5505  wd = static_cast<T_int>(
5506  result > max_int ? max_int : result < min_int ? min_int : result);
5507  } break;
5508  case MSUBR_Q: {
5509  result = (-product + (static_cast<T_int_dbl>(wd) << shift) +
5510  (1 << (shift - 1))) >>
5511  shift;
5512  wd = static_cast<T_int>(
5513  result > max_int ? max_int : result < min_int ? min_int : result);
5514  } break;
5515  default:
5516  UNREACHABLE();
5517  }
5518 }
5519 
5520 void Simulator::DecodeTypeMsa3RF() {
5521  DCHECK(IsMipsArchVariant(kMips32r6));
5522  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5523  uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
5524  msa_reg_t wd, ws, wt;
5525  if (opcode != FCAF) {
5526  get_msa_register(ws_reg(), &ws);
5527  get_msa_register(wt_reg(), &wt);
5528  }
5529  switch (opcode) {
5530  case FCAF:
5531  wd.d[0] = 0;
5532  wd.d[1] = 0;
5533  break;
5534  case FEXDO:
5535 #define PACK_FLOAT16(sign, exp, frac) \
5536  static_cast<uint16_t>(((sign) << 15) + ((exp) << 10) + (frac))
5537 #define FEXDO_DF(source, dst) \
5538  do { \
5539  element = source; \
5540  aSign = element >> 31; \
5541  aExp = element >> 23 & 0xFF; \
5542  aFrac = element & 0x007FFFFF; \
5543  if (aExp == 0xFF) { \
5544  if (aFrac) { \
5545  /* Input is a NaN */ \
5546  dst = 0x7DFFU; \
5547  break; \
5548  } \
5549  /* Infinity */ \
5550  dst = PACK_FLOAT16(aSign, 0x1F, 0); \
5551  break; \
5552  } else if (aExp == 0 && aFrac == 0) { \
5553  dst = PACK_FLOAT16(aSign, 0, 0); \
5554  break; \
5555  } else { \
5556  int maxexp = 29; \
5557  uint32_t mask; \
5558  uint32_t increment; \
5559  bool rounding_bumps_exp; \
5560  aFrac |= 0x00800000; \
5561  aExp -= 0x71; \
5562  if (aExp < 1) { \
5563  /* Will be denormal in halfprec */ \
5564  mask = 0x00FFFFFF; \
5565  if (aExp >= -11) { \
5566  mask >>= 11 + aExp; \
5567  } \
5568  } else { \
5569  /* Normal number in halfprec */ \
5570  mask = 0x00001FFF; \
5571  } \
5572  switch (MSACSR_ & 3) { \
5573  case kRoundToNearest: \
5574  increment = (mask + 1) >> 1; \
5575  if ((aFrac & mask) == increment) { \
5576  increment = aFrac & (increment << 1); \
5577  } \
5578  break; \
5579  case kRoundToPlusInf: \
5580  increment = aSign ? 0 : mask; \
5581  break; \
5582  case kRoundToMinusInf: \
5583  increment = aSign ? mask : 0; \
5584  break; \
5585  case kRoundToZero: \
5586  increment = 0; \
5587  break; \
5588  } \
5589  rounding_bumps_exp = (aFrac + increment >= 0x01000000); \
5590  if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { \
5591  dst = PACK_FLOAT16(aSign, 0x1F, 0); \
5592  break; \
5593  } \
5594  aFrac += increment; \
5595  if (rounding_bumps_exp) { \
5596  aFrac >>= 1; \
5597  aExp++; \
5598  } \
5599  if (aExp < -10) { \
5600  dst = PACK_FLOAT16(aSign, 0, 0); \
5601  break; \
5602  } \
5603  if (aExp < 0) { \
5604  aFrac >>= -aExp; \
5605  aExp = 0; \
5606  } \
5607  dst = PACK_FLOAT16(aSign, aExp, aFrac >> 13); \
5608  } \
5609  } while (0);
5610  switch (DecodeMsaDataFormat()) {
5611  case MSA_HALF:
5612  for (int i = 0; i < kMSALanesWord; i++) {
5613  uint_fast32_t element;
5614  uint_fast32_t aSign, aFrac;
5615  int_fast32_t aExp;
5616  FEXDO_DF(ws.uw[i], wd.uh[i + kMSALanesHalf / 2])
5617  FEXDO_DF(wt.uw[i], wd.uh[i])
5618  }
5619  break;
5620  case MSA_WORD:
5621  for (int i = 0; i < kMSALanesDword; i++) {
5622  wd.w[i + kMSALanesWord / 2] = bit_cast<int32_t>(
5623  static_cast<float>(bit_cast<double>(ws.d[i])));
5624  wd.w[i] = bit_cast<int32_t>(
5625  static_cast<float>(bit_cast<double>(wt.d[i])));
5626  }
5627  break;
5628  default:
5629  UNREACHABLE();
5630  }
5631  break;
5632 #undef PACK_FLOAT16
5633 #undef FEXDO_DF
5634  case FTQ:
5635 #define FTQ_DF(source, dst, fp_type, int_type) \
5636  element = bit_cast<fp_type>(source) * \
5637  (1U << (sizeof(int_type) * kBitsPerByte - 1)); \
5638  if (element > std::numeric_limits<int_type>::max()) { \
5639  dst = std::numeric_limits<int_type>::max(); \
5640  } else if (element < std::numeric_limits<int_type>::min()) { \
5641  dst = std::numeric_limits<int_type>::min(); \
5642  } else if (std::isnan(element)) { \
5643  dst = 0; \
5644  } else { \
5645  int_type fixed_point; \
5646  round_according_to_msacsr(element, element, fixed_point); \
5647  dst = fixed_point; \
5648  }
5649 
5650  switch (DecodeMsaDataFormat()) {
5651  case MSA_HALF:
5652  for (int i = 0; i < kMSALanesWord; i++) {
5653  float element;
5654  FTQ_DF(ws.w[i], wd.h[i + kMSALanesHalf / 2], float, int16_t)
5655  FTQ_DF(wt.w[i], wd.h[i], float, int16_t)
5656  }
5657  break;
5658  case MSA_WORD:
5659  double element;
5660  for (int i = 0; i < kMSALanesDword; i++) {
5661  FTQ_DF(ws.d[i], wd.w[i + kMSALanesWord / 2], double, int32_t)
5662  FTQ_DF(wt.d[i], wd.w[i], double, int32_t)
5663  }
5664  break;
5665  default:
5666  UNREACHABLE();
5667  }
5668  break;
5669 #undef FTQ_DF
5670 #define MSA_3RF_DF(T1, T2, Lanes, ws, wt, wd) \
5671  for (int i = 0; i < Lanes; i++) { \
5672  Msa3RFInstrHelper<T1, T2>(opcode, ws, wt, wd); \
5673  }
5674 #define MSA_3RF_DF2(T1, T2, Lanes, ws, wt, wd) \
5675  for (int i = 0; i < Lanes; i++) { \
5676  Msa3RFInstrHelper2<T1, T2>(opcode, ws, wt, wd); \
5677  }
5678  case MADD_Q:
5679  case MSUB_Q:
5680  case MADDR_Q:
5681  case MSUBR_Q:
5682  get_msa_register(wd_reg(), &wd);
5683  V8_FALLTHROUGH;
5684  case MUL_Q:
5685  case MULR_Q:
5686  switch (DecodeMsaDataFormat()) {
5687  case MSA_HALF:
5688  MSA_3RF_DF2(int16_t, int32_t, kMSALanesHalf, ws.h[i], wt.h[i],
5689  wd.h[i])
5690  break;
5691  case MSA_WORD:
5692  MSA_3RF_DF2(int32_t, int64_t, kMSALanesWord, ws.w[i], wt.w[i],
5693  wd.w[i])
5694  break;
5695  default:
5696  UNREACHABLE();
5697  }
5698  break;
5699  default:
5700  if (opcode == FMADD || opcode == FMSUB) {
5701  get_msa_register(wd_reg(), &wd);
5702  }
5703  switch (DecodeMsaDataFormat()) {
5704  case MSA_WORD:
5705  MSA_3RF_DF(int32_t, float, kMSALanesWord, ws.w[i], wt.w[i], wd.w[i])
5706  break;
5707  case MSA_DWORD:
5708  MSA_3RF_DF(int64_t, double, kMSALanesDword, ws.d[i], wt.d[i], wd.d[i])
5709  break;
5710  default:
5711  UNREACHABLE();
5712  }
5713  break;
5714 #undef MSA_3RF_DF
5715 #undef MSA_3RF_DF2
5716  }
5717  set_msa_register(wd_reg(), &wd);
5718  TraceMSARegWr(&wd);
5719 }
5720 
5721 void Simulator::DecodeTypeMsaVec() {
5722  DCHECK(IsMipsArchVariant(kMips32r6));
5723  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5724  uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
5725  msa_reg_t wd, ws, wt;
5726 
5727  get_msa_register(instr_.WsValue(), ws.w);
5728  get_msa_register(instr_.WtValue(), wt.w);
5729  if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) {
5730  get_msa_register(instr_.WdValue(), wd.w);
5731  }
5732 
5733  for (int i = 0; i < kMSALanesWord; i++) {
5734  switch (opcode) {
5735  case AND_V:
5736  wd.w[i] = ws.w[i] & wt.w[i];
5737  break;
5738  case OR_V:
5739  wd.w[i] = ws.w[i] | wt.w[i];
5740  break;
5741  case NOR_V:
5742  wd.w[i] = ~(ws.w[i] | wt.w[i]);
5743  break;
5744  case XOR_V:
5745  wd.w[i] = ws.w[i] ^ wt.w[i];
5746  break;
5747  case BMNZ_V:
5748  wd.w[i] = (wt.w[i] & ws.w[i]) | (~wt.w[i] & wd.w[i]);
5749  break;
5750  case BMZ_V:
5751  wd.w[i] = (~wt.w[i] & ws.w[i]) | (wt.w[i] & wd.w[i]);
5752  break;
5753  case BSEL_V:
5754  wd.w[i] = (~wd.w[i] & ws.w[i]) | (wd.w[i] & wt.w[i]);
5755  break;
5756  default:
5757  UNREACHABLE();
5758  }
5759  }
5760  set_msa_register(instr_.WdValue(), wd.w);
5761  TraceMSARegWr(wd.d);
5762 }
5763 
5764 void Simulator::DecodeTypeMsa2R() {
5765  DCHECK(IsMipsArchVariant(kMips32r6));
5766  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5767  uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
5768  msa_reg_t wd, ws;
5769  switch (opcode) {
5770  case FILL:
5771  switch (DecodeMsaDataFormat()) {
5772  case MSA_BYTE: {
5773  int32_t rs = get_register(instr_.WsValue());
5774  for (int i = 0; i < kMSALanesByte; i++) {
5775  wd.b[i] = rs & 0xFFu;
5776  }
5777  set_msa_register(instr_.WdValue(), wd.b);
5778  TraceMSARegWr(wd.b);
5779  break;
5780  }
5781  case MSA_HALF: {
5782  int32_t rs = get_register(instr_.WsValue());
5783  for (int i = 0; i < kMSALanesHalf; i++) {
5784  wd.h[i] = rs & 0xFFFFu;
5785  }
5786  set_msa_register(instr_.WdValue(), wd.h);
5787  TraceMSARegWr(wd.h);
5788  break;
5789  }
5790  case MSA_WORD: {
5791  int32_t rs = get_register(instr_.WsValue());
5792  for (int i = 0; i < kMSALanesWord; i++) {
5793  wd.w[i] = rs;
5794  }
5795  set_msa_register(instr_.WdValue(), wd.w);
5796  TraceMSARegWr(wd.w);
5797  break;
5798  }
5799  default:
5800  UNREACHABLE();
5801  }
5802  break;
5803  case PCNT:
5804 #define PCNT_DF(elem, num_of_lanes) \
5805  get_msa_register(instr_.WsValue(), ws.elem); \
5806  for (int i = 0; i < num_of_lanes; i++) { \
5807  uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
5808  wd.elem[i] = base::bits::CountPopulation(u64elem); \
5809  } \
5810  set_msa_register(instr_.WdValue(), wd.elem); \
5811  TraceMSARegWr(wd.elem)
5812 
5813  switch (DecodeMsaDataFormat()) {
5814  case MSA_BYTE:
5815  PCNT_DF(ub, kMSALanesByte);
5816  break;
5817  case MSA_HALF:
5818  PCNT_DF(uh, kMSALanesHalf);
5819  break;
5820  case MSA_WORD:
5821  PCNT_DF(uw, kMSALanesWord);
5822  break;
5823  case MSA_DWORD:
5824  PCNT_DF(ud, kMSALanesDword);
5825  break;
5826  default:
5827  UNREACHABLE();
5828  }
5829 #undef PCNT_DF
5830  break;
5831  case NLOC:
5832 #define NLOC_DF(elem, num_of_lanes) \
5833  get_msa_register(instr_.WsValue(), ws.elem); \
5834  for (int i = 0; i < num_of_lanes; i++) { \
5835  const uint64_t mask = (num_of_lanes == kMSALanesDword) \
5836  ? UINT64_MAX \
5837  : (1ULL << (kMSARegSize / num_of_lanes)) - 1; \
5838  uint64_t u64elem = static_cast<uint64_t>(~ws.elem[i]) & mask; \
5839  wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
5840  (64 - kMSARegSize / num_of_lanes); \
5841  } \
5842  set_msa_register(instr_.WdValue(), wd.elem); \
5843  TraceMSARegWr(wd.elem)
5844 
5845  switch (DecodeMsaDataFormat()) {
5846  case MSA_BYTE:
5847  NLOC_DF(ub, kMSALanesByte);
5848  break;
5849  case MSA_HALF:
5850  NLOC_DF(uh, kMSALanesHalf);
5851  break;
5852  case MSA_WORD:
5853  NLOC_DF(uw, kMSALanesWord);
5854  break;
5855  case MSA_DWORD:
5856  NLOC_DF(ud, kMSALanesDword);
5857  break;
5858  default:
5859  UNREACHABLE();
5860  }
5861 #undef NLOC_DF
5862  break;
5863  case NLZC:
5864 #define NLZC_DF(elem, num_of_lanes) \
5865  get_msa_register(instr_.WsValue(), ws.elem); \
5866  for (int i = 0; i < num_of_lanes; i++) { \
5867  uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
5868  wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
5869  (64 - kMSARegSize / num_of_lanes); \
5870  } \
5871  set_msa_register(instr_.WdValue(), wd.elem); \
5872  TraceMSARegWr(wd.elem)
5873 
5874  switch (DecodeMsaDataFormat()) {
5875  case MSA_BYTE:
5876  NLZC_DF(ub, kMSALanesByte);
5877  break;
5878  case MSA_HALF:
5879  NLZC_DF(uh, kMSALanesHalf);
5880  break;
5881  case MSA_WORD:
5882  NLZC_DF(uw, kMSALanesWord);
5883  break;
5884  case MSA_DWORD:
5885  NLZC_DF(ud, kMSALanesDword);
5886  break;
5887  default:
5888  UNREACHABLE();
5889  }
5890 #undef NLZC_DF
5891  break;
5892  default:
5893  UNREACHABLE();
5894  }
5895 }
5896 
5897 #define BIT(n) (0x1LL << n)
5898 #define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
5899 #define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
5900 static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
5901 static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
5902 #undef QUIET_BIT_S
5903 #undef QUIET_BIT_D
5904 
5905 template <typename T_int, typename T_fp, typename T_src, typename T_dst>
5906 T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
5907  Simulator* sim) {
5908  typedef typename std::make_unsigned<T_int>::type T_uint;
5909  switch (opcode) {
5910  case FCLASS: {
5911 #define SNAN_BIT BIT(0)
5912 #define QNAN_BIT BIT(1)
5913 #define NEG_INFINITY_BIT BIT(2)
5914 #define NEG_NORMAL_BIT BIT(3)
5915 #define NEG_SUBNORMAL_BIT BIT(4)
5916 #define NEG_ZERO_BIT BIT(5)
5917 #define POS_INFINITY_BIT BIT(6)
5918 #define POS_NORMAL_BIT BIT(7)
5919 #define POS_SUBNORMAL_BIT BIT(8)
5920 #define POS_ZERO_BIT BIT(9)
5921  T_fp element = *reinterpret_cast<T_fp*>(&src);
5922  switch (std::fpclassify(element)) {
5923  case FP_INFINITE:
5924  if (std::signbit(element)) {
5925  dst = NEG_INFINITY_BIT;
5926  } else {
5927  dst = POS_INFINITY_BIT;
5928  }
5929  break;
5930  case FP_NAN:
5931  if (isSnan(element)) {
5932  dst = SNAN_BIT;
5933  } else {
5934  dst = QNAN_BIT;
5935  }
5936  break;
5937  case FP_NORMAL:
5938  if (std::signbit(element)) {
5939  dst = NEG_NORMAL_BIT;
5940  } else {
5941  dst = POS_NORMAL_BIT;
5942  }
5943  break;
5944  case FP_SUBNORMAL:
5945  if (std::signbit(element)) {
5946  dst = NEG_SUBNORMAL_BIT;
5947  } else {
5948  dst = POS_SUBNORMAL_BIT;
5949  }
5950  break;
5951  case FP_ZERO:
5952  if (std::signbit(element)) {
5953  dst = NEG_ZERO_BIT;
5954  } else {
5955  dst = POS_ZERO_BIT;
5956  }
5957  break;
5958  default:
5959  UNREACHABLE();
5960  }
5961  break;
5962  }
5963 #undef BIT
5964 #undef SNAN_BIT
5965 #undef QNAN_BIT
5966 #undef NEG_INFINITY_BIT
5967 #undef NEG_NORMAL_BIT
5968 #undef NEG_SUBNORMAL_BIT
5969 #undef NEG_ZERO_BIT
5970 #undef POS_INFINITY_BIT
5971 #undef POS_NORMAL_BIT
5972 #undef POS_SUBNORMAL_BIT
5973 #undef POS_ZERO_BIT
5974  case FTRUNC_S: {
5975  T_fp element = bit_cast<T_fp>(src);
5976  const T_int max_int = std::numeric_limits<T_int>::max();
5977  const T_int min_int = std::numeric_limits<T_int>::min();
5978  if (std::isnan(element)) {
5979  dst = 0;
5980  } else if (element >= max_int || element <= min_int) {
5981  dst = element >= max_int ? max_int : min_int;
5982  } else {
5983  dst = static_cast<T_int>(std::trunc(element));
5984  }
5985  break;
5986  }
5987  case FTRUNC_U: {
5988  T_fp element = bit_cast<T_fp>(src);
5989  const T_uint max_int = std::numeric_limits<T_uint>::max();
5990  if (std::isnan(element)) {
5991  dst = 0;
5992  } else if (element >= max_int || element <= 0) {
5993  dst = element >= max_int ? max_int : 0;
5994  } else {
5995  dst = static_cast<T_uint>(std::trunc(element));
5996  }
5997  break;
5998  }
5999  case FSQRT: {
6000  T_fp element = bit_cast<T_fp>(src);
6001  if (element < 0 || std::isnan(element)) {
6002  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6003  } else {
6004  dst = bit_cast<T_int>(std::sqrt(element));
6005  }
6006  break;
6007  }
6008  case FRSQRT: {
6009  T_fp element = bit_cast<T_fp>(src);
6010  if (element < 0 || std::isnan(element)) {
6011  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6012  } else {
6013  dst = bit_cast<T_int>(1 / std::sqrt(element));
6014  }
6015  break;
6016  }
6017  case FRCP: {
6018  T_fp element = bit_cast<T_fp>(src);
6019  if (std::isnan(element)) {
6020  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6021  } else {
6022  dst = bit_cast<T_int>(1 / element);
6023  }
6024  break;
6025  }
6026  case FRINT: {
6027  T_fp element = bit_cast<T_fp>(src);
6028  if (std::isnan(element)) {
6029  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6030  } else {
6031  T_int dummy;
6032  sim->round_according_to_msacsr<T_fp, T_int>(element, element, dummy);
6033  dst = bit_cast<T_int>(element);
6034  }
6035  break;
6036  }
6037  case FLOG2: {
6038  T_fp element = bit_cast<T_fp>(src);
6039  switch (std::fpclassify(element)) {
6040  case FP_NORMAL:
6041  case FP_SUBNORMAL:
6042  dst = bit_cast<T_int>(std::logb(element));
6043  break;
6044  case FP_ZERO:
6045  dst = bit_cast<T_int>(-std::numeric_limits<T_fp>::infinity());
6046  break;
6047  case FP_NAN:
6048  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6049  break;
6050  case FP_INFINITE:
6051  if (element < 0) {
6052  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6053  } else {
6054  dst = bit_cast<T_int>(std::numeric_limits<T_fp>::infinity());
6055  }
6056  break;
6057  default:
6058  UNREACHABLE();
6059  }
6060  break;
6061  }
6062  case FTINT_S: {
6063  T_fp element = bit_cast<T_fp>(src);
6064  const T_int max_int = std::numeric_limits<T_int>::max();
6065  const T_int min_int = std::numeric_limits<T_int>::min();
6066  if (std::isnan(element)) {
6067  dst = 0;
6068  } else if (element < min_int || element > max_int) {
6069  dst = element > max_int ? max_int : min_int;
6070  } else {
6071  sim->round_according_to_msacsr<T_fp, T_int>(element, element, dst);
6072  }
6073  break;
6074  }
6075  case FTINT_U: {
6076  T_fp element = bit_cast<T_fp>(src);
6077  const T_uint max_uint = std::numeric_limits<T_uint>::max();
6078  if (std::isnan(element)) {
6079  dst = 0;
6080  } else if (element < 0 || element > max_uint) {
6081  dst = element > max_uint ? max_uint : 0;
6082  } else {
6083  T_uint res;
6084  sim->round_according_to_msacsr<T_fp, T_uint>(element, element, res);
6085  dst = *reinterpret_cast<T_int*>(&res);
6086  }
6087  break;
6088  }
6089  case FFINT_S:
6090  dst = bit_cast<T_int>(static_cast<T_fp>(src));
6091  break;
6092  case FFINT_U:
6093  typedef typename std::make_unsigned<T_src>::type uT_src;
6094  dst = bit_cast<T_int>(static_cast<T_fp>(bit_cast<uT_src>(src)));
6095  break;
6096  default:
6097  UNREACHABLE();
6098  }
6099  return 0;
6100 }
6101 
6102 template <typename T_int, typename T_fp, typename T_reg>
6103 T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
6104  switch (opcode) {
6105 #define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
6106 #define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1F)
6107 #define EXTRACT_FLOAT16_FRAC(fp16) (fp16 & 0x3FF)
6108 #define PACK_FLOAT32(sign, exp, frac) \
6109  static_cast<uint32_t>(((sign) << 31) + ((exp) << 23) + (frac))
6110 #define FEXUP_DF(src_index) \
6111  uint_fast16_t element = ws.uh[src_index]; \
6112  uint_fast32_t aSign, aFrac; \
6113  int_fast32_t aExp; \
6114  aSign = EXTRACT_FLOAT16_SIGN(element); \
6115  aExp = EXTRACT_FLOAT16_EXP(element); \
6116  aFrac = EXTRACT_FLOAT16_FRAC(element); \
6117  if (V8_LIKELY(aExp && aExp != 0x1F)) { \
6118  return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13); \
6119  } else if (aExp == 0x1F) { \
6120  if (aFrac) { \
6121  return bit_cast<int32_t>(std::numeric_limits<float>::quiet_NaN()); \
6122  } else { \
6123  return bit_cast<uint32_t>(std::numeric_limits<float>::infinity()) | \
6124  static_cast<uint32_t>(aSign) << 31; \
6125  } \
6126  } else { \
6127  if (aFrac == 0) { \
6128  return PACK_FLOAT32(aSign, 0, 0); \
6129  } else { \
6130  int_fast16_t shiftCount = \
6131  base::bits::CountLeadingZeros32(static_cast<uint32_t>(aFrac)) - 21; \
6132  aFrac <<= shiftCount; \
6133  aExp = -shiftCount; \
6134  return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13); \
6135  } \
6136  }
6137  case FEXUPL:
6138  if (std::is_same<int32_t, T_int>::value) {
6139  FEXUP_DF(i + kMSALanesWord)
6140  } else {
6141  return bit_cast<int64_t>(
6142  static_cast<double>(bit_cast<float>(ws.w[i + kMSALanesDword])));
6143  }
6144  case FEXUPR:
6145  if (std::is_same<int32_t, T_int>::value) {
6146  FEXUP_DF(i)
6147  } else {
6148  return bit_cast<int64_t>(static_cast<double>(bit_cast<float>(ws.w[i])));
6149  }
6150  case FFQL: {
6151  if (std::is_same<int32_t, T_int>::value) {
6152  return bit_cast<int32_t>(static_cast<float>(ws.h[i + kMSALanesWord]) /
6153  (1U << 15));
6154  } else {
6155  return bit_cast<int64_t>(static_cast<double>(ws.w[i + kMSALanesDword]) /
6156  (1U << 31));
6157  }
6158  break;
6159  }
6160  case FFQR: {
6161  if (std::is_same<int32_t, T_int>::value) {
6162  return bit_cast<int32_t>(static_cast<float>(ws.h[i]) / (1U << 15));
6163  } else {
6164  return bit_cast<int64_t>(static_cast<double>(ws.w[i]) / (1U << 31));
6165  }
6166  break;
6167  default:
6168  UNREACHABLE();
6169  }
6170  }
6171 #undef EXTRACT_FLOAT16_SIGN
6172 #undef EXTRACT_FLOAT16_EXP
6173 #undef EXTRACT_FLOAT16_FRAC
6174 #undef PACK_FLOAT32
6175 #undef FEXUP_DF
6176 }
6177 
6178 void Simulator::DecodeTypeMsa2RF() {
6179  DCHECK(IsMipsArchVariant(kMips32r6));
6180  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
6181  uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
6182  msa_reg_t wd, ws;
6183  get_msa_register(ws_reg(), &ws);
6184  if (opcode == FEXUPL || opcode == FEXUPR || opcode == FFQL ||
6185  opcode == FFQR) {
6186  switch (DecodeMsaDataFormat()) {
6187  case MSA_WORD:
6188  for (int i = 0; i < kMSALanesWord; i++) {
6189  wd.w[i] = Msa2RFInstrHelper2<int32_t, float>(opcode, ws, i);
6190  }
6191  break;
6192  case MSA_DWORD:
6193  for (int i = 0; i < kMSALanesDword; i++) {
6194  wd.d[i] = Msa2RFInstrHelper2<int64_t, double>(opcode, ws, i);
6195  }
6196  break;
6197  default:
6198  UNREACHABLE();
6199  }
6200  } else {
6201  switch (DecodeMsaDataFormat()) {
6202  case MSA_WORD:
6203  for (int i = 0; i < kMSALanesWord; i++) {
6204  Msa2RFInstrHelper<int32_t, float>(opcode, ws.w[i], wd.w[i], this);
6205  }
6206  break;
6207  case MSA_DWORD:
6208  for (int i = 0; i < kMSALanesDword; i++) {
6209  Msa2RFInstrHelper<int64_t, double>(opcode, ws.d[i], wd.d[i], this);
6210  }
6211  break;
6212  default:
6213  UNREACHABLE();
6214  }
6215  }
6216  set_msa_register(wd_reg(), &wd);
6217  TraceMSARegWr(&wd);
6218 }
6219 
6220 void Simulator::DecodeTypeRegister() {
6221  // ---------- Execution.
6222  switch (instr_.OpcodeFieldRaw()) {
6223  case COP1:
6224  DecodeTypeRegisterCOP1();
6225  break;
6226  case COP1X:
6227  DecodeTypeRegisterCOP1X();
6228  break;
6229  case SPECIAL:
6230  DecodeTypeRegisterSPECIAL();
6231  break;
6232  case SPECIAL2:
6233  DecodeTypeRegisterSPECIAL2();
6234  break;
6235  case SPECIAL3:
6236  DecodeTypeRegisterSPECIAL3();
6237  break;
6238  case MSA:
6239  switch (instr_.MSAMinorOpcodeField()) {
6240  case kMsaMinor3R:
6241  DecodeTypeMsa3R();
6242  break;
6243  case kMsaMinor3RF:
6244  DecodeTypeMsa3RF();
6245  break;
6246  case kMsaMinorVEC:
6247  DecodeTypeMsaVec();
6248  break;
6249  case kMsaMinor2R:
6250  DecodeTypeMsa2R();
6251  break;
6252  case kMsaMinor2RF:
6253  DecodeTypeMsa2RF();
6254  break;
6255  case kMsaMinorELM:
6256  DecodeTypeMsaELM();
6257  break;
6258  default:
6259  UNREACHABLE();
6260  }
6261  break;
6262  default:
6263  UNREACHABLE();
6264  }
6265 }
6266 
6267 
6268 // Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
6269 void Simulator::DecodeTypeImmediate() {
6270  // Instruction fields.
6271  Opcode op = instr_.OpcodeFieldRaw();
6272  int32_t rs_reg = instr_.RsValue();
6273  int32_t rs = get_register(instr_.RsValue());
6274  uint32_t rs_u = static_cast<uint32_t>(rs);
6275  int32_t rt_reg = instr_.RtValue(); // Destination register.
6276  int32_t rt = get_register(rt_reg);
6277  int16_t imm16 = instr_.Imm16Value();
6278 
6279  int32_t ft_reg = instr_.FtValue(); // Destination register.
6280 
6281  // Zero extended immediate.
6282  uint32_t oe_imm16 = 0xFFFF & imm16;
6283  // Sign extended immediate.
6284  int32_t se_imm16 = imm16;
6285 
6286  // Next pc.
6287  int32_t next_pc = bad_ra;
6288 
6289  // Used for conditional branch instructions.
6290  bool execute_branch_delay_instruction = false;
6291 
6292  // Used for arithmetic instructions.
6293  int32_t alu_out = 0;
6294 
6295  // Used for memory instructions.
6296  int32_t addr = 0x0;
6297 
6298  // Branch instructions common part.
6299  auto BranchAndLinkHelper =
6300  [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
6301  execute_branch_delay_instruction = true;
6302  int32_t current_pc = get_pc();
6303  set_register(31, current_pc + 2 * kInstrSize);
6304  if (do_branch) {
6305  int16_t imm16 = this->instr_.Imm16Value();
6306  next_pc = current_pc + (imm16 << 2) + kInstrSize;
6307  } else {
6308  next_pc = current_pc + 2 * kInstrSize;
6309  }
6310  };
6311 
6312  auto BranchHelper = [this, &next_pc,
6313  &execute_branch_delay_instruction](bool do_branch) {
6314  execute_branch_delay_instruction = true;
6315  int32_t current_pc = get_pc();
6316  if (do_branch) {
6317  int16_t imm16 = this->instr_.Imm16Value();
6318  next_pc = current_pc + (imm16 << 2) + kInstrSize;
6319  } else {
6320  next_pc = current_pc + 2 * kInstrSize;
6321  }
6322  };
6323 
6324  auto BranchHelper_MSA = [this, &next_pc, imm16,
6325  &execute_branch_delay_instruction](bool do_branch) {
6326  execute_branch_delay_instruction = true;
6327  int32_t current_pc = get_pc();
6328  const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
6329  if (do_branch) {
6330  if (FLAG_debug_code) {
6331  int16_t bits = imm16 & 0xFC;
6332  if (imm16 >= 0) {
6333  CHECK_EQ(bits, 0);
6334  } else {
6335  CHECK_EQ(bits ^ 0xFC, 0);
6336  }
6337  }
6338  // jump range :[pc + kInstrSize - 512 * kInstrSize,
6339  // pc + kInstrSize + 511 * kInstrSize]
6340  int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
6341  (bitsIn16Int - 12);
6342  next_pc = current_pc + offset + kInstrSize;
6343  } else {
6344  next_pc = current_pc + 2 * kInstrSize;
6345  }
6346  };
6347 
6348  auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6349  int32_t current_pc = get_pc();
6350  CheckForbiddenSlot(current_pc);
6351  if (do_branch) {
6352  int32_t imm = this->instr_.ImmValue(bits);
6353  imm <<= 32 - bits;
6354  imm >>= 32 - bits;
6355  next_pc = current_pc + (imm << 2) + kInstrSize;
6356  set_register(31, current_pc + kInstrSize);
6357  }
6358  };
6359 
6360  auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6361  int32_t current_pc = get_pc();
6362  CheckForbiddenSlot(current_pc);
6363  if (do_branch) {
6364  int32_t imm = this->instr_.ImmValue(bits);
6365  imm <<= 32 - bits;
6366  imm >>= 32 - bits;
6367  next_pc = get_pc() + (imm << 2) + kInstrSize;
6368  }
6369  };
6370 
6371  switch (op) {
6372  // ------------- COP1. Coprocessor instructions.
6373  case COP1:
6374  switch (instr_.RsFieldRaw()) {
6375  case BC1: { // Branch on coprocessor condition.
6376  // Floating point.
6377  uint32_t cc = instr_.FBccValue();
6378  uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
6379  uint32_t cc_value = test_fcsr_bit(fcsr_cc);
6380  bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
6381  BranchHelper(do_branch);
6382  break;
6383  }
6384  case BC1EQZ:
6385  BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
6386  break;
6387  case BC1NEZ:
6388  BranchHelper(get_fpu_register(ft_reg) & 0x1);
6389  break;
6390  case BZ_V: {
6391  msa_reg_t wt;
6392  get_msa_register(wt_reg(), &wt);
6393  BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
6394  } break;
6395 #define BZ_DF(witdh, lanes) \
6396  { \
6397  msa_reg_t wt; \
6398  get_msa_register(wt_reg(), &wt); \
6399  int i; \
6400  for (i = 0; i < lanes; ++i) { \
6401  if (wt.witdh[i] == 0) { \
6402  break; \
6403  } \
6404  } \
6405  BranchHelper_MSA(i != lanes); \
6406  }
6407  case BZ_B:
6408  BZ_DF(b, kMSALanesByte)
6409  break;
6410  case BZ_H:
6411  BZ_DF(h, kMSALanesHalf)
6412  break;
6413  case BZ_W:
6414  BZ_DF(w, kMSALanesWord)
6415  break;
6416  case BZ_D:
6417  BZ_DF(d, kMSALanesDword)
6418  break;
6419 #undef BZ_DF
6420  case BNZ_V: {
6421  msa_reg_t wt;
6422  get_msa_register(wt_reg(), &wt);
6423  BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
6424  } break;
6425 #define BNZ_DF(witdh, lanes) \
6426  { \
6427  msa_reg_t wt; \
6428  get_msa_register(wt_reg(), &wt); \
6429  int i; \
6430  for (i = 0; i < lanes; ++i) { \
6431  if (wt.witdh[i] == 0) { \
6432  break; \
6433  } \
6434  } \
6435  BranchHelper_MSA(i == lanes); \
6436  }
6437  case BNZ_B:
6438  BNZ_DF(b, kMSALanesByte)
6439  break;
6440  case BNZ_H:
6441  BNZ_DF(h, kMSALanesHalf)
6442  break;
6443  case BNZ_W:
6444  BNZ_DF(w, kMSALanesWord)
6445  break;
6446  case BNZ_D:
6447  BNZ_DF(d, kMSALanesDword)
6448  break;
6449 #undef BNZ_DF
6450  default:
6451  UNREACHABLE();
6452  }
6453  break;
6454  // ------------- REGIMM class.
6455  case REGIMM:
6456  switch (instr_.RtFieldRaw()) {
6457  case BLTZ:
6458  BranchHelper(rs < 0);
6459  break;
6460  case BGEZ:
6461  BranchHelper(rs >= 0);
6462  break;
6463  case BLTZAL:
6464  BranchAndLinkHelper(rs < 0);
6465  break;
6466  case BGEZAL:
6467  BranchAndLinkHelper(rs >= 0);
6468  break;
6469  default:
6470  UNREACHABLE();
6471  }
6472  break; // case REGIMM.
6473  // ------------- Branch instructions.
6474  // When comparing to zero, the encoding of rt field is always 0, so we don't
6475  // need to replace rt with zero.
6476  case BEQ:
6477  BranchHelper(rs == rt);
6478  break;
6479  case BNE:
6480  BranchHelper(rs != rt);
6481  break;
6482  case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
6483  if (IsMipsArchVariant(kMips32r6)) {
6484  if (rt_reg != 0) {
6485  if (rs_reg == 0) { // BLEZALC
6486  BranchAndLinkCompactHelper(rt <= 0, 16);
6487  } else {
6488  if (rs_reg == rt_reg) { // BGEZALC
6489  BranchAndLinkCompactHelper(rt >= 0, 16);
6490  } else { // BGEUC
6491  BranchCompactHelper(
6492  static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
6493  }
6494  }
6495  } else { // BLEZ
6496  BranchHelper(rs <= 0);
6497  }
6498  } else { // BLEZ
6499  BranchHelper(rs <= 0);
6500  }
6501  break;
6502  case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
6503  if (IsMipsArchVariant(kMips32r6)) {
6504  if (rt_reg != 0) {
6505  if (rs_reg == 0) { // BGTZALC
6506  BranchAndLinkCompactHelper(rt > 0, 16);
6507  } else {
6508  if (rt_reg == rs_reg) { // BLTZALC
6509  BranchAndLinkCompactHelper(rt < 0, 16);
6510  } else { // BLTUC
6511  BranchCompactHelper(
6512  static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
6513  }
6514  }
6515  } else { // BGTZ
6516  BranchHelper(rs > 0);
6517  }
6518  } else { // BGTZ
6519  BranchHelper(rs > 0);
6520  }
6521  break;
6522  case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
6523  if (IsMipsArchVariant(kMips32r6)) {
6524  if (rt_reg != 0) {
6525  if (rs_reg == 0) { // BLEZC
6526  BranchCompactHelper(rt <= 0, 16);
6527  } else {
6528  if (rs_reg == rt_reg) { // BGEZC
6529  BranchCompactHelper(rt >= 0, 16);
6530  } else { // BGEC/BLEC
6531  BranchCompactHelper(rs >= rt, 16);
6532  }
6533  }
6534  }
6535  } else { // BLEZL
6536  BranchAndLinkHelper(rs <= 0);
6537  }
6538  break;
6539  case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
6540  if (IsMipsArchVariant(kMips32r6)) {
6541  if (rt_reg != 0) {
6542  if (rs_reg == 0) { // BGTZC
6543  BranchCompactHelper(rt > 0, 16);
6544  } else {
6545  if (rs_reg == rt_reg) { // BLTZC
6546  BranchCompactHelper(rt < 0, 16);
6547  } else { // BLTC/BGTC
6548  BranchCompactHelper(rs < rt, 16);
6549  }
6550  }
6551  }
6552  } else { // BGTZL
6553  BranchAndLinkHelper(rs > 0);
6554  }
6555  break;
6556  case POP66: // BEQZC, JIC
6557  if (rs_reg != 0) { // BEQZC
6558  BranchCompactHelper(rs == 0, 21);
6559  } else { // JIC
6560  next_pc = rt + imm16;
6561  }
6562  break;
6563  case POP76: // BNEZC, JIALC
6564  if (rs_reg != 0) { // BNEZC
6565  BranchCompactHelper(rs != 0, 21);
6566  } else { // JIALC
6567  set_register(31, get_pc() + kInstrSize);
6568  next_pc = rt + imm16;
6569  }
6570  break;
6571  case BC:
6572  BranchCompactHelper(true, 26);
6573  break;
6574  case BALC:
6575  BranchAndLinkCompactHelper(true, 26);
6576  break;
6577  case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
6578  if (IsMipsArchVariant(kMips32r6)) {
6579  if (rs_reg >= rt_reg) { // BOVC
6580  if (HaveSameSign(rs, rt)) {
6581  if (rs > 0) {
6582  BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
6583  } else if (rs < 0) {
6584  BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
6585  }
6586  }
6587  } else {
6588  if (rs_reg == 0) { // BEQZALC
6589  BranchAndLinkCompactHelper(rt == 0, 16);
6590  } else { // BEQC
6591  BranchCompactHelper(rt == rs, 16);
6592  }
6593  }
6594  } else { // ADDI
6595  if (HaveSameSign(rs, se_imm16)) {
6596  if (rs > 0) {
6597  if (rs <= Registers::kMaxValue - se_imm16) {
6598  SignalException(kIntegerOverflow);
6599  }
6600  } else if (rs < 0) {
6601  if (rs >= Registers::kMinValue - se_imm16) {
6602  SignalException(kIntegerUnderflow);
6603  }
6604  }
6605  }
6606  SetResult(rt_reg, rs + se_imm16);
6607  }
6608  break;
6609  case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
6610  if (IsMipsArchVariant(kMips32r6)) {
6611  if (rs_reg >= rt_reg) { // BNVC
6612  if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
6613  BranchCompactHelper(true, 16);
6614  } else {
6615  if (rs > 0) {
6616  BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
6617  } else if (rs < 0) {
6618  BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
6619  }
6620  }
6621  } else {
6622  if (rs_reg == 0) { // BNEZALC
6623  BranchAndLinkCompactHelper(rt != 0, 16);
6624  } else { // BNEC
6625  BranchCompactHelper(rt != rs, 16);
6626  }
6627  }
6628  }
6629  break;
6630  // ------------- Arithmetic instructions.
6631  case ADDIU:
6632  SetResult(rt_reg, rs + se_imm16);
6633  break;
6634  case SLTI:
6635  SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
6636  break;
6637  case SLTIU:
6638  SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
6639  break;
6640  case ANDI:
6641  SetResult(rt_reg, rs & oe_imm16);
6642  break;
6643  case ORI:
6644  SetResult(rt_reg, rs | oe_imm16);
6645  break;
6646  case XORI:
6647  SetResult(rt_reg, rs ^ oe_imm16);
6648  break;
6649  case LUI:
6650  if (rs_reg != 0) {
6651  // AUI
6652  DCHECK(IsMipsArchVariant(kMips32r6));
6653  SetResult(rt_reg, rs + (se_imm16 << 16));
6654  } else {
6655  // LUI
6656  SetResult(rt_reg, oe_imm16 << 16);
6657  }
6658  break;
6659  // ------------- Memory instructions.
6660  case LB:
6661  set_register(rt_reg, ReadB(rs + se_imm16));
6662  break;
6663  case LH:
6664  set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
6665  break;
6666  case LWL: {
6667  // al_offset is offset of the effective address within an aligned word.
6668  uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6669  uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6670  uint32_t mask = (1 << byte_shift * 8) - 1;
6671  addr = rs + se_imm16 - al_offset;
6672  alu_out = ReadW(addr, instr_.instr());
6673  alu_out <<= byte_shift * 8;
6674  alu_out |= rt & mask;
6675  set_register(rt_reg, alu_out);
6676  break;
6677  }
6678  case LW:
6679  set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
6680  break;
6681  case LBU:
6682  set_register(rt_reg, ReadBU(rs + se_imm16));
6683  break;
6684  case LHU:
6685  set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
6686  break;
6687  case LWR: {
6688  // al_offset is offset of the effective address within an aligned word.
6689  uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6690  uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6691  uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
6692  addr = rs + se_imm16 - al_offset;
6693  alu_out = ReadW(addr, instr_.instr());
6694  alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
6695  alu_out |= rt & mask;
6696  set_register(rt_reg, alu_out);
6697  break;
6698  }
6699  case SB:
6700  WriteB(rs + se_imm16, static_cast<int8_t>(rt));
6701  break;
6702  case SH:
6703  WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
6704  break;
6705  case SWL: {
6706  uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6707  uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6708  uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
6709  addr = rs + se_imm16 - al_offset;
6710  // Value to be written in memory.
6711  uint32_t mem_value = ReadW(addr, instr_.instr()) & mask;
6712  mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
6713  WriteW(addr, mem_value, instr_.instr());
6714  break;
6715  }
6716  case SW:
6717  WriteW(rs + se_imm16, rt, instr_.instr());
6718  break;
6719  case SWR: {
6720  uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6721  uint32_t mask = (1 << al_offset * 8) - 1;
6722  addr = rs + se_imm16 - al_offset;
6723  uint32_t mem_value = ReadW(addr, instr_.instr());
6724  mem_value = (rt << al_offset * 8) | (mem_value & mask);
6725  WriteW(addr, mem_value, instr_.instr());
6726  break;
6727  }
6728  case LL: {
6729  // LL/SC sequence cannot be simulated properly
6730  DCHECK(!IsMipsArchVariant(kMips32r6));
6731  set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
6732  break;
6733  }
6734  case SC: {
6735  // LL/SC sequence cannot be simulated properly
6736  DCHECK(!IsMipsArchVariant(kMips32r6));
6737  WriteW(rs + se_imm16, rt, instr_.instr());
6738  set_register(rt_reg, 1);
6739  break;
6740  }
6741  case LWC1:
6742  set_fpu_register_hi_word(ft_reg, 0);
6743  set_fpu_register_word(ft_reg,
6744  ReadW(rs + se_imm16, instr_.instr(), FLOAT));
6745  if (ft_reg % 2) {
6746  TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg - 1), FLOAT_DOUBLE);
6747  } else {
6748  TraceMemRd(rs + se_imm16, get_fpu_register_word(ft_reg), FLOAT);
6749  }
6750  break;
6751  case LDC1:
6752  set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
6753  TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg), DOUBLE);
6754  break;
6755  case SWC1:
6756  WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr_.instr());
6757  TraceMemWr(rs + se_imm16, get_fpu_register_word(ft_reg));
6758  break;
6759  case SDC1:
6760  WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
6761  TraceMemWr(rs + se_imm16, get_fpu_register(ft_reg));
6762  break;
6763  // ------------- PC-Relative instructions.
6764  case PCREL: {
6765  // rt field: checking 5-bits.
6766  int32_t imm21 = instr_.Imm21Value();
6767  int32_t current_pc = get_pc();
6768  uint8_t rt = (imm21 >> kImm16Bits);
6769  switch (rt) {
6770  case ALUIPC:
6771  addr = current_pc + (se_imm16 << 16);
6772  alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
6773  break;
6774  case AUIPC:
6775  alu_out = current_pc + (se_imm16 << 16);
6776  break;
6777  default: {
6778  int32_t imm19 = instr_.Imm19Value();
6779  // rt field: checking the most significant 2-bits.
6780  rt = (imm21 >> kImm19Bits);
6781  switch (rt) {
6782  case LWPC: {
6783  // Set sign.
6784  imm19 <<= (kOpcodeBits + kRsBits + 2);
6785  imm19 >>= (kOpcodeBits + kRsBits + 2);
6786  addr = current_pc + (imm19 << 2);
6787  uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
6788  alu_out = *ptr;
6789  break;
6790  }
6791  case ADDIUPC: {
6792  int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xFFF80000 : 0);
6793  alu_out = current_pc + (se_imm19 << 2);
6794  break;
6795  }
6796  default:
6797  UNREACHABLE();
6798  break;
6799  }
6800  }
6801  }
6802  SetResult(rs_reg, alu_out);
6803  break;
6804  }
6805  case SPECIAL3: {
6806  switch (instr_.FunctionFieldRaw()) {
6807  case LL_R6: {
6808  // LL/SC sequence cannot be simulated properly
6809  DCHECK(IsMipsArchVariant(kMips32r6));
6810  int32_t base = get_register(instr_.BaseValue());
6811  int32_t offset9 = instr_.Imm9Value();
6812  set_register(rt_reg, ReadW(base + offset9, instr_.instr()));
6813  break;
6814  }
6815  case SC_R6: {
6816  // LL/SC sequence cannot be simulated properly
6817  DCHECK(IsMipsArchVariant(kMips32r6));
6818  int32_t base = get_register(instr_.BaseValue());
6819  int32_t offset9 = instr_.Imm9Value();
6820  int32_t bit6 = instr_.Bit(6);
6821  WriteW(base + offset9, rt, instr_.instr());
6822  // Only SC (and not SCX) instruction modifies rt_reg
6823  if (bit6 == 0) {
6824  set_register(rt_reg, 1);
6825  }
6826  break;
6827  }
6828  default:
6829  UNREACHABLE();
6830  }
6831  break;
6832  }
6833  case MSA:
6834  switch (instr_.MSAMinorOpcodeField()) {
6835  case kMsaMinorI8:
6836  DecodeTypeMsaI8();
6837  break;
6838  case kMsaMinorI5:
6839  DecodeTypeMsaI5();
6840  break;
6841  case kMsaMinorI10:
6842  DecodeTypeMsaI10();
6843  break;
6844  case kMsaMinorELM:
6845  DecodeTypeMsaELM();
6846  break;
6847  case kMsaMinorBIT:
6848  DecodeTypeMsaBIT();
6849  break;
6850  case kMsaMinorMI10:
6851  DecodeTypeMsaMI10();
6852  break;
6853  default:
6854  UNREACHABLE();
6855  break;
6856  }
6857  break;
6858  default:
6859  UNREACHABLE();
6860  }
6861 
6862  if (execute_branch_delay_instruction) {
6863  // Execute branch delay slot
6864  // We don't check for end_sim_pc. First it should not be met as the current
6865  // pc is valid. Secondly a jump should always execute its branch delay slot.
6866  Instruction* branch_delay_instr =
6867  reinterpret_cast<Instruction*>(get_pc() + kInstrSize);
6868  BranchDelayInstructionDecode(branch_delay_instr);
6869  }
6870 
6871  // If needed update pc after the branch delay execution.
6872  if (next_pc != bad_ra) {
6873  set_pc(next_pc);
6874  }
6875 }
6876 
6877 
6878 // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
6879 void Simulator::DecodeTypeJump() {
6880  SimInstruction simInstr = instr_;
6881  // Get current pc.
6882  int32_t current_pc = get_pc();
6883  // Get unchanged bits of pc.
6884  int32_t pc_high_bits = current_pc & 0xF0000000;
6885  // Next pc.
6886 
6887  int32_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2);
6888 
6889  // Execute branch delay slot.
6890  // We don't check for end_sim_pc. First it should not be met as the current pc
6891  // is valid. Secondly a jump should always execute its branch delay slot.
6892  Instruction* branch_delay_instr =
6893  reinterpret_cast<Instruction*>(current_pc + kInstrSize);
6894  BranchDelayInstructionDecode(branch_delay_instr);
6895 
6896  // Update pc and ra if necessary.
6897  // Do this after the branch delay execution.
6898  if (simInstr.IsLinkingInstruction()) {
6899  set_register(31, current_pc + 2 * kInstrSize);
6900  }
6901  set_pc(next_pc);
6902  pc_modified_ = true;
6903 }
6904 
6905 
6906 // Executes the current instruction.
6907 void Simulator::InstructionDecode(Instruction* instr) {
6908  if (v8::internal::FLAG_check_icache) {
6909  CheckICache(i_cache(), instr);
6910  }
6911  pc_modified_ = false;
6913  if (::v8::internal::FLAG_trace_sim) {
6914  SNPrintF(trace_buf_, "%s", "");
6915  disasm::NameConverter converter;
6916  disasm::Disassembler dasm(converter);
6917  dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
6918  }
6919 
6920  instr_ = instr;
6921  switch (instr_.InstructionType()) {
6922  case Instruction::kRegisterType:
6923  DecodeTypeRegister();
6924  break;
6925  case Instruction::kImmediateType:
6926  DecodeTypeImmediate();
6927  break;
6928  case Instruction::kJumpType:
6929  DecodeTypeJump();
6930  break;
6931  default:
6932  UNSUPPORTED();
6933  }
6934  if (::v8::internal::FLAG_trace_sim) {
6935  PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
6936  reinterpret_cast<intptr_t>(instr), buffer.start(),
6937  trace_buf_.start());
6938  }
6939  if (!pc_modified_) {
6940  set_register(pc, reinterpret_cast<int32_t>(instr) + kInstrSize);
6941  }
6942 }
6943 
6944 void Simulator::Execute() {
6945  // Get the PC to simulate. Cannot use the accessor here as we need the
6946  // raw PC value and not the one used as input to arithmetic instructions.
6947  int program_counter = get_pc();
6948  if (::v8::internal::FLAG_stop_sim_at == 0) {
6949  // Fast version of the dispatch loop without checking whether the simulator
6950  // should be stopping at a particular executed instruction.
6951  while (program_counter != end_sim_pc) {
6952  Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6953  icount_++;
6954  InstructionDecode(instr);
6955  program_counter = get_pc();
6956  }
6957  } else {
6958  // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
6959  // we reach the particular instruction count.
6960  while (program_counter != end_sim_pc) {
6961  Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6962  icount_++;
6963  if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
6964  MipsDebugger dbg(this);
6965  dbg.Debug();
6966  } else {
6967  InstructionDecode(instr);
6968  }
6969  program_counter = get_pc();
6970  }
6971  }
6972 }
6973 
6974 void Simulator::CallInternal(Address entry) {
6975  // Adjust JS-based stack limit to C-based stack limit.
6976  isolate_->stack_guard()->AdjustStackLimitForSimulator();
6977 
6978  // Prepare to execute the code at entry.
6979  set_register(pc, static_cast<int32_t>(entry));
6980  // Put down marker for end of simulation. The simulator will stop simulation
6981  // when the PC reaches this value. By saving the "end simulation" value into
6982  // the LR the simulation stops when returning to this call point.
6983  set_register(ra, end_sim_pc);
6984 
6985  // Remember the values of callee-saved registers.
6986  // The code below assumes that r9 is not used as sb (static base) in
6987  // simulator code and therefore is regarded as a callee-saved register.
6988  int32_t s0_val = get_register(s0);
6989  int32_t s1_val = get_register(s1);
6990  int32_t s2_val = get_register(s2);
6991  int32_t s3_val = get_register(s3);
6992  int32_t s4_val = get_register(s4);
6993  int32_t s5_val = get_register(s5);
6994  int32_t s6_val = get_register(s6);
6995  int32_t s7_val = get_register(s7);
6996  int32_t gp_val = get_register(gp);
6997  int32_t sp_val = get_register(sp);
6998  int32_t fp_val = get_register(fp);
6999 
7000  // Set up the callee-saved registers with a known value. To be able to check
7001  // that they are preserved properly across JS execution.
7002  int32_t callee_saved_value = static_cast<int32_t>(icount_);
7003  set_register(s0, callee_saved_value);
7004  set_register(s1, callee_saved_value);
7005  set_register(s2, callee_saved_value);
7006  set_register(s3, callee_saved_value);
7007  set_register(s4, callee_saved_value);
7008  set_register(s5, callee_saved_value);
7009  set_register(s6, callee_saved_value);
7010  set_register(s7, callee_saved_value);
7011  set_register(gp, callee_saved_value);
7012  set_register(fp, callee_saved_value);
7013 
7014  // Start the simulation.
7015  Execute();
7016 
7017  // Check that the callee-saved registers have been preserved.
7018  CHECK_EQ(callee_saved_value, get_register(s0));
7019  CHECK_EQ(callee_saved_value, get_register(s1));
7020  CHECK_EQ(callee_saved_value, get_register(s2));
7021  CHECK_EQ(callee_saved_value, get_register(s3));
7022  CHECK_EQ(callee_saved_value, get_register(s4));
7023  CHECK_EQ(callee_saved_value, get_register(s5));
7024  CHECK_EQ(callee_saved_value, get_register(s6));
7025  CHECK_EQ(callee_saved_value, get_register(s7));
7026  CHECK_EQ(callee_saved_value, get_register(gp));
7027  CHECK_EQ(callee_saved_value, get_register(fp));
7028 
7029  // Restore callee-saved registers with the original value.
7030  set_register(s0, s0_val);
7031  set_register(s1, s1_val);
7032  set_register(s2, s2_val);
7033  set_register(s3, s3_val);
7034  set_register(s4, s4_val);
7035  set_register(s5, s5_val);
7036  set_register(s6, s6_val);
7037  set_register(s7, s7_val);
7038  set_register(gp, gp_val);
7039  set_register(sp, sp_val);
7040  set_register(fp, fp_val);
7041 }
7042 
7043 intptr_t Simulator::CallImpl(Address entry, int argument_count,
7044  const intptr_t* arguments) {
7045  // Set up arguments.
7046 
7047  // First four arguments passed in registers.
7048  int reg_arg_count = std::min(4, argument_count);
7049  if (reg_arg_count > 0) set_register(a0, arguments[0]);
7050  if (reg_arg_count > 1) set_register(a1, arguments[1]);
7051  if (reg_arg_count > 2) set_register(a2, arguments[2]);
7052  if (reg_arg_count > 3) set_register(a3, arguments[3]);
7053 
7054  // Remaining arguments passed on stack.
7055  int original_stack = get_register(sp);
7056  // Compute position of stack on entry to generated code.
7057  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
7058  - kCArgsSlotsSize);
7059  if (base::OS::ActivationFrameAlignment() != 0) {
7060  entry_stack &= -base::OS::ActivationFrameAlignment();
7061  }
7062  // Store remaining arguments on stack, from low to high memory.
7063  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
7064  memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count,
7065  (argument_count - reg_arg_count) * sizeof(*arguments));
7066  set_register(sp, entry_stack);
7067 
7068  CallInternal(entry);
7069 
7070  // Pop stack passed arguments.
7071  CHECK_EQ(entry_stack, get_register(sp));
7072  set_register(sp, original_stack);
7073 
7074  return get_register(v0);
7075 }
7076 
7077 double Simulator::CallFP(Address entry, double d0, double d1) {
7078  if (!IsMipsSoftFloatABI) {
7079  set_fpu_register_double(f12, d0);
7080  set_fpu_register_double(f14, d1);
7081  } else {
7082  int buffer[2];
7083  DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
7084  memcpy(buffer, &d0, sizeof(d0));
7085  set_dw_register(a0, buffer);
7086  memcpy(buffer, &d1, sizeof(d1));
7087  set_dw_register(a2, buffer);
7088  }
7089  CallInternal(entry);
7090  if (!IsMipsSoftFloatABI) {
7091  return get_fpu_register_double(f0);
7092  } else {
7093  return get_double_from_register_pair(v0);
7094  }
7095 }
7096 
7097 
7098 uintptr_t Simulator::PushAddress(uintptr_t address) {
7099  int new_sp = get_register(sp) - sizeof(uintptr_t);
7100  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
7101  *stack_slot = address;
7102  set_register(sp, new_sp);
7103  return new_sp;
7104 }
7105 
7106 
7107 uintptr_t Simulator::PopAddress() {
7108  int current_sp = get_register(sp);
7109  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
7110  uintptr_t address = *stack_slot;
7111  set_register(sp, current_sp + sizeof(uintptr_t));
7112  return address;
7113 }
7114 
7115 
7116 #undef UNSUPPORTED
7117 
7118 } // namespace internal
7119 } // namespace v8
7120 
7121 #endif // USE_SIMULATOR
7122 
7123 #endif // V8_TARGET_ARCH_MIPS
Definition: libplatform.h:13