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