• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 "src/execution/loong64/simulator-loong64.h"
6 
7 // Only build the simulator if not compiling for real LOONG64 hardware.
8 #if defined(USE_SIMULATOR)
9 
10 #include <limits.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 
14 #include <cmath>
15 
16 #include "src/base/bits.h"
17 #include "src/base/platform/platform.h"
18 #include "src/base/platform/wrappers.h"
19 #include "src/base/strings.h"
20 #include "src/base/vector.h"
21 #include "src/codegen/assembler-inl.h"
22 #include "src/codegen/loong64/constants-loong64.h"
23 #include "src/codegen/macro-assembler.h"
24 #include "src/diagnostics/disasm.h"
25 #include "src/heap/combined-heap.h"
26 #include "src/runtime/runtime-utils.h"
27 #include "src/utils/ostreams.h"
28 
29 namespace v8 {
30 namespace internal {
31 
DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,Simulator::GlobalMonitor::Get)32 DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
33                                 Simulator::GlobalMonitor::Get)
34 
35 // #define PRINT_SIM_LOG
36 
37 // Util functions.
38 inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); }
39 
get_fcsr_condition_bit(uint32_t cc)40 uint32_t get_fcsr_condition_bit(uint32_t cc) {
41   if (cc == 0) {
42     return 23;
43   } else {
44     return 24 + cc;
45   }
46 }
47 
MultiplyHighSigned(int64_t u,int64_t v)48 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
49   uint64_t u0, v0, w0;
50   int64_t u1, v1, w1, w2, t;
51 
52   u0 = u & 0xFFFFFFFFL;
53   u1 = u >> 32;
54   v0 = v & 0xFFFFFFFFL;
55   v1 = v >> 32;
56 
57   w0 = u0 * v0;
58   t = u1 * v0 + (w0 >> 32);
59   w1 = t & 0xFFFFFFFFL;
60   w2 = t >> 32;
61   w1 = u0 * v1 + w1;
62 
63   return u1 * v1 + w2 + (w1 >> 32);
64 }
65 
MultiplyHighUnsigned(uint64_t u,uint64_t v)66 static uint64_t MultiplyHighUnsigned(uint64_t u, uint64_t v) {
67   uint64_t u0, v0, w0;
68   uint64_t u1, v1, w1, w2, t;
69 
70   u0 = u & 0xFFFFFFFFL;
71   u1 = u >> 32;
72   v0 = v & 0xFFFFFFFFL;
73   v1 = v >> 32;
74 
75   w0 = u0 * v0;
76   t = u1 * v0 + (w0 >> 32);
77   w1 = t & 0xFFFFFFFFL;
78   w2 = t >> 32;
79   w1 = u0 * v1 + w1;
80 
81   return u1 * v1 + w2 + (w1 >> 32);
82 }
83 
84 #ifdef PRINT_SIM_LOG
printf_instr(const char * _Format,...)85 inline void printf_instr(const char* _Format, ...) {
86   va_list varList;
87   va_start(varList, _Format);
88   vprintf(_Format, varList);
89   va_end(varList);
90 }
91 #else
92 #define printf_instr(...)
93 #endif
94 
95 // This macro provides a platform independent use of sscanf. The reason for
96 // SScanF not being implemented in a platform independent was through
97 // ::v8::internal::OS in the same way as base::SNPrintF is that the Windows C
98 // Run-Time Library does not provide vsscanf.
99 #define SScanF sscanf
100 
101 // The Loong64Debugger class is used by the simulator while debugging simulated
102 // code.
103 class Loong64Debugger {
104  public:
Loong64Debugger(Simulator * sim)105   explicit Loong64Debugger(Simulator* sim) : sim_(sim) {}
106 
107   void Stop(Instruction* instr);
108   void Debug();
109   // Print all registers with a nice formatting.
110   void PrintAllRegs();
111   void PrintAllRegsIncludingFPU();
112 
113  private:
114   // We set the breakpoint code to 0xFFFF to easily recognize it.
115   static const Instr kBreakpointInstr = BREAK | 0xFFFF;
116   static const Instr kNopInstr = 0x0;
117 
118   Simulator* sim_;
119 
120   int64_t GetRegisterValue(int regnum);
121   int64_t GetFPURegisterValue(int regnum);
122   float GetFPURegisterValueFloat(int regnum);
123   double GetFPURegisterValueDouble(int regnum);
124   bool GetValue(const char* desc, int64_t* value);
125 
126   // Set or delete a breakpoint. Returns true if successful.
127   bool SetBreakpoint(Instruction* breakpc);
128   bool DeleteBreakpoint(Instruction* breakpc);
129 
130   // Undo and redo all breakpoints. This is needed to bracket disassembly and
131   // execution to skip past breakpoints when run from the debugger.
132   void UndoBreakpoints();
133   void RedoBreakpoints();
134 };
135 
UNSUPPORTED()136 inline void UNSUPPORTED() { printf("Sim: Unsupported instruction.\n"); }
137 
Stop(Instruction * instr)138 void Loong64Debugger::Stop(Instruction* instr) {
139   // Get the stop code.
140   uint32_t code = instr->Bits(25, 6);
141   PrintF("Simulator hit (%u)\n", code);
142   Debug();
143 }
144 
GetRegisterValue(int regnum)145 int64_t Loong64Debugger::GetRegisterValue(int regnum) {
146   if (regnum == kNumSimuRegisters) {
147     return sim_->get_pc();
148   } else {
149     return sim_->get_register(regnum);
150   }
151 }
152 
GetFPURegisterValue(int regnum)153 int64_t Loong64Debugger::GetFPURegisterValue(int regnum) {
154   if (regnum == kNumFPURegisters) {
155     return sim_->get_pc();
156   } else {
157     return sim_->get_fpu_register(regnum);
158   }
159 }
160 
GetFPURegisterValueFloat(int regnum)161 float Loong64Debugger::GetFPURegisterValueFloat(int regnum) {
162   if (regnum == kNumFPURegisters) {
163     return sim_->get_pc();
164   } else {
165     return sim_->get_fpu_register_float(regnum);
166   }
167 }
168 
GetFPURegisterValueDouble(int regnum)169 double Loong64Debugger::GetFPURegisterValueDouble(int regnum) {
170   if (regnum == kNumFPURegisters) {
171     return sim_->get_pc();
172   } else {
173     return sim_->get_fpu_register_double(regnum);
174   }
175 }
176 
GetValue(const char * desc,int64_t * value)177 bool Loong64Debugger::GetValue(const char* desc, int64_t* value) {
178   int regnum = Registers::Number(desc);
179   int fpuregnum = FPURegisters::Number(desc);
180 
181   if (regnum != kInvalidRegister) {
182     *value = GetRegisterValue(regnum);
183     return true;
184   } else if (fpuregnum != kInvalidFPURegister) {
185     *value = GetFPURegisterValue(fpuregnum);
186     return true;
187   } else if (strncmp(desc, "0x", 2) == 0) {
188     return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<uint64_t*>(value)) ==
189            1;
190   } else {
191     return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
192   }
193 }
194 
SetBreakpoint(Instruction * breakpc)195 bool Loong64Debugger::SetBreakpoint(Instruction* breakpc) {
196   // Check if a breakpoint can be set. If not return without any side-effects.
197   if (sim_->break_pc_ != nullptr) {
198     return false;
199   }
200 
201   // Set the breakpoint.
202   sim_->break_pc_ = breakpc;
203   sim_->break_instr_ = breakpc->InstructionBits();
204   // Not setting the breakpoint instruction in the code itself. It will be set
205   // when the debugger shell continues.
206   return true;
207 }
208 
DeleteBreakpoint(Instruction * breakpc)209 bool Loong64Debugger::DeleteBreakpoint(Instruction* breakpc) {
210   if (sim_->break_pc_ != nullptr) {
211     sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
212   }
213 
214   sim_->break_pc_ = nullptr;
215   sim_->break_instr_ = 0;
216   return true;
217 }
218 
UndoBreakpoints()219 void Loong64Debugger::UndoBreakpoints() {
220   if (sim_->break_pc_ != nullptr) {
221     sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
222   }
223 }
224 
RedoBreakpoints()225 void Loong64Debugger::RedoBreakpoints() {
226   if (sim_->break_pc_ != nullptr) {
227     sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
228   }
229 }
230 
PrintAllRegs()231 void Loong64Debugger::PrintAllRegs() {
232 #define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
233 
234   PrintF("\n");
235   // at, v0, a0.
236   PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64
237          "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n",
238          REG_INFO(1), REG_INFO(2), REG_INFO(4));
239   // v1, a1.
240   PrintF("%34s\t%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
241          "  %14" PRId64 " \n",
242          "", REG_INFO(3), REG_INFO(5));
243   // a2.
244   PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 "  %14" PRId64 " \n", "", "",
245          REG_INFO(6));
246   // a3.
247   PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 "  %14" PRId64 " \n", "", "",
248          REG_INFO(7));
249   PrintF("\n");
250   // a4-t3, s0-s7
251   for (int i = 0; i < 8; i++) {
252     PrintF("%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
253            "  %14" PRId64 " \n",
254            REG_INFO(8 + i), REG_INFO(16 + i));
255   }
256   PrintF("\n");
257   // t8, k0, LO.
258   PrintF("%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
259          "  %14" PRId64 " \t%3s: 0x%016" PRIx64 "  %14" PRId64 " \n",
260          REG_INFO(24), REG_INFO(26), REG_INFO(32));
261   // t9, k1, HI.
262   PrintF("%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
263          "  %14" PRId64 " \t%3s: 0x%016" PRIx64 "  %14" PRId64 " \n",
264          REG_INFO(25), REG_INFO(27), REG_INFO(33));
265   // sp, fp, gp.
266   PrintF("%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
267          "  %14" PRId64 " \t%3s: 0x%016" PRIx64 "  %14" PRId64 " \n",
268          REG_INFO(29), REG_INFO(30), REG_INFO(28));
269   // pc.
270   PrintF("%3s: 0x%016" PRIx64 "  %14" PRId64 " \t%3s: 0x%016" PRIx64
271          "  %14" PRId64 " \n",
272          REG_INFO(31), REG_INFO(34));
273 
274 #undef REG_INFO
275 }
276 
PrintAllRegsIncludingFPU()277 void Loong64Debugger::PrintAllRegsIncludingFPU() {
278 #define FPU_REG_INFO(n) \
279   FPURegisters::Name(n), GetFPURegisterValue(n), GetFPURegisterValueDouble(n)
280 
281   PrintAllRegs();
282 
283   PrintF("\n\n");
284   // f0, f1, f2, ... f31.
285   // TODO(plind): consider printing 2 columns for space efficiency.
286   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(0));
287   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(1));
288   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(2));
289   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(3));
290   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(4));
291   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(5));
292   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(6));
293   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(7));
294   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(8));
295   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(9));
296   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(10));
297   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(11));
298   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(12));
299   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(13));
300   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(14));
301   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(15));
302   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(16));
303   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(17));
304   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(18));
305   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(19));
306   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(20));
307   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(21));
308   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(22));
309   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(23));
310   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(24));
311   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(25));
312   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(26));
313   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(27));
314   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(28));
315   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(29));
316   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(30));
317   PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n", FPU_REG_INFO(31));
318 
319 #undef FPU_REG_INFO
320 }
321 
Debug()322 void Loong64Debugger::Debug() {
323   intptr_t last_pc = -1;
324   bool done = false;
325 
326 #define COMMAND_SIZE 63
327 #define ARG_SIZE 255
328 
329 #define STR(a) #a
330 #define XSTR(a) STR(a)
331 
332   char cmd[COMMAND_SIZE + 1];
333   char arg1[ARG_SIZE + 1];
334   char arg2[ARG_SIZE + 1];
335   char* argv[3] = {cmd, arg1, arg2};
336 
337   // Make sure to have a proper terminating character if reaching the limit.
338   cmd[COMMAND_SIZE] = 0;
339   arg1[ARG_SIZE] = 0;
340   arg2[ARG_SIZE] = 0;
341 
342   // Undo all set breakpoints while running in the debugger shell. This will
343   // make them invisible to all commands.
344   UndoBreakpoints();
345 
346   while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
347     if (last_pc != sim_->get_pc()) {
348       disasm::NameConverter converter;
349       disasm::Disassembler dasm(converter);
350       // Use a reasonably large buffer.
351       v8::base::EmbeddedVector<char, 256> buffer;
352       dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
353       PrintF("  0x%016" PRIx64 "   %s\n", sim_->get_pc(), buffer.begin());
354       last_pc = sim_->get_pc();
355     }
356     char* line = ReadLine("sim> ");
357     if (line == nullptr) {
358       break;
359     } else {
360       char* last_input = sim_->last_debugger_input();
361       if (strcmp(line, "\n") == 0 && last_input != nullptr) {
362         line = last_input;
363       } else {
364         // Ownership is transferred to sim_;
365         sim_->set_last_debugger_input(line);
366       }
367       // Use sscanf to parse the individual parts of the command line. At the
368       // moment no command expects more than two parameters.
369       int argc = SScanF(line,
370                         "%" XSTR(COMMAND_SIZE) "s "
371                         "%" XSTR(ARG_SIZE) "s "
372                         "%" XSTR(ARG_SIZE) "s",
373                         cmd, arg1, arg2);
374       if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
375         Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
376         if (!(instr->IsTrap()) ||
377             instr->InstructionBits() == rtCallRedirInstr) {
378           sim_->InstructionDecode(
379               reinterpret_cast<Instruction*>(sim_->get_pc()));
380         } else {
381           // Allow si to jump over generated breakpoints.
382           PrintF("/!\\ Jumping over generated breakpoint.\n");
383           sim_->set_pc(sim_->get_pc() + kInstrSize);
384         }
385       } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
386         // Execute the one instruction we broke at with breakpoints disabled.
387         sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
388         // Leave the debugger shell.
389         done = true;
390       } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
391         if (argc == 2) {
392           int64_t value;
393           double dvalue;
394           if (strcmp(arg1, "all") == 0) {
395             PrintAllRegs();
396           } else if (strcmp(arg1, "allf") == 0) {
397             PrintAllRegsIncludingFPU();
398           } else {
399             int regnum = Registers::Number(arg1);
400             int fpuregnum = FPURegisters::Number(arg1);
401 
402             if (regnum != kInvalidRegister) {
403               value = GetRegisterValue(regnum);
404               PrintF("%s: 0x%08" PRIx64 "  %" PRId64 "  \n", arg1, value,
405                      value);
406             } else if (fpuregnum != kInvalidFPURegister) {
407               value = GetFPURegisterValue(fpuregnum);
408               dvalue = GetFPURegisterValueDouble(fpuregnum);
409               PrintF("%3s: 0x%016" PRIx64 "  %16.4e\n",
410                      FPURegisters::Name(fpuregnum), value, dvalue);
411             } else {
412               PrintF("%s unrecognized\n", arg1);
413             }
414           }
415         } else {
416           if (argc == 3) {
417             if (strcmp(arg2, "single") == 0) {
418               int64_t value;
419               float fvalue;
420               int fpuregnum = FPURegisters::Number(arg1);
421 
422               if (fpuregnum != kInvalidFPURegister) {
423                 value = GetFPURegisterValue(fpuregnum);
424                 value &= 0xFFFFFFFFUL;
425                 fvalue = GetFPURegisterValueFloat(fpuregnum);
426                 PrintF("%s: 0x%08" PRIx64 "  %11.4e\n", arg1, value, fvalue);
427               } else {
428                 PrintF("%s unrecognized\n", arg1);
429               }
430             } else {
431               PrintF("print <fpu register> single\n");
432             }
433           } else {
434             PrintF("print <register> or print <fpu register> single\n");
435           }
436         }
437       } else if ((strcmp(cmd, "po") == 0) ||
438                  (strcmp(cmd, "printobject") == 0)) {
439         if (argc == 2) {
440           int64_t value;
441           StdoutStream os;
442           if (GetValue(arg1, &value)) {
443             Object obj(value);
444             os << arg1 << ": \n";
445 #ifdef DEBUG
446             obj.Print(os);
447             os << "\n";
448 #else
449             os << Brief(obj) << "\n";
450 #endif
451           } else {
452             os << arg1 << " unrecognized\n";
453           }
454         } else {
455           PrintF("printobject <value>\n");
456         }
457       } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
458                  strcmp(cmd, "dump") == 0) {
459         int64_t* cur = nullptr;
460         int64_t* end = nullptr;
461         int next_arg = 1;
462 
463         if (strcmp(cmd, "stack") == 0) {
464           cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
465         } else {  // Command "mem".
466           int64_t value;
467           if (!GetValue(arg1, &value)) {
468             PrintF("%s unrecognized\n", arg1);
469             continue;
470           }
471           cur = reinterpret_cast<int64_t*>(value);
472           next_arg++;
473         }
474 
475         int64_t words;
476         if (argc == next_arg) {
477           words = 10;
478         } else {
479           if (!GetValue(argv[next_arg], &words)) {
480             words = 10;
481           }
482         }
483         end = cur + words;
484 
485         bool skip_obj_print = (strcmp(cmd, "dump") == 0);
486         while (cur < end) {
487           PrintF("  0x%012" PRIxPTR " :  0x%016" PRIx64 "  %14" PRId64 " ",
488                  reinterpret_cast<intptr_t>(cur), *cur, *cur);
489           Object obj(*cur);
490           Heap* current_heap = sim_->isolate_->heap();
491           if (!skip_obj_print) {
492             if (obj.IsSmi() ||
493                 IsValidHeapObject(current_heap, HeapObject::cast(obj))) {
494               PrintF(" (");
495               if (obj.IsSmi()) {
496                 PrintF("smi %d", Smi::ToInt(obj));
497               } else {
498                 obj.ShortPrint();
499               }
500               PrintF(")");
501             }
502           }
503           PrintF("\n");
504           cur++;
505         }
506 
507       } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
508                  (strcmp(cmd, "di") == 0)) {
509         disasm::NameConverter converter;
510         disasm::Disassembler dasm(converter);
511         // Use a reasonably large buffer.
512         v8::base::EmbeddedVector<char, 256> buffer;
513 
514         byte* cur = nullptr;
515         byte* end = nullptr;
516 
517         if (argc == 1) {
518           cur = reinterpret_cast<byte*>(sim_->get_pc());
519           end = cur + (10 * kInstrSize);
520         } else if (argc == 2) {
521           int regnum = Registers::Number(arg1);
522           if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
523             // The argument is an address or a register name.
524             int64_t value;
525             if (GetValue(arg1, &value)) {
526               cur = reinterpret_cast<byte*>(value);
527               // Disassemble 10 instructions at <arg1>.
528               end = cur + (10 * kInstrSize);
529             }
530           } else {
531             // The argument is the number of instructions.
532             int64_t value;
533             if (GetValue(arg1, &value)) {
534               cur = reinterpret_cast<byte*>(sim_->get_pc());
535               // Disassemble <arg1> instructions.
536               end = cur + (value * kInstrSize);
537             }
538           }
539         } else {
540           int64_t value1;
541           int64_t value2;
542           if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
543             cur = reinterpret_cast<byte*>(value1);
544             end = cur + (value2 * kInstrSize);
545           }
546         }
547 
548         while (cur < end) {
549           dasm.InstructionDecode(buffer, cur);
550           PrintF("  0x%08" PRIxPTR "   %s\n", reinterpret_cast<intptr_t>(cur),
551                  buffer.begin());
552           cur += kInstrSize;
553         }
554       } else if (strcmp(cmd, "gdb") == 0) {
555         PrintF("relinquishing control to gdb\n");
556         v8::base::OS::DebugBreak();
557         PrintF("regaining control from gdb\n");
558       } else if (strcmp(cmd, "break") == 0) {
559         if (argc == 2) {
560           int64_t value;
561           if (GetValue(arg1, &value)) {
562             if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
563               PrintF("setting breakpoint failed\n");
564             }
565           } else {
566             PrintF("%s unrecognized\n", arg1);
567           }
568         } else {
569           PrintF("break <address>\n");
570         }
571       } else if (strcmp(cmd, "del") == 0) {
572         if (!DeleteBreakpoint(nullptr)) {
573           PrintF("deleting breakpoint failed\n");
574         }
575       } else if (strcmp(cmd, "flags") == 0) {
576         PrintF("No flags on LOONG64 !\n");
577       } else if (strcmp(cmd, "stop") == 0) {
578         int64_t value;
579         intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
580         Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
581         Instruction* msg_address =
582             reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
583         if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
584           // Remove the current stop.
585           if (sim_->IsStopInstruction(stop_instr)) {
586             stop_instr->SetInstructionBits(kNopInstr);
587             msg_address->SetInstructionBits(kNopInstr);
588           } else {
589             PrintF("Not at debugger stop.\n");
590           }
591         } else if (argc == 3) {
592           // Print information about all/the specified breakpoint(s).
593           if (strcmp(arg1, "info") == 0) {
594             if (strcmp(arg2, "all") == 0) {
595               PrintF("Stop information:\n");
596               for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
597                    i++) {
598                 sim_->PrintStopInfo(i);
599               }
600             } else if (GetValue(arg2, &value)) {
601               sim_->PrintStopInfo(value);
602             } else {
603               PrintF("Unrecognized argument.\n");
604             }
605           } else if (strcmp(arg1, "enable") == 0) {
606             // Enable all/the specified breakpoint(s).
607             if (strcmp(arg2, "all") == 0) {
608               for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
609                    i++) {
610                 sim_->EnableStop(i);
611               }
612             } else if (GetValue(arg2, &value)) {
613               sim_->EnableStop(value);
614             } else {
615               PrintF("Unrecognized argument.\n");
616             }
617           } else if (strcmp(arg1, "disable") == 0) {
618             // Disable all/the specified breakpoint(s).
619             if (strcmp(arg2, "all") == 0) {
620               for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
621                    i++) {
622                 sim_->DisableStop(i);
623               }
624             } else if (GetValue(arg2, &value)) {
625               sim_->DisableStop(value);
626             } else {
627               PrintF("Unrecognized argument.\n");
628             }
629           }
630         } else {
631           PrintF("Wrong usage. Use help command for more information.\n");
632         }
633       } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
634         // Print registers and disassemble.
635         PrintAllRegs();
636         PrintF("\n");
637 
638         disasm::NameConverter converter;
639         disasm::Disassembler dasm(converter);
640         // Use a reasonably large buffer.
641         v8::base::EmbeddedVector<char, 256> buffer;
642 
643         byte* cur = nullptr;
644         byte* end = nullptr;
645 
646         if (argc == 1) {
647           cur = reinterpret_cast<byte*>(sim_->get_pc());
648           end = cur + (10 * kInstrSize);
649         } else if (argc == 2) {
650           int64_t value;
651           if (GetValue(arg1, &value)) {
652             cur = reinterpret_cast<byte*>(value);
653             // no length parameter passed, assume 10 instructions
654             end = cur + (10 * kInstrSize);
655           }
656         } else {
657           int64_t value1;
658           int64_t value2;
659           if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
660             cur = reinterpret_cast<byte*>(value1);
661             end = cur + (value2 * kInstrSize);
662           }
663         }
664 
665         while (cur < end) {
666           dasm.InstructionDecode(buffer, cur);
667           PrintF("  0x%08" PRIxPTR "   %s\n", reinterpret_cast<intptr_t>(cur),
668                  buffer.begin());
669           cur += kInstrSize;
670         }
671       } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
672         PrintF("cont\n");
673         PrintF("  continue execution (alias 'c')\n");
674         PrintF("stepi\n");
675         PrintF("  step one instruction (alias 'si')\n");
676         PrintF("print <register>\n");
677         PrintF("  print register content (alias 'p')\n");
678         PrintF("  use register name 'all' to print all registers\n");
679         PrintF("printobject <register>\n");
680         PrintF("  print an object from a register (alias 'po')\n");
681         PrintF("stack [<words>]\n");
682         PrintF("  dump stack content, default dump 10 words)\n");
683         PrintF("mem <address> [<words>]\n");
684         PrintF("  dump memory content, default dump 10 words)\n");
685         PrintF("dump [<words>]\n");
686         PrintF(
687             "  dump memory content without pretty printing JS objects, default "
688             "dump 10 words)\n");
689         PrintF("flags\n");
690         PrintF("  print flags\n");
691         PrintF("disasm [<instructions>]\n");
692         PrintF("disasm [<address/register>]\n");
693         PrintF("disasm [[<address/register>] <instructions>]\n");
694         PrintF("  disassemble code, default is 10 instructions\n");
695         PrintF("  from pc (alias 'di')\n");
696         PrintF("gdb\n");
697         PrintF("  enter gdb\n");
698         PrintF("break <address>\n");
699         PrintF("  set a break point on the address\n");
700         PrintF("del\n");
701         PrintF("  delete the breakpoint\n");
702         PrintF("stop feature:\n");
703         PrintF("  Description:\n");
704         PrintF("    Stops are debug instructions inserted by\n");
705         PrintF("    the Assembler::stop() function.\n");
706         PrintF("    When hitting a stop, the Simulator will\n");
707         PrintF("    stop and give control to the Debugger.\n");
708         PrintF("    All stop codes are watched:\n");
709         PrintF("    - They can be enabled / disabled: the Simulator\n");
710         PrintF("       will / won't stop when hitting them.\n");
711         PrintF("    - The Simulator keeps track of how many times they \n");
712         PrintF("      are met. (See the info command.) Going over a\n");
713         PrintF("      disabled stop still increases its counter. \n");
714         PrintF("  Commands:\n");
715         PrintF("    stop info all/<code> : print infos about number <code>\n");
716         PrintF("      or all stop(s).\n");
717         PrintF("    stop enable/disable all/<code> : enables / disables\n");
718         PrintF("      all or number <code> stop(s)\n");
719         PrintF("    stop unstop\n");
720         PrintF("      ignore the stop instruction at the current location\n");
721         PrintF("      from now on\n");
722       } else {
723         PrintF("Unknown command: %s\n", cmd);
724       }
725     }
726   }
727 
728   // Add all the breakpoints back to stop execution and enter the debugger
729   // shell when hit.
730   RedoBreakpoints();
731 
732 #undef COMMAND_SIZE
733 #undef ARG_SIZE
734 
735 #undef STR
736 #undef XSTR
737 }
738 
ICacheMatch(void * one,void * two)739 bool Simulator::ICacheMatch(void* one, void* two) {
740   DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
741   DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
742   return one == two;
743 }
744 
ICacheHash(void * key)745 static uint32_t ICacheHash(void* key) {
746   return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
747 }
748 
AllOnOnePage(uintptr_t start,size_t size)749 static bool AllOnOnePage(uintptr_t start, size_t size) {
750   intptr_t start_page = (start & ~CachePage::kPageMask);
751   intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
752   return start_page == end_page;
753 }
754 
set_last_debugger_input(char * input)755 void Simulator::set_last_debugger_input(char* input) {
756   DeleteArray(last_debugger_input_);
757   last_debugger_input_ = input;
758 }
759 
SetRedirectInstruction(Instruction * instruction)760 void Simulator::SetRedirectInstruction(Instruction* instruction) {
761   instruction->SetInstructionBits(rtCallRedirInstr);
762 }
763 
FlushICache(base::CustomMatcherHashMap * i_cache,void * start_addr,size_t size)764 void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
765                             void* start_addr, size_t size) {
766   int64_t start = reinterpret_cast<int64_t>(start_addr);
767   int64_t intra_line = (start & CachePage::kLineMask);
768   start -= intra_line;
769   size += intra_line;
770   size = ((size - 1) | CachePage::kLineMask) + 1;
771   int offset = (start & CachePage::kPageMask);
772   while (!AllOnOnePage(start, size - 1)) {
773     int bytes_to_flush = CachePage::kPageSize - offset;
774     FlushOnePage(i_cache, start, bytes_to_flush);
775     start += bytes_to_flush;
776     size -= bytes_to_flush;
777     DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
778     offset = 0;
779   }
780   if (size != 0) {
781     FlushOnePage(i_cache, start, size);
782   }
783 }
784 
GetCachePage(base::CustomMatcherHashMap * i_cache,void * page)785 CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
786                                    void* page) {
787   base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
788   if (entry->value == nullptr) {
789     CachePage* new_page = new CachePage();
790     entry->value = new_page;
791   }
792   return reinterpret_cast<CachePage*>(entry->value);
793 }
794 
795 // Flush from start up to and not including start + size.
FlushOnePage(base::CustomMatcherHashMap * i_cache,intptr_t start,size_t size)796 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
797                              intptr_t start, size_t size) {
798   DCHECK_LE(size, CachePage::kPageSize);
799   DCHECK(AllOnOnePage(start, size - 1));
800   DCHECK_EQ(start & CachePage::kLineMask, 0);
801   DCHECK_EQ(size & CachePage::kLineMask, 0);
802   void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
803   int offset = (start & CachePage::kPageMask);
804   CachePage* cache_page = GetCachePage(i_cache, page);
805   char* valid_bytemap = cache_page->ValidityByte(offset);
806   memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
807 }
808 
CheckICache(base::CustomMatcherHashMap * i_cache,Instruction * instr)809 void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
810                             Instruction* instr) {
811   int64_t address = reinterpret_cast<int64_t>(instr);
812   void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
813   void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
814   int offset = (address & CachePage::kPageMask);
815   CachePage* cache_page = GetCachePage(i_cache, page);
816   char* cache_valid_byte = cache_page->ValidityByte(offset);
817   bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
818   char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
819   if (cache_hit) {
820     // Check that the data in memory matches the contents of the I-cache.
821     CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
822                        cache_page->CachedData(offset), kInstrSize));
823   } else {
824     // Cache miss.  Load memory into the cache.
825     memcpy(cached_line, line, CachePage::kLineLength);
826     *cache_valid_byte = CachePage::LINE_VALID;
827   }
828 }
829 
Simulator(Isolate * isolate)830 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
831   // Set up simulator support first. Some of this information is needed to
832   // setup the architecture state.
833   stack_size_ = FLAG_sim_stack_size * KB;
834   stack_ = reinterpret_cast<char*>(base::Malloc(stack_size_));
835   pc_modified_ = false;
836   icount_ = 0;
837   break_count_ = 0;
838   break_pc_ = nullptr;
839   break_instr_ = 0;
840 
841   // Set up architecture state.
842   // All registers are initialized to zero to start with.
843   for (int i = 0; i < kNumSimuRegisters; i++) {
844     registers_[i] = 0;
845   }
846   for (int i = 0; i < kNumFPURegisters; i++) {
847     FPUregisters_[i] = 0;
848   }
849   for (int i = 0; i < kNumCFRegisters; i++) {
850     CFregisters_[i] = 0;
851   }
852 
853   FCSR_ = 0;
854 
855   // The sp is initialized to point to the bottom (high address) of the
856   // allocated stack area. To be safe in potential stack underflows we leave
857   // some buffer below.
858   registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64;
859   // The ra and pc are initialized to a known bad value that will cause an
860   // access violation if the simulator ever tries to execute it.
861   registers_[pc] = bad_ra;
862   registers_[ra] = bad_ra;
863 
864   last_debugger_input_ = nullptr;
865 }
866 
~Simulator()867 Simulator::~Simulator() {
868   GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
869   base::Free(stack_);
870 }
871 
872 // Get the active Simulator for the current thread.
current(Isolate * isolate)873 Simulator* Simulator::current(Isolate* isolate) {
874   v8::internal::Isolate::PerIsolateThreadData* isolate_data =
875       isolate->FindOrAllocatePerThreadDataForThisThread();
876   DCHECK_NOT_NULL(isolate_data);
877 
878   Simulator* sim = isolate_data->simulator();
879   if (sim == nullptr) {
880     // TODO(146): delete the simulator object when a thread/isolate goes away.
881     sim = new Simulator(isolate);
882     isolate_data->set_simulator(sim);
883   }
884   return sim;
885 }
886 
887 // Sets the register in the architecture state. It will also deal with updating
888 // Simulator internal state for special registers such as PC.
set_register(int reg,int64_t value)889 void Simulator::set_register(int reg, int64_t value) {
890   DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
891   if (reg == pc) {
892     pc_modified_ = true;
893   }
894 
895   // Zero register always holds 0.
896   registers_[reg] = (reg == 0) ? 0 : value;
897 }
898 
set_dw_register(int reg,const int * dbl)899 void Simulator::set_dw_register(int reg, const int* dbl) {
900   DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
901   registers_[reg] = dbl[1];
902   registers_[reg] = registers_[reg] << 32;
903   registers_[reg] += dbl[0];
904 }
905 
set_fpu_register(int fpureg,int64_t value)906 void Simulator::set_fpu_register(int fpureg, int64_t value) {
907   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
908   FPUregisters_[fpureg] = value;
909 }
910 
set_fpu_register_word(int fpureg,int32_t value)911 void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
912   // Set ONLY lower 32-bits, leaving upper bits untouched.
913   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
914   int32_t* pword;
915   pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
916 
917   *pword = value;
918 }
919 
set_fpu_register_hi_word(int fpureg,int32_t value)920 void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
921   // Set ONLY upper 32-bits, leaving lower bits untouched.
922   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
923   int32_t* phiword;
924   phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
925 
926   *phiword = value;
927 }
928 
set_fpu_register_float(int fpureg,float value)929 void Simulator::set_fpu_register_float(int fpureg, float value) {
930   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
931   *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
932 }
933 
set_fpu_register_double(int fpureg,double value)934 void Simulator::set_fpu_register_double(int fpureg, double value) {
935   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
936   *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
937 }
938 
set_cf_register(int cfreg,bool value)939 void Simulator::set_cf_register(int cfreg, bool value) {
940   DCHECK((cfreg >= 0) && (cfreg < kNumCFRegisters));
941   CFregisters_[cfreg] = value;
942 }
943 
944 // Get the register from the architecture state. This function does handle
945 // the special case of accessing the PC register.
get_register(int reg) const946 int64_t Simulator::get_register(int reg) const {
947   DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
948   if (reg == 0)
949     return 0;
950   else
951     return registers_[reg];
952 }
953 
get_double_from_register_pair(int reg)954 double Simulator::get_double_from_register_pair(int reg) {
955   // TODO(plind): bad ABI stuff, refactor or remove.
956   DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
957 
958   double dm_val = 0.0;
959   // Read the bits from the unsigned integer register_[] array
960   // into the double precision floating point value and return it.
961   char buffer[sizeof(registers_[0])];
962   memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
963   memcpy(&dm_val, buffer, sizeof(registers_[0]));
964   return (dm_val);
965 }
966 
get_fpu_register(int fpureg) const967 int64_t Simulator::get_fpu_register(int fpureg) const {
968   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
969   return FPUregisters_[fpureg];
970 }
971 
get_fpu_register_word(int fpureg) const972 int32_t Simulator::get_fpu_register_word(int fpureg) const {
973   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
974   return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
975 }
976 
get_fpu_register_signed_word(int fpureg) const977 int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
978   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
979   return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
980 }
981 
get_fpu_register_hi_word(int fpureg) const982 int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
983   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
984   return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xFFFFFFFF);
985 }
986 
get_fpu_register_float(int fpureg) const987 float Simulator::get_fpu_register_float(int fpureg) const {
988   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
989   return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
990 }
991 
get_fpu_register_double(int fpureg) const992 double Simulator::get_fpu_register_double(int fpureg) const {
993   DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
994   return *bit_cast<double*>(&FPUregisters_[fpureg]);
995 }
996 
get_cf_register(int cfreg) const997 bool Simulator::get_cf_register(int cfreg) const {
998   DCHECK((cfreg >= 0) && (cfreg < kNumCFRegisters));
999   return CFregisters_[cfreg];
1000 }
1001 
1002 // Runtime FP routines take up to two double arguments and zero
1003 // or one integer arguments. All are constructed here,
1004 // from a0-a3 or fa0 and fa1 (n64).
GetFpArgs(double * x,double * y,int32_t * z)1005 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1006   const int fparg2 = f1;
1007   *x = get_fpu_register_double(f0);
1008   *y = get_fpu_register_double(fparg2);
1009   *z = static_cast<int32_t>(get_register(a2));
1010 }
1011 
1012 // The return value is either in v0/v1 or f0.
SetFpResult(const double & result)1013 void Simulator::SetFpResult(const double& result) {
1014   set_fpu_register_double(0, result);
1015 }
1016 
1017 // Helper functions for setting and testing the FCSR register's bits.
set_fcsr_bit(uint32_t cc,bool value)1018 void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1019   if (value) {
1020     FCSR_ |= (1 << cc);
1021   } else {
1022     FCSR_ &= ~(1 << cc);
1023   }
1024 }
1025 
test_fcsr_bit(uint32_t cc)1026 bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
1027 
set_fcsr_rounding_mode(FPURoundingMode mode)1028 void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1029   FCSR_ |= mode & kFPURoundingModeMask;
1030 }
1031 
get_fcsr_rounding_mode()1032 unsigned int Simulator::get_fcsr_rounding_mode() {
1033   return FCSR_ & kFPURoundingModeMask;
1034 }
1035 
1036 // Sets the rounding error codes in FCSR based on the result of the rounding.
1037 // Returns true if the operation was invalid.
set_fcsr_round_error(double original,double rounded)1038 bool Simulator::set_fcsr_round_error(double original, double rounded) {
1039   bool ret = false;
1040   double max_int32 = std::numeric_limits<int32_t>::max();
1041   double min_int32 = std::numeric_limits<int32_t>::min();
1042   set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1043   set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1044   set_fcsr_bit(kFCSROverflowCauseBit, false);
1045   set_fcsr_bit(kFCSRInexactCauseBit, false);
1046 
1047   if (!std::isfinite(original) || !std::isfinite(rounded)) {
1048     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1049     ret = true;
1050   }
1051 
1052   if (original != rounded) {
1053     set_fcsr_bit(kFCSRInexactCauseBit, true);
1054   }
1055 
1056   if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1057     set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1058     ret = true;
1059   }
1060 
1061   if (rounded > max_int32 || rounded < min_int32) {
1062     set_fcsr_bit(kFCSROverflowCauseBit, true);
1063     // The reference is not really clear but it seems this is required:
1064     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1065     ret = true;
1066   }
1067 
1068   return ret;
1069 }
1070 
1071 // Sets the rounding error codes in FCSR based on the result of the rounding.
1072 // Returns true if the operation was invalid.
set_fcsr_round64_error(double original,double rounded)1073 bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1074   bool ret = false;
1075   // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1076   // loading the most accurate representation into max_int64, which is 2^63.
1077   double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1078   double min_int64 = std::numeric_limits<int64_t>::min();
1079   set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1080   set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1081   set_fcsr_bit(kFCSROverflowCauseBit, false);
1082   set_fcsr_bit(kFCSRInexactCauseBit, false);
1083 
1084   if (!std::isfinite(original) || !std::isfinite(rounded)) {
1085     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1086     ret = true;
1087   }
1088 
1089   if (original != rounded) {
1090     set_fcsr_bit(kFCSRInexactCauseBit, true);
1091   }
1092 
1093   if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1094     set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1095     ret = true;
1096   }
1097 
1098   if (rounded >= max_int64 || rounded < min_int64) {
1099     set_fcsr_bit(kFCSROverflowCauseBit, true);
1100     // The reference is not really clear but it seems this is required:
1101     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1102     ret = true;
1103   }
1104 
1105   return ret;
1106 }
1107 
1108 // Sets the rounding error codes in FCSR based on the result of the rounding.
1109 // Returns true if the operation was invalid.
set_fcsr_round_error(float original,float rounded)1110 bool Simulator::set_fcsr_round_error(float original, float rounded) {
1111   bool ret = false;
1112   double max_int32 = std::numeric_limits<int32_t>::max();
1113   double min_int32 = std::numeric_limits<int32_t>::min();
1114   set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1115   set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1116   set_fcsr_bit(kFCSROverflowCauseBit, false);
1117   set_fcsr_bit(kFCSRInexactCauseBit, false);
1118 
1119   if (!std::isfinite(original) || !std::isfinite(rounded)) {
1120     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1121     ret = true;
1122   }
1123 
1124   if (original != rounded) {
1125     set_fcsr_bit(kFCSRInexactCauseBit, true);
1126   }
1127 
1128   if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1129     set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1130     ret = true;
1131   }
1132 
1133   if (rounded > max_int32 || rounded < min_int32) {
1134     set_fcsr_bit(kFCSROverflowCauseBit, true);
1135     // The reference is not really clear but it seems this is required:
1136     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1137     ret = true;
1138   }
1139 
1140   return ret;
1141 }
1142 
set_fpu_register_word_invalid_result(float original,float rounded)1143 void Simulator::set_fpu_register_word_invalid_result(float original,
1144                                                      float rounded) {
1145   double max_int32 = std::numeric_limits<int32_t>::max();
1146   double min_int32 = std::numeric_limits<int32_t>::min();
1147   if (std::isnan(original)) {
1148     set_fpu_register_word(fd_reg(), 0);
1149   } else if (rounded > max_int32) {
1150     set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1151   } else if (rounded < min_int32) {
1152     set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1153   } else {
1154     UNREACHABLE();
1155   }
1156 }
1157 
set_fpu_register_invalid_result(float original,float rounded)1158 void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1159   double max_int32 = std::numeric_limits<int32_t>::max();
1160   double min_int32 = std::numeric_limits<int32_t>::min();
1161   if (std::isnan(original)) {
1162     set_fpu_register(fd_reg(), 0);
1163   } else if (rounded > max_int32) {
1164     set_fpu_register(fd_reg(), kFPUInvalidResult);
1165   } else if (rounded < min_int32) {
1166     set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1167   } else {
1168     UNREACHABLE();
1169   }
1170 }
1171 
set_fpu_register_invalid_result64(float original,float rounded)1172 void Simulator::set_fpu_register_invalid_result64(float original,
1173                                                   float rounded) {
1174   // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1175   // loading the most accurate representation into max_int64, which is 2^63.
1176   double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1177   double min_int64 = std::numeric_limits<int64_t>::min();
1178   if (std::isnan(original)) {
1179     set_fpu_register(fd_reg(), 0);
1180   } else if (rounded >= max_int64) {
1181     set_fpu_register(fd_reg(), kFPU64InvalidResult);
1182   } else if (rounded < min_int64) {
1183     set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1184   } else {
1185     UNREACHABLE();
1186   }
1187 }
1188 
set_fpu_register_word_invalid_result(double original,double rounded)1189 void Simulator::set_fpu_register_word_invalid_result(double original,
1190                                                      double rounded) {
1191   double max_int32 = std::numeric_limits<int32_t>::max();
1192   double min_int32 = std::numeric_limits<int32_t>::min();
1193   if (std::isnan(original)) {
1194     set_fpu_register_word(fd_reg(), 0);
1195   } else if (rounded > max_int32) {
1196     set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1197   } else if (rounded < min_int32) {
1198     set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1199   } else {
1200     UNREACHABLE();
1201   }
1202 }
1203 
set_fpu_register_invalid_result(double original,double rounded)1204 void Simulator::set_fpu_register_invalid_result(double original,
1205                                                 double rounded) {
1206   double max_int32 = std::numeric_limits<int32_t>::max();
1207   double min_int32 = std::numeric_limits<int32_t>::min();
1208   if (std::isnan(original)) {
1209     set_fpu_register(fd_reg(), 0);
1210   } else if (rounded > max_int32) {
1211     set_fpu_register(fd_reg(), kFPUInvalidResult);
1212   } else if (rounded < min_int32) {
1213     set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1214   } else {
1215     UNREACHABLE();
1216   }
1217 }
1218 
set_fpu_register_invalid_result64(double original,double rounded)1219 void Simulator::set_fpu_register_invalid_result64(double original,
1220                                                   double rounded) {
1221   // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1222   // loading the most accurate representation into max_int64, which is 2^63.
1223   double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1224   double min_int64 = std::numeric_limits<int64_t>::min();
1225   if (std::isnan(original)) {
1226     set_fpu_register(fd_reg(), 0);
1227   } else if (rounded >= max_int64) {
1228     set_fpu_register(fd_reg(), kFPU64InvalidResult);
1229   } else if (rounded < min_int64) {
1230     set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1231   } else {
1232     UNREACHABLE();
1233   }
1234 }
1235 
1236 // Sets the rounding error codes in FCSR based on the result of the rounding.
1237 // Returns true if the operation was invalid.
set_fcsr_round64_error(float original,float rounded)1238 bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1239   bool ret = false;
1240   // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1241   // loading the most accurate representation into max_int64, which is 2^63.
1242   double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1243   double min_int64 = std::numeric_limits<int64_t>::min();
1244   set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1245   set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1246   set_fcsr_bit(kFCSROverflowCauseBit, false);
1247   set_fcsr_bit(kFCSRInexactCauseBit, false);
1248 
1249   if (!std::isfinite(original) || !std::isfinite(rounded)) {
1250     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1251     ret = true;
1252   }
1253 
1254   if (original != rounded) {
1255     set_fcsr_bit(kFCSRInexactCauseBit, true);
1256   }
1257 
1258   if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1259     set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1260     ret = true;
1261   }
1262 
1263   if (rounded >= max_int64 || rounded < min_int64) {
1264     set_fcsr_bit(kFCSROverflowCauseBit, true);
1265     // The reference is not really clear but it seems this is required:
1266     set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1267     ret = true;
1268   }
1269 
1270   return ret;
1271 }
1272 
1273 // For ftint instructions only
round_according_to_fcsr(double toRound,double * rounded,int32_t * rounded_int)1274 void Simulator::round_according_to_fcsr(double toRound, double* rounded,
1275                                         int32_t* rounded_int) {
1276   // 0 RN (round to nearest): Round a result to the nearest
1277   // representable value; if the result is exactly halfway between
1278   // two representable values, round to zero.
1279 
1280   // 1 RZ (round toward zero): Round a result to the closest
1281   // representable value whose absolute value is less than or
1282   // equal to the infinitely accurate result.
1283 
1284   // 2 RP (round up, or toward +infinity): Round a result to the
1285   // next representable value up.
1286 
1287   // 3 RN (round down, or toward −infinity): Round a result to
1288   // the next representable value down.
1289   // switch ((FCSR_ >> 8) & 3) {
1290   switch (FCSR_ & kFPURoundingModeMask) {
1291     case kRoundToNearest:
1292       *rounded = std::floor(toRound + 0.5);
1293       *rounded_int = static_cast<int32_t>(*rounded);
1294       if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1295         // If the number is halfway between two integers,
1296         // round to the even one.
1297         *rounded_int -= 1;
1298         *rounded -= 1.;
1299       }
1300       break;
1301     case kRoundToZero:
1302       *rounded = trunc(toRound);
1303       *rounded_int = static_cast<int32_t>(*rounded);
1304       break;
1305     case kRoundToPlusInf:
1306       *rounded = std::ceil(toRound);
1307       *rounded_int = static_cast<int32_t>(*rounded);
1308       break;
1309     case kRoundToMinusInf:
1310       *rounded = std::floor(toRound);
1311       *rounded_int = static_cast<int32_t>(*rounded);
1312       break;
1313   }
1314 }
1315 
round64_according_to_fcsr(double toRound,double * rounded,int64_t * rounded_int)1316 void Simulator::round64_according_to_fcsr(double toRound, double* rounded,
1317                                           int64_t* rounded_int) {
1318   // 0 RN (round to nearest): Round a result to the nearest
1319   // representable value; if the result is exactly halfway between
1320   // two representable values, round to zero.
1321 
1322   // 1 RZ (round toward zero): Round a result to the closest
1323   // representable value whose absolute value is less than or.
1324   // equal to the infinitely accurate result.
1325 
1326   // 2 RP (round up, or toward +infinity): Round a result to the
1327   // next representable value up.
1328 
1329   // 3 RN (round down, or toward −infinity): Round a result to
1330   // the next representable value down.
1331   switch (FCSR_ & kFPURoundingModeMask) {
1332     case kRoundToNearest:
1333       *rounded = std::floor(toRound + 0.5);
1334       *rounded_int = static_cast<int64_t>(*rounded);
1335       if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1336         // If the number is halfway between two integers,
1337         // round to the even one.
1338         *rounded_int -= 1;
1339         *rounded -= 1.;
1340       }
1341       break;
1342     case kRoundToZero:
1343       *rounded = std::trunc(toRound);
1344       *rounded_int = static_cast<int64_t>(*rounded);
1345       break;
1346     case kRoundToPlusInf:
1347       *rounded = std::ceil(toRound);
1348       *rounded_int = static_cast<int64_t>(*rounded);
1349       break;
1350     case kRoundToMinusInf:
1351       *rounded = std::floor(toRound);
1352       *rounded_int = static_cast<int64_t>(*rounded);
1353       break;
1354   }
1355 }
1356 
round_according_to_fcsr(float toRound,float * rounded,int32_t * rounded_int)1357 void Simulator::round_according_to_fcsr(float toRound, float* rounded,
1358                                         int32_t* rounded_int) {
1359   // 0 RN (round to nearest): Round a result to the nearest
1360   // representable value; if the result is exactly halfway between
1361   // two representable values, round to zero.
1362 
1363   // 1 RZ (round toward zero): Round a result to the closest
1364   // representable value whose absolute value is less than or
1365   // equal to the infinitely accurate result.
1366 
1367   // 2 RP (round up, or toward +infinity): Round a result to the
1368   // next representable value up.
1369 
1370   // 3 RN (round down, or toward −infinity): Round a result to
1371   // the next representable value down.
1372   switch (FCSR_ & kFPURoundingModeMask) {
1373     case kRoundToNearest:
1374       *rounded = std::floor(toRound + 0.5);
1375       *rounded_int = static_cast<int32_t>(*rounded);
1376       if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1377         // If the number is halfway between two integers,
1378         // round to the even one.
1379         *rounded_int -= 1;
1380         *rounded -= 1.f;
1381       }
1382       break;
1383     case kRoundToZero:
1384       *rounded = std::trunc(toRound);
1385       *rounded_int = static_cast<int32_t>(*rounded);
1386       break;
1387     case kRoundToPlusInf:
1388       *rounded = std::ceil(toRound);
1389       *rounded_int = static_cast<int32_t>(*rounded);
1390       break;
1391     case kRoundToMinusInf:
1392       *rounded = std::floor(toRound);
1393       *rounded_int = static_cast<int32_t>(*rounded);
1394       break;
1395   }
1396 }
1397 
round64_according_to_fcsr(float toRound,float * rounded,int64_t * rounded_int)1398 void Simulator::round64_according_to_fcsr(float toRound, float* rounded,
1399                                           int64_t* rounded_int) {
1400   // 0 RN (round to nearest): Round a result to the nearest
1401   // representable value; if the result is exactly halfway between
1402   // two representable values, round to zero.
1403 
1404   // 1 RZ (round toward zero): Round a result to the closest
1405   // representable value whose absolute value is less than or.
1406   // equal to the infinitely accurate result.
1407 
1408   // 2 RP (round up, or toward +infinity): Round a result to the
1409   // next representable value up.
1410 
1411   // 3 RN (round down, or toward −infinity): Round a result to
1412   // the next representable value down.
1413   switch (FCSR_ & kFPURoundingModeMask) {
1414     case kRoundToNearest:
1415       *rounded = std::floor(toRound + 0.5);
1416       *rounded_int = static_cast<int64_t>(*rounded);
1417       if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1418         // If the number is halfway between two integers,
1419         // round to the even one.
1420         *rounded_int -= 1;
1421         *rounded -= 1.f;
1422       }
1423       break;
1424     case kRoundToZero:
1425       *rounded = trunc(toRound);
1426       *rounded_int = static_cast<int64_t>(*rounded);
1427       break;
1428     case kRoundToPlusInf:
1429       *rounded = std::ceil(toRound);
1430       *rounded_int = static_cast<int64_t>(*rounded);
1431       break;
1432     case kRoundToMinusInf:
1433       *rounded = std::floor(toRound);
1434       *rounded_int = static_cast<int64_t>(*rounded);
1435       break;
1436   }
1437 }
1438 
1439 // Raw access to the PC register.
set_pc(int64_t value)1440 void Simulator::set_pc(int64_t value) {
1441   pc_modified_ = true;
1442   registers_[pc] = value;
1443 }
1444 
has_bad_pc() const1445 bool Simulator::has_bad_pc() const {
1446   return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1447 }
1448 
1449 // Raw access to the PC register without the special adjustment when reading.
get_pc() const1450 int64_t Simulator::get_pc() const { return registers_[pc]; }
1451 
1452 // TODO(plind): refactor this messy debug code when we do unaligned access.
DieOrDebug()1453 void Simulator::DieOrDebug() {
1454   if ((1)) {  // Flag for this was removed.
1455     Loong64Debugger dbg(this);
1456     dbg.Debug();
1457   } else {
1458     base::OS::Abort();
1459   }
1460 }
1461 
TraceRegWr(int64_t value,TraceType t)1462 void Simulator::TraceRegWr(int64_t value, TraceType t) {
1463   if (::v8::internal::FLAG_trace_sim) {
1464     union {
1465       int64_t fmt_int64;
1466       int32_t fmt_int32[2];
1467       float fmt_float[2];
1468       double fmt_double;
1469     } v;
1470     v.fmt_int64 = value;
1471 
1472     switch (t) {
1473       case WORD:
1474         base::SNPrintF(trace_buf_,
1475                        "%016" PRIx64 "    (%" PRId64 ")    int32:%" PRId32
1476                        " uint32:%" PRIu32,
1477                        v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]);
1478         break;
1479       case DWORD:
1480         base::SNPrintF(trace_buf_,
1481                        "%016" PRIx64 "    (%" PRId64 ")    int64:%" PRId64
1482                        " uint64:%" PRIu64,
1483                        value, icount_, value, value);
1484         break;
1485       case FLOAT:
1486         base::SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRId64 ")    flt:%e",
1487                        v.fmt_int64, icount_, v.fmt_float[0]);
1488         break;
1489       case DOUBLE:
1490         base::SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRId64 ")    dbl:%e",
1491                        v.fmt_int64, icount_, v.fmt_double);
1492         break;
1493       case FLOAT_DOUBLE:
1494         base::SNPrintF(trace_buf_,
1495                        "%016" PRIx64 "    (%" PRId64 ")    flt:%e dbl:%e",
1496                        v.fmt_int64, icount_, v.fmt_float[0], v.fmt_double);
1497         break;
1498       case WORD_DWORD:
1499         base::SNPrintF(trace_buf_,
1500                        "%016" PRIx64 "    (%" PRId64 ")    int32:%" PRId32
1501                        " uint32:%" PRIu32 " int64:%" PRId64 " uint64:%" PRIu64,
1502                        v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0],
1503                        v.fmt_int64, v.fmt_int64);
1504         break;
1505       default:
1506         UNREACHABLE();
1507     }
1508   }
1509 }
1510 
1511 // TODO(plind): consider making icount_ printing a flag option.
TraceMemRd(int64_t addr,int64_t value,TraceType t)1512 void Simulator::TraceMemRd(int64_t addr, int64_t value, TraceType t) {
1513   if (::v8::internal::FLAG_trace_sim) {
1514     union {
1515       int64_t fmt_int64;
1516       int32_t fmt_int32[2];
1517       float fmt_float[2];
1518       double fmt_double;
1519     } v;
1520     v.fmt_int64 = value;
1521 
1522     switch (t) {
1523       case WORD:
1524         base::SNPrintF(trace_buf_,
1525                        "%016" PRIx64 "  <-- [%016" PRIx64 "]    (%" PRId64
1526                        ")    int32:%" PRId32 " uint32:%" PRIu32,
1527                        v.fmt_int64, addr, icount_, v.fmt_int32[0],
1528                        v.fmt_int32[0]);
1529         break;
1530       case DWORD:
1531         base::SNPrintF(trace_buf_,
1532                        "%016" PRIx64 "  <-- [%016" PRIx64 "]    (%" PRId64
1533                        ")    int64:%" PRId64 " uint64:%" PRIu64,
1534                        value, addr, icount_, value, value);
1535         break;
1536       case FLOAT:
1537         base::SNPrintF(trace_buf_,
1538                        "%016" PRIx64 "  <-- [%016" PRIx64 "]    (%" PRId64
1539                        ")    flt:%e",
1540                        v.fmt_int64, addr, icount_, v.fmt_float[0]);
1541         break;
1542       case DOUBLE:
1543         base::SNPrintF(trace_buf_,
1544                        "%016" PRIx64 "  <-- [%016" PRIx64 "]    (%" PRId64
1545                        ")    dbl:%e",
1546                        v.fmt_int64, addr, icount_, v.fmt_double);
1547         break;
1548       case FLOAT_DOUBLE:
1549         base::SNPrintF(trace_buf_,
1550                        "%016" PRIx64 "  <-- [%016" PRIx64 "]    (%" PRId64
1551                        ")    flt:%e dbl:%e",
1552                        v.fmt_int64, addr, icount_, v.fmt_float[0],
1553                        v.fmt_double);
1554         break;
1555       default:
1556         UNREACHABLE();
1557     }
1558   }
1559 }
1560 
TraceMemWr(int64_t addr,int64_t value,TraceType t)1561 void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
1562   if (::v8::internal::FLAG_trace_sim) {
1563     switch (t) {
1564       case BYTE:
1565         base::SNPrintF(trace_buf_,
1566                        "               %02" PRIx8 " --> [%016" PRIx64
1567                        "]    (%" PRId64 ")",
1568                        static_cast<uint8_t>(value), addr, icount_);
1569         break;
1570       case HALF:
1571         base::SNPrintF(trace_buf_,
1572                        "            %04" PRIx16 " --> [%016" PRIx64
1573                        "]    (%" PRId64 ")",
1574                        static_cast<uint16_t>(value), addr, icount_);
1575         break;
1576       case WORD:
1577         base::SNPrintF(trace_buf_,
1578                        "        %08" PRIx32 " --> [%016" PRIx64 "]    (%" PRId64
1579                        ")",
1580                        static_cast<uint32_t>(value), addr, icount_);
1581         break;
1582       case DWORD:
1583         base::SNPrintF(trace_buf_,
1584                        "%016" PRIx64 "  --> [%016" PRIx64 "]    (%" PRId64 " )",
1585                        value, addr, icount_);
1586         break;
1587       default:
1588         UNREACHABLE();
1589     }
1590   }
1591 }
1592 
1593 template <typename T>
TraceMemRd(int64_t addr,T value)1594 void Simulator::TraceMemRd(int64_t addr, T value) {
1595   if (::v8::internal::FLAG_trace_sim) {
1596     switch (sizeof(T)) {
1597       case 1:
1598         base::SNPrintF(trace_buf_,
1599                        "%08" PRIx8 " <-- [%08" PRIx64 "]    (%" PRIu64
1600                        ")    int8:%" PRId8 " uint8:%" PRIu8,
1601                        static_cast<uint8_t>(value), addr, icount_,
1602                        static_cast<int8_t>(value), static_cast<uint8_t>(value));
1603         break;
1604       case 2:
1605         base::SNPrintF(trace_buf_,
1606                        "%08" PRIx16 " <-- [%08" PRIx64 "]    (%" PRIu64
1607                        ")    int16:%" PRId16 " uint16:%" PRIu16,
1608                        static_cast<uint16_t>(value), addr, icount_,
1609                        static_cast<int16_t>(value),
1610                        static_cast<uint16_t>(value));
1611         break;
1612       case 4:
1613         base::SNPrintF(trace_buf_,
1614                        "%08" PRIx32 " <-- [%08" PRIx64 "]    (%" PRIu64
1615                        ")    int32:%" PRId32 " uint32:%" PRIu32,
1616                        static_cast<uint32_t>(value), addr, icount_,
1617                        static_cast<int32_t>(value),
1618                        static_cast<uint32_t>(value));
1619         break;
1620       case 8:
1621         base::SNPrintF(trace_buf_,
1622                        "%08" PRIx64 " <-- [%08" PRIx64 "]    (%" PRIu64
1623                        ")    int64:%" PRId64 " uint64:%" PRIu64,
1624                        static_cast<uint64_t>(value), addr, icount_,
1625                        static_cast<int64_t>(value),
1626                        static_cast<uint64_t>(value));
1627         break;
1628       default:
1629         UNREACHABLE();
1630     }
1631   }
1632 }
1633 
1634 template <typename T>
TraceMemWr(int64_t addr,T value)1635 void Simulator::TraceMemWr(int64_t addr, T value) {
1636   if (::v8::internal::FLAG_trace_sim) {
1637     switch (sizeof(T)) {
1638       case 1:
1639         base::SNPrintF(trace_buf_,
1640                        "      %02" PRIx8 " --> [%08" PRIx64 "]    (%" PRIu64
1641                        ")",
1642                        static_cast<uint8_t>(value), addr, icount_);
1643         break;
1644       case 2:
1645         base::SNPrintF(trace_buf_,
1646                        "    %04" PRIx16 " --> [%08" PRIx64 "]    (%" PRIu64 ")",
1647                        static_cast<uint16_t>(value), addr, icount_);
1648         break;
1649       case 4:
1650         base::SNPrintF(trace_buf_,
1651                        "%08" PRIx32 " --> [%08" PRIx64 "]    (%" PRIu64 ")",
1652                        static_cast<uint32_t>(value), addr, icount_);
1653         break;
1654       case 8:
1655         base::SNPrintF(trace_buf_,
1656                        "%16" PRIx64 " --> [%08" PRIx64 "]    (%" PRIu64 ")",
1657                        static_cast<uint64_t>(value), addr, icount_);
1658         break;
1659       default:
1660         UNREACHABLE();
1661     }
1662   }
1663 }
1664 
1665 // TODO(plind): sign-extend and zero-extend not implmented properly
1666 // on all the ReadXX functions, I don't think re-interpret cast does it.
ReadW(int64_t addr,Instruction * instr,TraceType t)1667 int32_t Simulator::ReadW(int64_t addr, Instruction* instr, TraceType t) {
1668   if (addr >= 0 && addr < 0x400) {
1669     // This has to be a nullptr-dereference, drop into debugger.
1670     PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1671            " \n",
1672            addr, reinterpret_cast<intptr_t>(instr));
1673     DieOrDebug();
1674   }
1675   /* if ((addr & 0x3) == 0)*/ {
1676     local_monitor_.NotifyLoad();
1677     int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1678     TraceMemRd(addr, static_cast<int64_t>(*ptr), t);
1679     return *ptr;
1680   }
1681   //  PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
1682   //  addr,
1683   //         reinterpret_cast<intptr_t>(instr));
1684   //  DieOrDebug();
1685   //  return 0;
1686 }
1687 
ReadWU(int64_t addr,Instruction * instr)1688 uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) {
1689   if (addr >= 0 && addr < 0x400) {
1690     // This has to be a nullptr-dereference, drop into debugger.
1691     PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1692            " \n",
1693            addr, reinterpret_cast<intptr_t>(instr));
1694     DieOrDebug();
1695   }
1696   // if ((addr & 0x3) == 0) {
1697   local_monitor_.NotifyLoad();
1698   uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1699   TraceMemRd(addr, static_cast<int64_t>(*ptr), WORD);
1700   return *ptr;
1701   // }
1702   // PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1703   //        reinterpret_cast<intptr_t>(instr));
1704   // DieOrDebug();
1705   // return 0;
1706 }
1707 
WriteW(int64_t addr,int32_t value,Instruction * instr)1708 void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) {
1709   if (addr >= 0 && addr < 0x400) {
1710     // This has to be a nullptr-dereference, drop into debugger.
1711     PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1712            " \n",
1713            addr, reinterpret_cast<intptr_t>(instr));
1714     DieOrDebug();
1715   }
1716   /*if ((addr & 0x3) == 0)*/ {
1717     local_monitor_.NotifyStore();
1718     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1719     GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1720     TraceMemWr(addr, value, WORD);
1721     int* ptr = reinterpret_cast<int*>(addr);
1722     *ptr = value;
1723     return;
1724   }
1725   //  PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
1726   //  addr,
1727   //         reinterpret_cast<intptr_t>(instr));
1728   //  DieOrDebug();
1729 }
1730 
WriteConditionalW(int64_t addr,int32_t value,Instruction * instr,int32_t rk_reg)1731 void Simulator::WriteConditionalW(int64_t addr, int32_t value,
1732                                   Instruction* instr, int32_t rk_reg) {
1733   if (addr >= 0 && addr < 0x400) {
1734     // This has to be a nullptr-dereference, drop into debugger.
1735     PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1736            " \n",
1737            addr, reinterpret_cast<intptr_t>(instr));
1738     DieOrDebug();
1739   }
1740   if ((addr & 0x3) == 0) {
1741     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1742     if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
1743         GlobalMonitor::Get()->NotifyStoreConditional_Locked(
1744             addr, &global_monitor_thread_)) {
1745       local_monitor_.NotifyStore();
1746       GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1747       TraceMemWr(addr, value, WORD);
1748       int* ptr = reinterpret_cast<int*>(addr);
1749       *ptr = value;
1750       set_register(rk_reg, 1);
1751     } else {
1752       set_register(rk_reg, 0);
1753     }
1754     return;
1755   }
1756   PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1757          reinterpret_cast<intptr_t>(instr));
1758   DieOrDebug();
1759 }
1760 
Read2W(int64_t addr,Instruction * instr)1761 int64_t Simulator::Read2W(int64_t addr, Instruction* instr) {
1762   if (addr >= 0 && addr < 0x400) {
1763     // This has to be a nullptr-dereference, drop into debugger.
1764     PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1765            " \n",
1766            addr, reinterpret_cast<intptr_t>(instr));
1767     DieOrDebug();
1768   }
1769   /*  if ((addr & kPointerAlignmentMask) == 0)*/ {
1770     local_monitor_.NotifyLoad();
1771     int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1772     TraceMemRd(addr, *ptr);
1773     return *ptr;
1774   }
1775   //  PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
1776   //  addr,
1777   //         reinterpret_cast<intptr_t>(instr));
1778   //  DieOrDebug();
1779   //  return 0;
1780 }
1781 
Write2W(int64_t addr,int64_t value,Instruction * instr)1782 void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) {
1783   if (addr >= 0 && addr < 0x400) {
1784     // This has to be a nullptr-dereference, drop into debugger.
1785     PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1786            "\n",
1787            addr, reinterpret_cast<intptr_t>(instr));
1788     DieOrDebug();
1789   }
1790   /*if ((addr & kPointerAlignmentMask) == 0)*/ {
1791     local_monitor_.NotifyStore();
1792     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1793     GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1794     TraceMemWr(addr, value, DWORD);
1795     int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1796     *ptr = value;
1797     return;
1798   }
1799   //  PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
1800   //  addr,
1801   //         reinterpret_cast<intptr_t>(instr));
1802   //  DieOrDebug();
1803 }
1804 
WriteConditional2W(int64_t addr,int64_t value,Instruction * instr,int32_t rk_reg)1805 void Simulator::WriteConditional2W(int64_t addr, int64_t value,
1806                                    Instruction* instr, int32_t rk_reg) {
1807   if (addr >= 0 && addr < 0x400) {
1808     // This has to be a nullptr-dereference, drop into debugger.
1809     PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1810            "\n",
1811            addr, reinterpret_cast<intptr_t>(instr));
1812     DieOrDebug();
1813   }
1814   if ((addr & kPointerAlignmentMask) == 0) {
1815     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1816     if (local_monitor_.NotifyStoreConditional(addr,
1817                                               TransactionSize::DoubleWord) &&
1818         GlobalMonitor::Get()->NotifyStoreConditional_Locked(
1819             addr, &global_monitor_thread_)) {
1820       local_monitor_.NotifyStore();
1821       GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1822       TraceMemWr(addr, value, DWORD);
1823       int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1824       *ptr = value;
1825       set_register(rk_reg, 1);
1826     } else {
1827       set_register(rk_reg, 0);
1828     }
1829     return;
1830   }
1831   PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1832          reinterpret_cast<intptr_t>(instr));
1833   DieOrDebug();
1834 }
1835 
ReadD(int64_t addr,Instruction * instr)1836 double Simulator::ReadD(int64_t addr, Instruction* instr) {
1837   /*if ((addr & kDoubleAlignmentMask) == 0)*/ {
1838     local_monitor_.NotifyLoad();
1839     double* ptr = reinterpret_cast<double*>(addr);
1840     return *ptr;
1841   }
1842   // PrintF("Unaligned (double) read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
1843   // "\n",
1844   //       addr, reinterpret_cast<intptr_t>(instr));
1845   // base::OS::Abort();
1846   // return 0;
1847 }
1848 
WriteD(int64_t addr,double value,Instruction * instr)1849 void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
1850   /*if ((addr & kDoubleAlignmentMask) == 0)*/ {
1851     local_monitor_.NotifyStore();
1852     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1853     GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1854     double* ptr = reinterpret_cast<double*>(addr);
1855     *ptr = value;
1856     return;
1857   }
1858   // PrintF("Unaligned (double) write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
1859   //       "\n",
1860   //       addr, reinterpret_cast<intptr_t>(instr));
1861   // DieOrDebug();
1862 }
1863 
ReadHU(int64_t addr,Instruction * instr)1864 uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
1865   // if ((addr & 1) == 0) {
1866   local_monitor_.NotifyLoad();
1867   uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1868   TraceMemRd(addr, static_cast<int64_t>(*ptr));
1869   return *ptr;
1870   // }
1871   // PrintF("Unaligned unsigned halfword read at 0x%08" PRIx64
1872   //        " , pc=0x%08" V8PRIxPTR "\n",
1873   //        addr, reinterpret_cast<intptr_t>(instr));
1874   // DieOrDebug();
1875   // return 0;
1876 }
1877 
ReadH(int64_t addr,Instruction * instr)1878 int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
1879   // if ((addr & 1) == 0) {
1880   local_monitor_.NotifyLoad();
1881   int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1882   TraceMemRd(addr, static_cast<int64_t>(*ptr));
1883   return *ptr;
1884   // }
1885   // PrintF("Unaligned signed halfword read at 0x%08" PRIx64
1886   //        " , pc=0x%08" V8PRIxPTR "\n",
1887   //        addr, reinterpret_cast<intptr_t>(instr));
1888   // DieOrDebug();
1889   // return 0;
1890 }
1891 
WriteH(int64_t addr,uint16_t value,Instruction * instr)1892 void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
1893   // if ((addr & 1) == 0) {
1894   local_monitor_.NotifyStore();
1895   base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1896   GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1897   TraceMemWr(addr, value, HALF);
1898   uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1899   *ptr = value;
1900   return;
1901   // }
1902   // PrintF("Unaligned unsigned halfword write at 0x%08" PRIx64
1903   //        " , pc=0x%08" V8PRIxPTR "\n",
1904   //        addr, reinterpret_cast<intptr_t>(instr));
1905   // DieOrDebug();
1906 }
1907 
WriteH(int64_t addr,int16_t value,Instruction * instr)1908 void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
1909   // if ((addr & 1) == 0) {
1910   local_monitor_.NotifyStore();
1911   base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1912   GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1913   TraceMemWr(addr, value, HALF);
1914   int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1915   *ptr = value;
1916   return;
1917   // }
1918   // PrintF("Unaligned halfword write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
1919   //        "\n",
1920   //        addr, reinterpret_cast<intptr_t>(instr));
1921   // DieOrDebug();
1922 }
1923 
ReadBU(int64_t addr)1924 uint32_t Simulator::ReadBU(int64_t addr) {
1925   local_monitor_.NotifyLoad();
1926   uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1927   TraceMemRd(addr, static_cast<int64_t>(*ptr));
1928   return *ptr & 0xFF;
1929 }
1930 
ReadB(int64_t addr)1931 int32_t Simulator::ReadB(int64_t addr) {
1932   local_monitor_.NotifyLoad();
1933   int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1934   TraceMemRd(addr, static_cast<int64_t>(*ptr));
1935   return *ptr;
1936 }
1937 
WriteB(int64_t addr,uint8_t value)1938 void Simulator::WriteB(int64_t addr, uint8_t value) {
1939   local_monitor_.NotifyStore();
1940   base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1941   GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1942   TraceMemWr(addr, value, BYTE);
1943   uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1944   *ptr = value;
1945 }
1946 
WriteB(int64_t addr,int8_t value)1947 void Simulator::WriteB(int64_t addr, int8_t value) {
1948   local_monitor_.NotifyStore();
1949   base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1950   GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1951   TraceMemWr(addr, value, BYTE);
1952   int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1953   *ptr = value;
1954 }
1955 
1956 template <typename T>
ReadMem(int64_t addr,Instruction * instr)1957 T Simulator::ReadMem(int64_t addr, Instruction* instr) {
1958   int alignment_mask = (1 << sizeof(T)) - 1;
1959   if ((addr & alignment_mask) == 0) {
1960     local_monitor_.NotifyLoad();
1961     T* ptr = reinterpret_cast<T*>(addr);
1962     TraceMemRd(addr, *ptr);
1963     return *ptr;
1964   }
1965   PrintF("Unaligned read of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
1966          "\n",
1967          sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
1968   base::OS::Abort();
1969   return 0;
1970 }
1971 
1972 template <typename T>
WriteMem(int64_t addr,T value,Instruction * instr)1973 void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) {
1974   int alignment_mask = (1 << sizeof(T)) - 1;
1975   if ((addr & alignment_mask) == 0) {
1976     local_monitor_.NotifyStore();
1977     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1978     GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1979     T* ptr = reinterpret_cast<T*>(addr);
1980     *ptr = value;
1981     TraceMemWr(addr, value);
1982     return;
1983   }
1984   PrintF("Unaligned write of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
1985          "\n",
1986          sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
1987   base::OS::Abort();
1988 }
1989 
1990 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const1991 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1992   // The simulator uses a separate JS stack. If we have exhausted the C stack,
1993   // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1994   if (base::Stack::GetCurrentStackPosition() < c_limit) {
1995     return reinterpret_cast<uintptr_t>(get_sp());
1996   }
1997 
1998   // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1999   // to prevent overrunning the stack when pushing values.
2000   return reinterpret_cast<uintptr_t>(stack_) + 1024;
2001 }
2002 
2003 // Unsupported instructions use Format to print an error and stop execution.
Format(Instruction * instr,const char * format)2004 void Simulator::Format(Instruction* instr, const char* format) {
2005   PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n",
2006          reinterpret_cast<intptr_t>(instr), format);
2007   UNIMPLEMENTED();
2008 }
2009 
2010 // Calls into the V8 runtime are based on this very simple interface.
2011 // Note: To be able to return two values from some calls the code in runtime.cc
2012 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
2013 // 64-bit value. With the code below we assume that all runtime calls return
2014 // 64 bits of result. If they don't, the v1 result register contains a bogus
2015 // value, which is fine because it is caller-saved.
2016 
2017 using SimulatorRuntimeCall = ObjectPair (*)(
2018     int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4,
2019     int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg9,
2020     int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13, int64_t arg14,
2021     int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18, int64_t arg19);
2022 
2023 // These prototypes handle the four types of FP calls.
2024 using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
2025 using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
2026 using SimulatorRuntimeFPCall = double (*)(double darg0);
2027 using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
2028 
2029 // This signature supports direct call in to API function native callback
2030 // (refer to InvocationCallback in v8.h).
2031 using SimulatorRuntimeDirectApiCall = void (*)(int64_t arg0);
2032 using SimulatorRuntimeProfilingApiCall = void (*)(int64_t arg0, void* arg1);
2033 
2034 // This signature supports direct call to accessor getter callback.
2035 using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1);
2036 using SimulatorRuntimeProfilingGetterCall = void (*)(int64_t arg0, int64_t arg1,
2037                                                      void* arg2);
2038 
2039 // Software interrupt instructions are used by the simulator to call into the
2040 // C-based V8 runtime. They are also used for debugging with simulator.
SoftwareInterrupt()2041 void Simulator::SoftwareInterrupt() {
2042   int32_t opcode_hi15 = instr_.Bits(31, 17);
2043   CHECK_EQ(opcode_hi15, 0x15);
2044   uint32_t code = instr_.Bits(14, 0);
2045   // We first check if we met a call_rt_redirected.
2046   if (instr_.InstructionBits() == rtCallRedirInstr) {
2047     Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2048 
2049     int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
2050 
2051     int64_t arg0 = get_register(a0);
2052     int64_t arg1 = get_register(a1);
2053     int64_t arg2 = get_register(a2);
2054     int64_t arg3 = get_register(a3);
2055     int64_t arg4 = get_register(a4);
2056     int64_t arg5 = get_register(a5);
2057     int64_t arg6 = get_register(a6);
2058     int64_t arg7 = get_register(a7);
2059     int64_t arg8 = stack_pointer[0];
2060     int64_t arg9 = stack_pointer[1];
2061     int64_t arg10 = stack_pointer[2];
2062     int64_t arg11 = stack_pointer[3];
2063     int64_t arg12 = stack_pointer[4];
2064     int64_t arg13 = stack_pointer[5];
2065     int64_t arg14 = stack_pointer[6];
2066     int64_t arg15 = stack_pointer[7];
2067     int64_t arg16 = stack_pointer[8];
2068     int64_t arg17 = stack_pointer[9];
2069     int64_t arg18 = stack_pointer[10];
2070     int64_t arg19 = stack_pointer[11];
2071     STATIC_ASSERT(kMaxCParameters == 20);
2072 
2073     bool fp_call =
2074         (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2075         (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2076         (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2077         (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2078 
2079     {
2080       // With the hard floating point calling convention, double
2081       // arguments are passed in FPU registers. Fetch the arguments
2082       // from there and call the builtin using soft floating point
2083       // convention.
2084       switch (redirection->type()) {
2085         case ExternalReference::BUILTIN_FP_FP_CALL:
2086         case ExternalReference::BUILTIN_COMPARE_CALL:
2087           arg0 = get_fpu_register(f0);
2088           arg1 = get_fpu_register(f1);
2089           arg2 = get_fpu_register(f2);
2090           arg3 = get_fpu_register(f3);
2091           break;
2092         case ExternalReference::BUILTIN_FP_CALL:
2093           arg0 = get_fpu_register(f0);
2094           arg1 = get_fpu_register(f1);
2095           break;
2096         case ExternalReference::BUILTIN_FP_INT_CALL:
2097           arg0 = get_fpu_register(f0);
2098           arg1 = get_fpu_register(f1);
2099           arg2 = get_register(a2);
2100           break;
2101         default:
2102           break;
2103       }
2104     }
2105 
2106     // This is dodgy but it works because the C entry stubs are never moved.
2107     // See comment in codegen-arm.cc and bug 1242173.
2108     int64_t saved_ra = get_register(ra);
2109 
2110     intptr_t external =
2111         reinterpret_cast<intptr_t>(redirection->external_function());
2112 
2113     // Based on CpuFeatures::IsSupported(FPU), Loong64 will use either hardware
2114     // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2115     // simulator. Soft-float has additional abstraction of ExternalReference,
2116     // to support serialization.
2117     if (fp_call) {
2118       double dval0, dval1;  // one or two double parameters
2119       int32_t ival;         // zero or one integer parameters
2120       int64_t iresult = 0;  // integer return value
2121       double dresult = 0;   // double return value
2122       GetFpArgs(&dval0, &dval1, &ival);
2123       SimulatorRuntimeCall generic_target =
2124           reinterpret_cast<SimulatorRuntimeCall>(external);
2125       if (::v8::internal::FLAG_trace_sim) {
2126         switch (redirection->type()) {
2127           case ExternalReference::BUILTIN_FP_FP_CALL:
2128           case ExternalReference::BUILTIN_COMPARE_CALL:
2129             PrintF("Call to host function at %p with args %f, %f",
2130                    reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2131                    dval0, dval1);
2132             break;
2133           case ExternalReference::BUILTIN_FP_CALL:
2134             PrintF("Call to host function at %p with arg %f",
2135                    reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2136                    dval0);
2137             break;
2138           case ExternalReference::BUILTIN_FP_INT_CALL:
2139             PrintF("Call to host function at %p with args %f, %d",
2140                    reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2141                    dval0, ival);
2142             break;
2143           default:
2144             UNREACHABLE();
2145         }
2146       }
2147       switch (redirection->type()) {
2148         case ExternalReference::BUILTIN_COMPARE_CALL: {
2149           SimulatorRuntimeCompareCall target =
2150               reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2151           iresult = target(dval0, dval1);
2152           set_register(v0, static_cast<int64_t>(iresult));
2153           //  set_register(v1, static_cast<int64_t>(iresult >> 32));
2154           break;
2155         }
2156         case ExternalReference::BUILTIN_FP_FP_CALL: {
2157           SimulatorRuntimeFPFPCall target =
2158               reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2159           dresult = target(dval0, dval1);
2160           SetFpResult(dresult);
2161           break;
2162         }
2163         case ExternalReference::BUILTIN_FP_CALL: {
2164           SimulatorRuntimeFPCall target =
2165               reinterpret_cast<SimulatorRuntimeFPCall>(external);
2166           dresult = target(dval0);
2167           SetFpResult(dresult);
2168           break;
2169         }
2170         case ExternalReference::BUILTIN_FP_INT_CALL: {
2171           SimulatorRuntimeFPIntCall target =
2172               reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2173           dresult = target(dval0, ival);
2174           SetFpResult(dresult);
2175           break;
2176         }
2177         default:
2178           UNREACHABLE();
2179       }
2180       if (::v8::internal::FLAG_trace_sim) {
2181         switch (redirection->type()) {
2182           case ExternalReference::BUILTIN_COMPARE_CALL:
2183             PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2184             break;
2185           case ExternalReference::BUILTIN_FP_FP_CALL:
2186           case ExternalReference::BUILTIN_FP_CALL:
2187           case ExternalReference::BUILTIN_FP_INT_CALL:
2188             PrintF("Returned %f\n", dresult);
2189             break;
2190           default:
2191             UNREACHABLE();
2192         }
2193       }
2194     } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2195       if (::v8::internal::FLAG_trace_sim) {
2196         PrintF("Call to host function at %p args %08" PRIx64 " \n",
2197                reinterpret_cast<void*>(external), arg0);
2198       }
2199       SimulatorRuntimeDirectApiCall target =
2200           reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2201       target(arg0);
2202     } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
2203       if (::v8::internal::FLAG_trace_sim) {
2204         PrintF("Call to host function at %p args %08" PRIx64 "  %08" PRIx64
2205                " \n",
2206                reinterpret_cast<void*>(external), arg0, arg1);
2207       }
2208       SimulatorRuntimeProfilingApiCall target =
2209           reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2210       target(arg0, Redirection::ReverseRedirection(arg1));
2211     } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2212       if (::v8::internal::FLAG_trace_sim) {
2213         PrintF("Call to host function at %p args %08" PRIx64 "  %08" PRIx64
2214                " \n",
2215                reinterpret_cast<void*>(external), arg0, arg1);
2216       }
2217       SimulatorRuntimeDirectGetterCall target =
2218           reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2219       target(arg0, arg1);
2220     } else if (redirection->type() ==
2221                ExternalReference::PROFILING_GETTER_CALL) {
2222       if (::v8::internal::FLAG_trace_sim) {
2223         PrintF("Call to host function at %p args %08" PRIx64 "  %08" PRIx64
2224                "  %08" PRIx64 " \n",
2225                reinterpret_cast<void*>(external), arg0, arg1, arg2);
2226       }
2227       SimulatorRuntimeProfilingGetterCall target =
2228           reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2229       target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2230     } else {
2231       DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2232              redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2233       SimulatorRuntimeCall target =
2234           reinterpret_cast<SimulatorRuntimeCall>(external);
2235       if (::v8::internal::FLAG_trace_sim) {
2236         PrintF(
2237             "Call to host function at %p "
2238             "args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2239             " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2240             " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2241             " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2242             " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2243             " \n",
2244             reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
2245             arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
2246             arg13, arg14, arg15, arg16, arg17, arg18, arg19);
2247       }
2248       ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
2249                                  arg8, arg9, arg10, arg11, arg12, arg13, arg14,
2250                                  arg15, arg16, arg17, arg18, arg19);
2251       set_register(v0, (int64_t)(result.x));
2252       set_register(v1, (int64_t)(result.y));
2253     }
2254     if (::v8::internal::FLAG_trace_sim) {
2255       PrintF("Returned %08" PRIx64 "  : %08" PRIx64 " \n", get_register(v1),
2256              get_register(v0));
2257     }
2258     set_register(ra, saved_ra);
2259     set_pc(get_register(ra));
2260 
2261   } else if (code <= kMaxStopCode) {
2262     if (IsWatchpoint(code)) {
2263       PrintWatchpoint(code);
2264     } else {
2265       IncreaseStopCounter(code);
2266       HandleStop(code, instr_.instr());
2267     }
2268   } else {
2269     // All remaining break_ codes, and all traps are handled here.
2270     Loong64Debugger dbg(this);
2271     dbg.Debug();
2272   }
2273 }
2274 
2275 // Stop helper functions.
IsWatchpoint(uint64_t code)2276 bool Simulator::IsWatchpoint(uint64_t code) {
2277   return (code <= kMaxWatchpointCode);
2278 }
2279 
PrintWatchpoint(uint64_t code)2280 void Simulator::PrintWatchpoint(uint64_t code) {
2281   Loong64Debugger dbg(this);
2282   ++break_count_;
2283   PrintF("\n---- break %" PRId64 "  marker: %3d  (instr count: %8" PRId64
2284          " ) ----------"
2285          "----------------------------------",
2286          code, break_count_, icount_);
2287   dbg.PrintAllRegs();  // Print registers and continue running.
2288 }
2289 
HandleStop(uint64_t code,Instruction * instr)2290 void Simulator::HandleStop(uint64_t code, Instruction* instr) {
2291   // Stop if it is enabled, otherwise go on jumping over the stop
2292   // and the message address.
2293   if (IsEnabledStop(code)) {
2294     Loong64Debugger dbg(this);
2295     dbg.Stop(instr);
2296   }
2297 }
2298 
IsStopInstruction(Instruction * instr)2299 bool Simulator::IsStopInstruction(Instruction* instr) {
2300   int32_t opcode_hi15 = instr->Bits(31, 17);
2301   uint32_t code = static_cast<uint32_t>(instr->Bits(14, 0));
2302   return (opcode_hi15 == 0x15) && code > kMaxWatchpointCode &&
2303          code <= kMaxStopCode;
2304 }
2305 
IsEnabledStop(uint64_t code)2306 bool Simulator::IsEnabledStop(uint64_t code) {
2307   DCHECK_LE(code, kMaxStopCode);
2308   DCHECK_GT(code, kMaxWatchpointCode);
2309   return !(watched_stops_[code].count & kStopDisabledBit);
2310 }
2311 
EnableStop(uint64_t code)2312 void Simulator::EnableStop(uint64_t code) {
2313   if (!IsEnabledStop(code)) {
2314     watched_stops_[code].count &= ~kStopDisabledBit;
2315   }
2316 }
2317 
DisableStop(uint64_t code)2318 void Simulator::DisableStop(uint64_t code) {
2319   if (IsEnabledStop(code)) {
2320     watched_stops_[code].count |= kStopDisabledBit;
2321   }
2322 }
2323 
IncreaseStopCounter(uint64_t code)2324 void Simulator::IncreaseStopCounter(uint64_t code) {
2325   DCHECK_LE(code, kMaxStopCode);
2326   if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2327     PrintF("Stop counter for code %" PRId64
2328            "  has overflowed.\n"
2329            "Enabling this code and reseting the counter to 0.\n",
2330            code);
2331     watched_stops_[code].count = 0;
2332     EnableStop(code);
2333   } else {
2334     watched_stops_[code].count++;
2335   }
2336 }
2337 
2338 // Print a stop status.
PrintStopInfo(uint64_t code)2339 void Simulator::PrintStopInfo(uint64_t code) {
2340   if (code <= kMaxWatchpointCode) {
2341     PrintF("That is a watchpoint, not a stop.\n");
2342     return;
2343   } else if (code > kMaxStopCode) {
2344     PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2345     return;
2346   }
2347   const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2348   int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2349   // Don't print the state of unused breakpoints.
2350   if (count != 0) {
2351     if (watched_stops_[code].desc) {
2352       PrintF("stop %" PRId64 "  - 0x%" PRIx64 " : \t%s, \tcounter = %i, \t%s\n",
2353              code, code, state, count, watched_stops_[code].desc);
2354     } else {
2355       PrintF("stop %" PRId64 "  - 0x%" PRIx64 " : \t%s, \tcounter = %i\n", code,
2356              code, state, count);
2357     }
2358   }
2359 }
2360 
SignalException(Exception e)2361 void Simulator::SignalException(Exception e) {
2362   FATAL("Error: Exception %i raised.", static_cast<int>(e));
2363 }
2364 
2365 template <typename T>
2366 static T FPAbs(T a);
2367 
2368 template <>
FPAbs(double a)2369 double FPAbs<double>(double a) {
2370   return fabs(a);
2371 }
2372 
2373 template <>
FPAbs(float a)2374 float FPAbs<float>(float a) {
2375   return fabsf(a);
2376 }
2377 
2378 template <typename T>
FPUProcessNaNsAndZeros(T a,T b,MaxMinKind kind,T * result)2379 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
2380   if (std::isnan(a) && std::isnan(b)) {
2381     *result = a;
2382   } else if (std::isnan(a)) {
2383     *result = b;
2384   } else if (std::isnan(b)) {
2385     *result = a;
2386   } else if (b == a) {
2387     // Handle -0.0 == 0.0 case.
2388     // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2389     // negates the result.
2390     *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2391   } else {
2392     return false;
2393   }
2394   return true;
2395 }
2396 
2397 template <typename T>
FPUMin(T a,T b)2398 static T FPUMin(T a, T b) {
2399   T result;
2400   if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2401     return result;
2402   } else {
2403     return b < a ? b : a;
2404   }
2405 }
2406 
2407 template <typename T>
FPUMax(T a,T b)2408 static T FPUMax(T a, T b) {
2409   T result;
2410   if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
2411     return result;
2412   } else {
2413     return b > a ? b : a;
2414   }
2415 }
2416 
2417 template <typename T>
FPUMinA(T a,T b)2418 static T FPUMinA(T a, T b) {
2419   T result;
2420   if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2421     if (FPAbs(a) < FPAbs(b)) {
2422       result = a;
2423     } else if (FPAbs(b) < FPAbs(a)) {
2424       result = b;
2425     } else {
2426       result = a < b ? a : b;
2427     }
2428   }
2429   return result;
2430 }
2431 
2432 template <typename T>
FPUMaxA(T a,T b)2433 static T FPUMaxA(T a, T b) {
2434   T result;
2435   if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2436     if (FPAbs(a) > FPAbs(b)) {
2437       result = a;
2438     } else if (FPAbs(b) > FPAbs(a)) {
2439       result = b;
2440     } else {
2441       result = a > b ? a : b;
2442     }
2443   }
2444   return result;
2445 }
2446 
2447 enum class KeepSign : bool { no = false, yes };
2448 
2449 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2450                                               int>::type = 0>
FPUCanonalizeNaNArg(T result,T arg,KeepSign keepSign=KeepSign::no)2451 T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2452   DCHECK(std::isnan(arg));
2453   T qNaN = std::numeric_limits<T>::quiet_NaN();
2454   if (keepSign == KeepSign::yes) {
2455     return std::copysign(qNaN, result);
2456   }
2457   return qNaN;
2458 }
2459 
2460 template <typename T>
FPUCanonalizeNaNArgs(T result,KeepSign keepSign,T first)2461 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2462   if (std::isnan(first)) {
2463     return FPUCanonalizeNaNArg(result, first, keepSign);
2464   }
2465   return result;
2466 }
2467 
2468 template <typename T, typename... Args>
FPUCanonalizeNaNArgs(T result,KeepSign keepSign,T first,Args...args)2469 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2470   if (std::isnan(first)) {
2471     return FPUCanonalizeNaNArg(result, first, keepSign);
2472   }
2473   return FPUCanonalizeNaNArgs(result, keepSign, args...);
2474 }
2475 
2476 template <typename Func, typename T, typename... Args>
FPUCanonalizeOperation(Func f,T first,Args...args)2477 T FPUCanonalizeOperation(Func f, T first, Args... args) {
2478   return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2479 }
2480 
2481 template <typename Func, typename T, typename... Args>
FPUCanonalizeOperation(Func f,KeepSign keepSign,T first,Args...args)2482 T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2483   T result = f(first, args...);
2484   if (std::isnan(result)) {
2485     result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2486   }
2487   return result;
2488 }
2489 
2490 // Handle execution based on instruction types.
DecodeTypeOp6()2491 void Simulator::DecodeTypeOp6() {
2492   int64_t alu_out;
2493   // Next pc.
2494   int64_t next_pc = bad_ra;
2495 
2496   // Branch instructions common part.
2497   auto BranchAndLinkHelper = [this, &next_pc]() {
2498     int64_t current_pc = get_pc();
2499     set_register(ra, current_pc + kInstrSize);
2500     int32_t offs26_low16 =
2501         static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2502     int32_t offs26_high10 = static_cast<int32_t>(instr_.Bits(9, 0) << 22) >> 6;
2503     int32_t offs26 = offs26_low16 | offs26_high10;
2504     next_pc = current_pc + (offs26 << 2);
2505     printf_instr("Offs26: %08x\n", offs26);
2506     set_pc(next_pc);
2507   };
2508 
2509   auto BranchOff16Helper = [this, &next_pc](bool do_branch) {
2510     int64_t current_pc = get_pc();
2511     int32_t offs16 = static_cast<int32_t>(instr_.Bits(25, 10) << 16) >> 16;
2512     printf_instr("Offs16: %08x\n", offs16);
2513     int32_t offs = do_branch ? (offs16 << 2) : kInstrSize;
2514     next_pc = current_pc + offs;
2515     set_pc(next_pc);
2516   };
2517 
2518   auto BranchOff21Helper = [this, &next_pc](bool do_branch) {
2519     int64_t current_pc = get_pc();
2520     int32_t offs21_low16 =
2521         static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2522     int32_t offs21_high5 = static_cast<int32_t>(instr_.Bits(4, 0) << 27) >> 11;
2523     int32_t offs = offs21_low16 | offs21_high5;
2524     printf_instr("Offs21: %08x\n", offs);
2525     offs = do_branch ? (offs << 2) : kInstrSize;
2526     next_pc = current_pc + offs;
2527     set_pc(next_pc);
2528   };
2529 
2530   auto BranchOff26Helper = [this, &next_pc]() {
2531     int64_t current_pc = get_pc();
2532     int32_t offs26_low16 =
2533         static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2534     int32_t offs26_high10 = static_cast<int32_t>(instr_.Bits(9, 0) << 22) >> 6;
2535     int32_t offs26 = offs26_low16 | offs26_high10;
2536     next_pc = current_pc + (offs26 << 2);
2537     printf_instr("Offs26: %08x\n", offs26);
2538     set_pc(next_pc);
2539   };
2540 
2541   auto JumpOff16Helper = [this, &next_pc]() {
2542     int32_t offs16 = static_cast<int32_t>(instr_.Bits(25, 10) << 16) >> 16;
2543     printf_instr("JIRL\t %s: %016lx, %s: %016lx, offs16: %x\n",
2544                  Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2545                  rj(), offs16);
2546     set_register(rd_reg(), get_pc() + kInstrSize);
2547     next_pc = rj() + (offs16 << 2);
2548     set_pc(next_pc);
2549   };
2550 
2551   switch (instr_.Bits(31, 26) << 26) {
2552     case ADDU16I_D: {
2553       printf_instr("ADDU16I_D\t %s: %016lx, %s: %016lx, si16: %d\n",
2554                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2555                    rj(), si16());
2556       int32_t si16_upper = static_cast<int32_t>(si16()) << 16;
2557       alu_out = static_cast<int64_t>(si16_upper) + rj();
2558       SetResult(rd_reg(), alu_out);
2559       break;
2560     }
2561     case BEQZ:
2562       printf_instr("BEQZ\t %s: %016lx, ", Registers::Name(rj_reg()), rj());
2563       BranchOff21Helper(rj() == 0);
2564       break;
2565     case BNEZ:
2566       printf_instr("BNEZ\t %s: %016lx, ", Registers::Name(rj_reg()), rj());
2567       BranchOff21Helper(rj() != 0);
2568       break;
2569     case BCZ: {
2570       if (instr_.Bits(9, 8) == 0b00) {
2571         // BCEQZ
2572         printf_instr("BCEQZ\t fcc%d: %s, ", cj_reg(), cj() ? "True" : "False");
2573         BranchOff21Helper(cj() == false);
2574       } else if (instr_.Bits(9, 8) == 0b01) {
2575         // BCNEZ
2576         printf_instr("BCNEZ\t fcc%d: %s, ", cj_reg(), cj() ? "True" : "False");
2577         BranchOff21Helper(cj() == true);
2578       } else {
2579         UNREACHABLE();
2580       }
2581       break;
2582     }
2583     case JIRL:
2584       JumpOff16Helper();
2585       break;
2586     case B:
2587       printf_instr("B\t ");
2588       BranchOff26Helper();
2589       break;
2590     case BL:
2591       printf_instr("BL\t ");
2592       BranchAndLinkHelper();
2593       break;
2594     case BEQ:
2595       printf_instr("BEQ\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2596                    rj(), Registers::Name(rd_reg()), rd());
2597       BranchOff16Helper(rj() == rd());
2598       break;
2599     case BNE:
2600       printf_instr("BNE\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2601                    rj(), Registers::Name(rd_reg()), rd());
2602       BranchOff16Helper(rj() != rd());
2603       break;
2604     case BLT:
2605       printf_instr("BLT\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2606                    rj(), Registers::Name(rd_reg()), rd());
2607       BranchOff16Helper(rj() < rd());
2608       break;
2609     case BGE:
2610       printf_instr("BGE\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2611                    rj(), Registers::Name(rd_reg()), rd());
2612       BranchOff16Helper(rj() >= rd());
2613       break;
2614     case BLTU:
2615       printf_instr("BLTU\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2616                    rj(), Registers::Name(rd_reg()), rd());
2617       BranchOff16Helper(rj_u() < rd_u());
2618       break;
2619     case BGEU:
2620       printf_instr("BGEU\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2621                    rj(), Registers::Name(rd_reg()), rd());
2622       BranchOff16Helper(rj_u() >= rd_u());
2623       break;
2624     default:
2625       UNREACHABLE();
2626   }
2627 }
2628 
DecodeTypeOp7()2629 void Simulator::DecodeTypeOp7() {
2630   int64_t alu_out;
2631 
2632   switch (instr_.Bits(31, 25) << 25) {
2633     case LU12I_W: {
2634       printf_instr("LU12I_W\t %s: %016lx, si20: %d\n",
2635                    Registers::Name(rd_reg()), rd(), si20());
2636       int32_t si20_upper = static_cast<int32_t>(si20() << 12);
2637       SetResult(rd_reg(), static_cast<int64_t>(si20_upper));
2638       break;
2639     }
2640     case LU32I_D: {
2641       printf_instr("LU32I_D\t %s: %016lx, si20: %d\n",
2642                    Registers::Name(rd_reg()), rd(), si20());
2643       int32_t si20_signExtend = static_cast<int32_t>(si20() << 12) >> 12;
2644       int64_t lower_32bit_mask = 0xFFFFFFFF;
2645       alu_out = (static_cast<int64_t>(si20_signExtend) << 32) |
2646                 (rd() & lower_32bit_mask);
2647       SetResult(rd_reg(), alu_out);
2648       break;
2649     }
2650     case PCADDI: {
2651       printf_instr("PCADDI\t %s: %016lx, si20: %d\n", Registers::Name(rd_reg()),
2652                    rd(), si20());
2653       int32_t si20_signExtend = static_cast<int32_t>(si20() << 12) >> 10;
2654       int64_t current_pc = get_pc();
2655       alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2656       SetResult(rd_reg(), alu_out);
2657       break;
2658     }
2659     case PCALAU12I: {
2660       printf_instr("PCALAU12I\t %s: %016lx, si20: %d\n",
2661                    Registers::Name(rd_reg()), rd(), si20());
2662       int32_t si20_signExtend = static_cast<int32_t>(si20() << 12);
2663       int64_t current_pc = get_pc();
2664       int64_t clear_lower12bit_mask = 0xFFFFFFFFFFFFF000;
2665       alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2666       SetResult(rd_reg(), alu_out & clear_lower12bit_mask);
2667       break;
2668     }
2669     case PCADDU12I: {
2670       printf_instr("PCADDU12I\t %s: %016lx, si20: %d\n",
2671                    Registers::Name(rd_reg()), rd(), si20());
2672       int32_t si20_signExtend = static_cast<int32_t>(si20() << 12);
2673       int64_t current_pc = get_pc();
2674       alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2675       SetResult(rd_reg(), alu_out);
2676       break;
2677     }
2678     case PCADDU18I: {
2679       printf_instr("PCADDU18I\t %s: %016lx, si20: %d\n",
2680                    Registers::Name(rd_reg()), rd(), si20());
2681       int64_t si20_signExtend = (static_cast<int64_t>(si20()) << 44) >> 26;
2682       int64_t current_pc = get_pc();
2683       alu_out = si20_signExtend + current_pc;
2684       SetResult(rd_reg(), alu_out);
2685       break;
2686     }
2687     default:
2688       UNREACHABLE();
2689   }
2690 }
2691 
DecodeTypeOp8()2692 void Simulator::DecodeTypeOp8() {
2693   int64_t addr = 0x0;
2694   int64_t si14_se = (static_cast<int64_t>(si14()) << 50) >> 48;
2695 
2696   switch (instr_.Bits(31, 24) << 24) {
2697     case LDPTR_W:
2698       printf_instr("LDPTR_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2699                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2700                    rj(), si14_se);
2701       set_register(rd_reg(), ReadW(rj() + si14_se, instr_.instr()));
2702       break;
2703     case STPTR_W:
2704       printf_instr("STPTR_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2705                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2706                    rj(), si14_se);
2707       WriteW(rj() + si14_se, static_cast<int32_t>(rd()), instr_.instr());
2708       break;
2709     case LDPTR_D:
2710       printf_instr("LDPTR_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2711                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2712                    rj(), si14_se);
2713       set_register(rd_reg(), Read2W(rj() + si14_se, instr_.instr()));
2714       break;
2715     case STPTR_D:
2716       printf_instr("STPTR_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2717                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2718                    rj(), si14_se);
2719       Write2W(rj() + si14_se, rd(), instr_.instr());
2720       break;
2721     case LL_W: {
2722       printf_instr("LL_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2723                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2724                    rj(), si14_se);
2725       base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2726       addr = si14_se + rj();
2727       set_register(rd_reg(), ReadW(addr, instr_.instr()));
2728       local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
2729       GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
2730                                                     &global_monitor_thread_);
2731       break;
2732     }
2733     case SC_W: {
2734       printf_instr("SC_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2735                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2736                    rj(), si14_se);
2737       addr = si14_se + rj();
2738       WriteConditionalW(addr, static_cast<int32_t>(rd()), instr_.instr(),
2739                         rd_reg());
2740       break;
2741     }
2742     case LL_D: {
2743       printf_instr("LL_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2744                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2745                    rj(), si14_se);
2746       base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2747       addr = si14_se + rj();
2748       set_register(rd_reg(), Read2W(addr, instr_.instr()));
2749       local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord);
2750       GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
2751                                                     &global_monitor_thread_);
2752       break;
2753     }
2754     case SC_D: {
2755       printf_instr("SC_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2756                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2757                    rj(), si14_se);
2758       addr = si14_se + rj();
2759       WriteConditional2W(addr, rd(), instr_.instr(), rd_reg());
2760       break;
2761     }
2762     default:
2763       UNREACHABLE();
2764   }
2765 }
2766 
DecodeTypeOp10()2767 void Simulator::DecodeTypeOp10() {
2768   int64_t alu_out = 0x0;
2769   int64_t si12_se = (static_cast<int64_t>(si12()) << 52) >> 52;
2770   uint64_t si12_ze = (static_cast<uint64_t>(ui12()) << 52) >> 52;
2771 
2772   switch (instr_.Bits(31, 22) << 22) {
2773     case BSTR_W: {
2774       CHECK_EQ(instr_.Bit(21), 1);
2775       uint8_t lsbw_ = lsbw();
2776       uint8_t msbw_ = msbw();
2777       CHECK_LE(lsbw_, msbw_);
2778       uint8_t size = msbw_ - lsbw_ + 1;
2779       uint64_t mask = (1ULL << size) - 1;
2780       if (instr_.Bit(15) == 0) {
2781         // BSTRINS_W
2782         printf_instr(
2783             "BSTRINS_W\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2784             Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2785             msbw_, lsbw_);
2786         alu_out = static_cast<int32_t>((rd_u() & ~(mask << lsbw_)) |
2787                                        ((rj_u() & mask) << lsbw_));
2788       } else {
2789         // BSTRPICK_W
2790         printf_instr(
2791             "BSTRPICK_W\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2792             Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2793             msbw_, lsbw_);
2794         alu_out = static_cast<int32_t>((rj_u() & (mask << lsbw_)) >> lsbw_);
2795       }
2796       SetResult(rd_reg(), alu_out);
2797       break;
2798     }
2799     case BSTRINS_D: {
2800       uint8_t lsbd_ = lsbd();
2801       uint8_t msbd_ = msbd();
2802       CHECK_LE(lsbd_, msbd_);
2803       printf_instr(
2804           "BSTRINS_D\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2805           Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2806           msbd_, lsbd_);
2807       uint8_t size = msbd_ - lsbd_ + 1;
2808       if (size < 64) {
2809         uint64_t mask = (1ULL << size) - 1;
2810         alu_out = (rd_u() & ~(mask << lsbd_)) | ((rj_u() & mask) << lsbd_);
2811         SetResult(rd_reg(), alu_out);
2812       } else if (size == 64) {
2813         SetResult(rd_reg(), rj());
2814       }
2815       break;
2816     }
2817     case BSTRPICK_D: {
2818       uint8_t lsbd_ = lsbd();
2819       uint8_t msbd_ = msbd();
2820       CHECK_LE(lsbd_, msbd_);
2821       printf_instr(
2822           "BSTRPICK_D\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2823           Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2824           msbd_, lsbd_);
2825       uint8_t size = msbd_ - lsbd_ + 1;
2826       if (size < 64) {
2827         uint64_t mask = (1ULL << size) - 1;
2828         alu_out = (rj_u() & (mask << lsbd_)) >> lsbd_;
2829         SetResult(rd_reg(), alu_out);
2830       } else if (size == 64) {
2831         SetResult(rd_reg(), rj());
2832       }
2833       break;
2834     }
2835     case SLTI:
2836       printf_instr("SLTI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2837                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2838                    rj(), si12_se);
2839       SetResult(rd_reg(), rj() < si12_se ? 1 : 0);
2840       break;
2841     case SLTUI:
2842       printf_instr("SLTUI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2843                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2844                    rj(), si12_se);
2845       SetResult(rd_reg(), rj_u() < static_cast<uint64_t>(si12_se) ? 1 : 0);
2846       break;
2847     case ADDI_W: {
2848       printf_instr("ADDI_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2849                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2850                    rj(), si12_se);
2851       int32_t alu32_out =
2852           static_cast<int32_t>(rj()) + static_cast<int32_t>(si12_se);
2853       SetResult(rd_reg(), alu32_out);
2854       break;
2855     }
2856     case ADDI_D:
2857       printf_instr("ADDI_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2858                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2859                    rj(), si12_se);
2860       SetResult(rd_reg(), rj() + si12_se);
2861       break;
2862     case LU52I_D: {
2863       printf_instr("LU52I_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2864                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2865                    rj(), si12_se);
2866       int64_t si12_se = static_cast<int64_t>(si12()) << 52;
2867       uint64_t mask = (1ULL << 52) - 1;
2868       alu_out = si12_se + (rj() & mask);
2869       SetResult(rd_reg(), alu_out);
2870       break;
2871     }
2872     case ANDI:
2873       printf_instr("ANDI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2874                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2875                    rj(), si12_ze);
2876       SetResult(rd_reg(), rj() & si12_ze);
2877       break;
2878     case ORI:
2879       printf_instr("ORI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2880                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2881                    rj(), si12_ze);
2882       SetResult(rd_reg(), rj_u() | si12_ze);
2883       break;
2884     case XORI:
2885       printf_instr("XORI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2886                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2887                    rj(), si12_ze);
2888       SetResult(rd_reg(), rj_u() ^ si12_ze);
2889       break;
2890     case LD_B:
2891       printf_instr("LD_B\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2892                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2893                    rj(), si12_ze);
2894       set_register(rd_reg(), ReadB(rj() + si12_se));
2895       break;
2896     case LD_H:
2897       printf_instr("LD_H\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2898                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2899                    rj(), si12_ze);
2900       set_register(rd_reg(), ReadH(rj() + si12_se, instr_.instr()));
2901       break;
2902     case LD_W:
2903       printf_instr("LD_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2904                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2905                    rj(), si12_ze);
2906       set_register(rd_reg(), ReadW(rj() + si12_se, instr_.instr()));
2907       break;
2908     case LD_D:
2909       printf_instr("LD_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2910                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2911                    rj(), si12_ze);
2912       set_register(rd_reg(), Read2W(rj() + si12_se, instr_.instr()));
2913       break;
2914     case ST_B:
2915       printf_instr("ST_B\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2916                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2917                    rj(), si12_ze);
2918       WriteB(rj() + si12_se, static_cast<int8_t>(rd()));
2919       break;
2920     case ST_H:
2921       printf_instr("ST_H\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2922                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2923                    rj(), si12_ze);
2924       WriteH(rj() + si12_se, static_cast<int16_t>(rd()), instr_.instr());
2925       break;
2926     case ST_W:
2927       printf_instr("ST_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2928                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2929                    rj(), si12_ze);
2930       WriteW(rj() + si12_se, static_cast<int32_t>(rd()), instr_.instr());
2931       break;
2932     case ST_D:
2933       printf_instr("ST_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2934                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2935                    rj(), si12_ze);
2936       Write2W(rj() + si12_se, rd(), instr_.instr());
2937       break;
2938     case LD_BU:
2939       printf_instr("LD_BU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2940                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2941                    rj(), si12_ze);
2942       set_register(rd_reg(), ReadBU(rj() + si12_se));
2943       break;
2944     case LD_HU:
2945       printf_instr("LD_HU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2946                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2947                    rj(), si12_ze);
2948       set_register(rd_reg(), ReadHU(rj() + si12_se, instr_.instr()));
2949       break;
2950     case LD_WU:
2951       printf_instr("LD_WU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2952                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2953                    rj(), si12_ze);
2954       set_register(rd_reg(), ReadWU(rj() + si12_se, instr_.instr()));
2955       break;
2956     case FLD_S: {
2957       printf_instr("FLD_S\t %s: %016f, %s: %016lx, si12: %016lx\n",
2958                    FPURegisters::Name(fd_reg()), fd_float(),
2959                    Registers::Name(rj_reg()), rj(), si12_ze);
2960       set_fpu_register(fd_reg(), kFPUInvalidResult);  // Trash upper 32 bits.
2961       set_fpu_register_word(
2962           fd_reg(), ReadW(rj() + si12_se, instr_.instr(), FLOAT_DOUBLE));
2963       break;
2964     }
2965     case FST_S: {
2966       printf_instr("FST_S\t %s: %016f, %s: %016lx, si12: %016lx\n",
2967                    FPURegisters::Name(fd_reg()), fd_float(),
2968                    Registers::Name(rj_reg()), rj(), si12_ze);
2969       int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(fd_reg()));
2970       WriteW(rj() + si12_se, alu_out_32, instr_.instr());
2971       break;
2972     }
2973     case FLD_D: {
2974       printf_instr("FLD_D\t %s: %016f, %s: %016lx, si12: %016lx\n",
2975                    FPURegisters::Name(fd_reg()), fd_double(),
2976                    Registers::Name(rj_reg()), rj(), si12_ze);
2977       set_fpu_register_double(fd_reg(), ReadD(rj() + si12_se, instr_.instr()));
2978       TraceMemRd(rj() + si12_se, get_fpu_register(fd_reg()), DOUBLE);
2979       break;
2980     }
2981     case FST_D: {
2982       printf_instr("FST_D\t %s: %016f, %s: %016lx, si12: %016lx\n",
2983                    FPURegisters::Name(fd_reg()), fd_double(),
2984                    Registers::Name(rj_reg()), rj(), si12_ze);
2985       WriteD(rj() + si12_se, get_fpu_register_double(fd_reg()), instr_.instr());
2986       TraceMemWr(rj() + si12_se, get_fpu_register(fd_reg()), DWORD);
2987       break;
2988     }
2989     default:
2990       UNREACHABLE();
2991   }
2992 }
2993 
DecodeTypeOp12()2994 void Simulator::DecodeTypeOp12() {
2995   switch (instr_.Bits(31, 20) << 20) {
2996     case FMADD_S:
2997       printf_instr("FMADD_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
2998                    FPURegisters::Name(fd_reg()), fd_float(),
2999                    FPURegisters::Name(fk_reg()), fk_float(),
3000                    FPURegisters::Name(fa_reg()), fa_float(),
3001                    FPURegisters::Name(fj_reg()), fj_float());
3002       SetFPUFloatResult(fd_reg(), std::fma(fj_float(), fk_float(), fa_float()));
3003       break;
3004     case FMADD_D:
3005       printf_instr("FMADD_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3006                    FPURegisters::Name(fd_reg()), fd_double(),
3007                    FPURegisters::Name(fk_reg()), fk_double(),
3008                    FPURegisters::Name(fa_reg()), fa_double(),
3009                    FPURegisters::Name(fj_reg()), fj_double());
3010       SetFPUDoubleResult(fd_reg(),
3011                          std::fma(fj_double(), fk_double(), fa_double()));
3012       break;
3013     case FMSUB_S:
3014       printf_instr("FMSUB_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3015                    FPURegisters::Name(fd_reg()), fd_float(),
3016                    FPURegisters::Name(fk_reg()), fk_float(),
3017                    FPURegisters::Name(fa_reg()), fa_float(),
3018                    FPURegisters::Name(fj_reg()), fj_float());
3019       SetFPUFloatResult(fd_reg(),
3020                         std::fma(fj_float(), fk_float(), -fa_float()));
3021       break;
3022     case FMSUB_D:
3023       printf_instr("FMSUB_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3024                    FPURegisters::Name(fd_reg()), fd_double(),
3025                    FPURegisters::Name(fk_reg()), fk_double(),
3026                    FPURegisters::Name(fa_reg()), fa_double(),
3027                    FPURegisters::Name(fj_reg()), fj_double());
3028       SetFPUDoubleResult(fd_reg(),
3029                          std::fma(fj_double(), fk_double(), -fa_double()));
3030       break;
3031     case FNMADD_S:
3032       printf_instr("FNMADD_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3033                    FPURegisters::Name(fd_reg()), fd_float(),
3034                    FPURegisters::Name(fk_reg()), fk_float(),
3035                    FPURegisters::Name(fa_reg()), fa_float(),
3036                    FPURegisters::Name(fj_reg()), fj_float());
3037       SetFPUFloatResult(fd_reg(),
3038                         std::fma(-fj_float(), fk_float(), -fa_float()));
3039       break;
3040     case FNMADD_D:
3041       printf_instr("FNMADD_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3042                    FPURegisters::Name(fd_reg()), fd_double(),
3043                    FPURegisters::Name(fk_reg()), fk_double(),
3044                    FPURegisters::Name(fa_reg()), fa_double(),
3045                    FPURegisters::Name(fj_reg()), fj_double());
3046       SetFPUDoubleResult(fd_reg(),
3047                          std::fma(-fj_double(), fk_double(), -fa_double()));
3048       break;
3049     case FNMSUB_S:
3050       printf_instr("FNMSUB_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3051                    FPURegisters::Name(fd_reg()), fd_float(),
3052                    FPURegisters::Name(fk_reg()), fk_float(),
3053                    FPURegisters::Name(fa_reg()), fa_float(),
3054                    FPURegisters::Name(fj_reg()), fj_float());
3055       SetFPUFloatResult(fd_reg(),
3056                         std::fma(-fj_float(), fk_float(), fa_float()));
3057       break;
3058     case FNMSUB_D:
3059       printf_instr("FNMSUB_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3060                    FPURegisters::Name(fd_reg()), fd_double(),
3061                    FPURegisters::Name(fk_reg()), fk_double(),
3062                    FPURegisters::Name(fa_reg()), fa_double(),
3063                    FPURegisters::Name(fj_reg()), fj_double());
3064       SetFPUDoubleResult(fd_reg(),
3065                          std::fma(-fj_double(), fk_double(), fa_double()));
3066       break;
3067     case FCMP_COND_S: {
3068       CHECK_EQ(instr_.Bits(4, 3), 0);
3069       float fj = fj_float();
3070       float fk = fk_float();
3071       switch (cond()) {
3072         case CAF: {
3073           printf_instr("FCMP_CAF_S fcc%d\n", cd_reg());
3074           set_cf_register(cd_reg(), false);
3075           break;
3076         }
3077         case CUN: {
3078           printf_instr("FCMP_CUN_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3079                        FPURegisters::Name(fj_reg()), fj,
3080                        FPURegisters::Name(fk_reg()), fk);
3081           set_cf_register(cd_reg(), std::isnan(fj) || std::isnan(fk));
3082           break;
3083         }
3084         case CEQ: {
3085           printf_instr("FCMP_CEQ_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3086                        FPURegisters::Name(fj_reg()), fj,
3087                        FPURegisters::Name(fk_reg()), fk);
3088           set_cf_register(cd_reg(), fj == fk);
3089           break;
3090         }
3091         case CUEQ: {
3092           printf_instr("FCMP_CUEQ_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3093                        FPURegisters::Name(fj_reg()), fj,
3094                        FPURegisters::Name(fk_reg()), fk);
3095           set_cf_register(cd_reg(),
3096                           (fj == fk) || std::isnan(fj) || std::isnan(fk));
3097           break;
3098         }
3099         case CLT: {
3100           printf_instr("FCMP_CLT_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3101                        FPURegisters::Name(fj_reg()), fj,
3102                        FPURegisters::Name(fk_reg()), fk);
3103           set_cf_register(cd_reg(), fj < fk);
3104           break;
3105         }
3106         case CULT: {
3107           printf_instr("FCMP_CULT_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3108                        FPURegisters::Name(fj_reg()), fj,
3109                        FPURegisters::Name(fk_reg()), fk);
3110           set_cf_register(cd_reg(),
3111                           (fj < fk) || std::isnan(fj) || std::isnan(fk));
3112           break;
3113         }
3114         case CLE: {
3115           printf_instr("FCMP_CLE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3116                        FPURegisters::Name(fj_reg()), fj,
3117                        FPURegisters::Name(fk_reg()), fk);
3118           set_cf_register(cd_reg(), fj <= fk);
3119           break;
3120         }
3121         case CULE: {
3122           printf_instr("FCMP_CULE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3123                        FPURegisters::Name(fj_reg()), fj,
3124                        FPURegisters::Name(fk_reg()), fk);
3125           set_cf_register(cd_reg(),
3126                           (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3127           break;
3128         }
3129         case CNE: {
3130           printf_instr("FCMP_CNE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3131                        FPURegisters::Name(fj_reg()), fj,
3132                        FPURegisters::Name(fk_reg()), fk);
3133           set_cf_register(cd_reg(), (fj < fk) || (fj > fk));
3134           break;
3135         }
3136         case COR: {
3137           printf_instr("FCMP_COR_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3138                        FPURegisters::Name(fj_reg()), fj,
3139                        FPURegisters::Name(fk_reg()), fk);
3140           set_cf_register(cd_reg(), !std::isnan(fj) && !std::isnan(fk));
3141           break;
3142         }
3143         case CUNE: {
3144           printf_instr("FCMP_CUNE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3145                        FPURegisters::Name(fj_reg()), fj,
3146                        FPURegisters::Name(fk_reg()), fk);
3147           set_cf_register(cd_reg(),
3148                           (fj != fk) || std::isnan(fj) || std::isnan(fk));
3149           break;
3150         }
3151         case SAF:
3152         case SUN:
3153         case SEQ:
3154         case SUEQ:
3155         case SLT:
3156         case SULT:
3157         case SLE:
3158         case SULE:
3159         case SNE:
3160         case SOR:
3161         case SUNE:
3162           UNIMPLEMENTED();
3163         default:
3164           UNREACHABLE();
3165       }
3166       break;
3167     }
3168     case FCMP_COND_D: {
3169       CHECK_EQ(instr_.Bits(4, 3), 0);
3170       double fj = fj_double();
3171       double fk = fk_double();
3172       switch (cond()) {
3173         case CAF: {
3174           printf_instr("FCMP_CAF_D fcc%d\n", cd_reg());
3175           set_cf_register(cd_reg(), false);
3176           break;
3177         }
3178         case CUN: {
3179           printf_instr("FCMP_CUN_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3180                        FPURegisters::Name(fj_reg()), fj,
3181                        FPURegisters::Name(fk_reg()), fk);
3182           set_cf_register(cd_reg(), std::isnan(fj) || std::isnan(fk));
3183           break;
3184         }
3185         case CEQ: {
3186           printf_instr("FCMP_CEQ_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3187                        FPURegisters::Name(fj_reg()), fj,
3188                        FPURegisters::Name(fk_reg()), fk);
3189           set_cf_register(cd_reg(), fj == fk);
3190           break;
3191         }
3192         case CUEQ: {
3193           printf_instr("FCMP_CUEQ_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3194                        FPURegisters::Name(fj_reg()), fj,
3195                        FPURegisters::Name(fk_reg()), fk);
3196           set_cf_register(cd_reg(),
3197                           (fj == fk) || std::isnan(fj) || std::isnan(fk));
3198           break;
3199         }
3200         case CLT: {
3201           printf_instr("FCMP_CLT_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3202                        FPURegisters::Name(fj_reg()), fj,
3203                        FPURegisters::Name(fk_reg()), fk);
3204           set_cf_register(cd_reg(), fj < fk);
3205           break;
3206         }
3207         case CULT: {
3208           printf_instr("FCMP_CULT_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3209                        FPURegisters::Name(fj_reg()), fj,
3210                        FPURegisters::Name(fk_reg()), fk);
3211           set_cf_register(cd_reg(),
3212                           (fj < fk) || std::isnan(fj) || std::isnan(fk));
3213           break;
3214         }
3215         case CLE: {
3216           printf_instr("FCMP_CLE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3217                        FPURegisters::Name(fj_reg()), fj,
3218                        FPURegisters::Name(fk_reg()), fk);
3219           set_cf_register(cd_reg(), fj <= fk);
3220           break;
3221         }
3222         case CULE: {
3223           printf_instr("FCMP_CULE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3224                        FPURegisters::Name(fj_reg()), fj,
3225                        FPURegisters::Name(fk_reg()), fk);
3226           set_cf_register(cd_reg(),
3227                           (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3228           break;
3229         }
3230         case CNE: {
3231           printf_instr("FCMP_CNE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3232                        FPURegisters::Name(fj_reg()), fj,
3233                        FPURegisters::Name(fk_reg()), fk);
3234           set_cf_register(cd_reg(), (fj < fk) || (fj > fk));
3235           break;
3236         }
3237         case COR: {
3238           printf_instr("FCMP_COR_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3239                        FPURegisters::Name(fj_reg()), fj,
3240                        FPURegisters::Name(fk_reg()), fk);
3241           set_cf_register(cd_reg(), !std::isnan(fj) && !std::isnan(fk));
3242           break;
3243         }
3244         case CUNE: {
3245           printf_instr("FCMP_CUNE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3246                        FPURegisters::Name(fj_reg()), fj,
3247                        FPURegisters::Name(fk_reg()), fk);
3248           set_cf_register(cd_reg(),
3249                           (fj != fk) || std::isnan(fj) || std::isnan(fk));
3250           break;
3251         }
3252         case SAF:
3253         case SUN:
3254         case SEQ:
3255         case SUEQ:
3256         case SLT:
3257         case SULT:
3258         case SLE:
3259         case SULE:
3260         case SNE:
3261         case SOR:
3262         case SUNE:
3263           UNIMPLEMENTED();
3264         default:
3265           UNREACHABLE();
3266       }
3267       break;
3268     }
3269     case FSEL: {
3270       CHECK_EQ(instr_.Bits(19, 18), 0);
3271       printf_instr("FSEL fcc%d, %s: %016f, %s: %016f, %s: %016f\n", ca_reg(),
3272                    FPURegisters::Name(fd_reg()), fd_double(),
3273                    FPURegisters::Name(fj_reg()), fj_double(),
3274                    FPURegisters::Name(fk_reg()), fk_double());
3275       if (ca() == 0) {
3276         SetFPUDoubleResult(fd_reg(), fj_double());
3277       } else {
3278         SetFPUDoubleResult(fd_reg(), fk_double());
3279       }
3280       break;
3281     }
3282     default:
3283       UNREACHABLE();
3284   }
3285 }
3286 
DecodeTypeOp14()3287 void Simulator::DecodeTypeOp14() {
3288   int64_t alu_out = 0x0;
3289   int32_t alu32_out = 0x0;
3290 
3291   switch (instr_.Bits(31, 18) << 18) {
3292     case ALSL: {
3293       uint8_t sa = sa2() + 1;
3294       alu32_out =
3295           (static_cast<int32_t>(rj()) << sa) + static_cast<int32_t>(rk());
3296       if (instr_.Bit(17) == 0) {
3297         // ALSL_W
3298         printf_instr("ALSL_W\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3299                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3300                      rj(), Registers::Name(rk_reg()), rk(), sa2());
3301         SetResult(rd_reg(), alu32_out);
3302       } else {
3303         // ALSL_WU
3304         printf_instr("ALSL_WU\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3305                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3306                      rj(), Registers::Name(rk_reg()), rk(), sa2());
3307         SetResult(rd_reg(), static_cast<uint32_t>(alu32_out));
3308       }
3309       break;
3310     }
3311     case BYTEPICK_W: {
3312       CHECK_EQ(instr_.Bit(17), 0);
3313       printf_instr("BYTEPICK_W\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3314                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3315                    rj(), Registers::Name(rk_reg()), rk(), sa2());
3316       uint8_t sa = sa2() * 8;
3317       if (sa == 0) {
3318         alu32_out = static_cast<int32_t>(rk());
3319       } else {
3320         int32_t mask = (1 << 31) >> (sa - 1);
3321         int32_t rk_hi = (static_cast<int32_t>(rk()) & (~mask)) << sa;
3322         int32_t rj_lo = (static_cast<uint32_t>(rj()) & mask) >> (32 - sa);
3323         alu32_out = rk_hi | rj_lo;
3324       }
3325       SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3326       break;
3327     }
3328     case BYTEPICK_D: {
3329       printf_instr("BYTEPICK_D\t %s: %016lx, %s: %016lx, %s: %016lx, sa3: %d\n",
3330                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3331                    rj(), Registers::Name(rk_reg()), rk(), sa3());
3332       uint8_t sa = sa3() * 8;
3333       if (sa == 0) {
3334         alu_out = rk();
3335       } else {
3336         int64_t mask = (1LL << 63) >> (sa - 1);
3337         int64_t rk_hi = (rk() & (~mask)) << sa;
3338         int64_t rj_lo = static_cast<uint64_t>(rj() & mask) >> (64 - sa);
3339         alu_out = rk_hi | rj_lo;
3340       }
3341       SetResult(rd_reg(), alu_out);
3342       break;
3343     }
3344     case ALSL_D: {
3345       printf_instr("ALSL_D\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3346                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3347                    rj(), Registers::Name(rk_reg()), rk(), sa2());
3348       CHECK_EQ(instr_.Bit(17), 0);
3349       uint8_t sa = sa2() + 1;
3350       alu_out = (rj() << sa) + rk();
3351       SetResult(rd_reg(), alu_out);
3352       break;
3353     }
3354     case SLLI: {
3355       DCHECK_EQ(instr_.Bit(17), 0);
3356       if (instr_.Bits(17, 15) == 0b001) {
3357         // SLLI_W
3358         printf_instr("SLLI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3359                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3360                      rj(), ui5());
3361         alu32_out = static_cast<int32_t>(rj()) << ui5();
3362         SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3363       } else if ((instr_.Bits(17, 16) == 0b01)) {
3364         // SLLI_D
3365         printf_instr("SLLI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3366                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3367                      rj(), ui6());
3368         SetResult(rd_reg(), rj() << ui6());
3369       }
3370       break;
3371     }
3372     case SRLI: {
3373       DCHECK_EQ(instr_.Bit(17), 0);
3374       if (instr_.Bits(17, 15) == 0b001) {
3375         // SRLI_W
3376         printf_instr("SRLI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3377                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3378                      rj(), ui5());
3379         alu32_out = static_cast<uint32_t>(rj()) >> ui5();
3380         SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3381       } else if (instr_.Bits(17, 16) == 0b01) {
3382         // SRLI_D
3383         printf_instr("SRLI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3384                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3385                      rj(), ui6());
3386         SetResult(rd_reg(), rj_u() >> ui6());
3387       }
3388       break;
3389     }
3390     case SRAI: {
3391       DCHECK_EQ(instr_.Bit(17), 0);
3392       if (instr_.Bits(17, 15) == 0b001) {
3393         // SRAI_W
3394         printf_instr("SRAI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3395                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3396                      rj(), ui5());
3397         alu32_out = static_cast<int32_t>(rj()) >> ui5();
3398         SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3399       } else if (instr_.Bits(17, 16) == 0b01) {
3400         // SRAI_D
3401         printf_instr("SRAI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3402                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3403                      rj(), ui6());
3404         SetResult(rd_reg(), rj() >> ui6());
3405       }
3406       break;
3407     }
3408     case ROTRI: {
3409       DCHECK_EQ(instr_.Bit(17), 0);
3410       if (instr_.Bits(17, 15) == 0b001) {
3411         // ROTRI_W
3412         printf_instr("ROTRI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3413                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3414                      rj(), ui5());
3415         alu32_out = static_cast<int32_t>(
3416             base::bits::RotateRight32(static_cast<const uint32_t>(rj_u()),
3417                                       static_cast<const uint32_t>(ui5())));
3418         SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3419       } else if (instr_.Bits(17, 16) == 0b01) {
3420         // ROTRI_D
3421         printf_instr("ROTRI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3422                      Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3423                      rj(), ui6());
3424         alu_out =
3425             static_cast<int64_t>(base::bits::RotateRight64(rj_u(), ui6()));
3426         SetResult(rd_reg(), alu_out);
3427         printf_instr("ROTRI, %s, %s, %d\n", Registers::Name(rd_reg()),
3428                      Registers::Name(rj_reg()), ui6());
3429       }
3430       break;
3431     }
3432     default:
3433       UNREACHABLE();
3434   }
3435 }
3436 
DecodeTypeOp17()3437 void Simulator::DecodeTypeOp17() {
3438   int64_t alu_out;
3439 
3440   switch (instr_.Bits(31, 15) << 15) {
3441     case ADD_W: {
3442       printf_instr("ADD_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3443                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3444                    rj(), Registers::Name(rk_reg()), rk());
3445       int32_t alu32_out = static_cast<int32_t>(rj() + rk());
3446       // Sign-extend result of 32bit operation into 64bit register.
3447       SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3448       break;
3449     }
3450     case ADD_D:
3451       printf_instr("ADD_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3452                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3453                    rj(), Registers::Name(rk_reg()), rk());
3454       SetResult(rd_reg(), rj() + rk());
3455       break;
3456     case SUB_W: {
3457       printf_instr("SUB_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3458                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3459                    rj(), Registers::Name(rk_reg()), rk());
3460       int32_t alu32_out = static_cast<int32_t>(rj() - rk());
3461       // Sign-extend result of 32bit operation into 64bit register.
3462       SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3463       break;
3464     }
3465     case SUB_D:
3466       printf_instr("SUB_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3467                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3468                    rj(), Registers::Name(rk_reg()), rk());
3469       SetResult(rd_reg(), rj() - rk());
3470       break;
3471     case SLT:
3472       printf_instr("SLT\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3473                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3474                    rj(), Registers::Name(rk_reg()), rk());
3475       SetResult(rd_reg(), rj() < rk() ? 1 : 0);
3476       break;
3477     case SLTU:
3478       printf_instr("SLTU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3479                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3480                    rj(), Registers::Name(rk_reg()), rk());
3481       SetResult(rd_reg(), rj_u() < rk_u() ? 1 : 0);
3482       break;
3483     case MASKEQZ:
3484       printf_instr("MASKEQZ\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3485                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3486                    rj(), Registers::Name(rk_reg()), rk());
3487       SetResult(rd_reg(), rk() == 0 ? 0 : rj());
3488       break;
3489     case MASKNEZ:
3490       printf_instr("MASKNEZ\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3491                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3492                    rj(), Registers::Name(rk_reg()), rk());
3493       SetResult(rd_reg(), rk() != 0 ? 0 : rj());
3494       break;
3495     case NOR:
3496       printf_instr("NOR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3497                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3498                    rj(), Registers::Name(rk_reg()), rk());
3499       SetResult(rd_reg(), ~(rj() | rk()));
3500       break;
3501     case AND:
3502       printf_instr("AND\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3503                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3504                    rj(), Registers::Name(rk_reg()), rk());
3505       SetResult(rd_reg(), rj() & rk());
3506       break;
3507     case OR:
3508       printf_instr("OR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3509                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3510                    rj(), Registers::Name(rk_reg()), rk());
3511       SetResult(rd_reg(), rj() | rk());
3512       break;
3513     case XOR:
3514       printf_instr("XOR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3515                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3516                    rj(), Registers::Name(rk_reg()), rk());
3517       SetResult(rd_reg(), rj() ^ rk());
3518       break;
3519     case ORN:
3520       printf_instr("ORN\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3521                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3522                    rj(), Registers::Name(rk_reg()), rk());
3523       SetResult(rd_reg(), rj() | (~rk()));
3524       break;
3525     case ANDN:
3526       printf_instr("ANDN\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3527                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3528                    rj(), Registers::Name(rk_reg()), rk());
3529       SetResult(rd_reg(), rj() & (~rk()));
3530       break;
3531     case SLL_W:
3532       printf_instr("SLL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3533                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3534                    rj(), Registers::Name(rk_reg()), rk());
3535       SetResult(rd_reg(), (int32_t)rj() << (rk_u() % 32));
3536       break;
3537     case SRL_W: {
3538       printf_instr("SRL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3539                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3540                    rj(), Registers::Name(rk_reg()), rk());
3541       alu_out = static_cast<int32_t>((uint32_t)rj_u() >> (rk_u() % 32));
3542       SetResult(rd_reg(), alu_out);
3543       break;
3544     }
3545     case SRA_W:
3546       printf_instr("SRA_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3547                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3548                    rj(), Registers::Name(rk_reg()), rk());
3549       SetResult(rd_reg(), (int32_t)rj() >> (rk_u() % 32));
3550       break;
3551     case SLL_D:
3552       printf_instr("SLL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3553                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3554                    rj(), Registers::Name(rk_reg()), rk());
3555       SetResult(rd_reg(), rj() << (rk_u() % 64));
3556       break;
3557     case SRL_D: {
3558       printf_instr("SRL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3559                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3560                    rj(), Registers::Name(rk_reg()), rk());
3561       alu_out = static_cast<int64_t>(rj_u() >> (rk_u() % 64));
3562       SetResult(rd_reg(), alu_out);
3563       break;
3564     }
3565     case SRA_D:
3566       printf_instr("SRA_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3567                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3568                    rj(), Registers::Name(rk_reg()), rk());
3569       SetResult(rd_reg(), rj() >> (rk_u() % 64));
3570       break;
3571     case ROTR_W: {
3572       printf_instr("ROTR_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3573                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3574                    rj(), Registers::Name(rk_reg()), rk());
3575       alu_out = static_cast<int32_t>(
3576           base::bits::RotateRight32(static_cast<const uint32_t>(rj_u()),
3577                                     static_cast<const uint32_t>(rk_u() % 32)));
3578       SetResult(rd_reg(), alu_out);
3579       break;
3580     }
3581     case ROTR_D: {
3582       printf_instr("ROTR_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3583                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3584                    rj(), Registers::Name(rk_reg()), rk());
3585       alu_out = static_cast<int64_t>(
3586           base::bits::RotateRight64((rj_u()), (rk_u() % 64)));
3587       SetResult(rd_reg(), alu_out);
3588       break;
3589     }
3590     case MUL_W: {
3591       printf_instr("MUL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3592                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3593                    rj(), Registers::Name(rk_reg()), rk());
3594       alu_out = static_cast<int32_t>(rj()) * static_cast<int32_t>(rk());
3595       SetResult(rd_reg(), alu_out);
3596       break;
3597     }
3598     case MULH_W: {
3599       printf_instr("MULH_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3600                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3601                    rj(), Registers::Name(rk_reg()), rk());
3602       int32_t rj_lo = static_cast<int32_t>(rj());
3603       int32_t rk_lo = static_cast<int32_t>(rk());
3604       alu_out = static_cast<int64_t>(rj_lo) * static_cast<int64_t>(rk_lo);
3605       SetResult(rd_reg(), alu_out >> 32);
3606       break;
3607     }
3608     case MULH_WU: {
3609       printf_instr("MULH_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3610                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3611                    rj(), Registers::Name(rk_reg()), rk());
3612       uint32_t rj_lo = static_cast<uint32_t>(rj_u());
3613       uint32_t rk_lo = static_cast<uint32_t>(rk_u());
3614       alu_out = static_cast<uint64_t>(rj_lo) * static_cast<uint64_t>(rk_lo);
3615       SetResult(rd_reg(), alu_out >> 32);
3616       break;
3617     }
3618     case MUL_D:
3619       printf_instr("MUL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3620                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3621                    rj(), Registers::Name(rk_reg()), rk());
3622       SetResult(rd_reg(), rj() * rk());
3623       break;
3624     case MULH_D:
3625       printf_instr("MULH_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3626                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3627                    rj(), Registers::Name(rk_reg()), rk());
3628       SetResult(rd_reg(), MultiplyHighSigned(rj(), rk()));
3629       break;
3630     case MULH_DU:
3631       printf_instr("MULH_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3632                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3633                    rj(), Registers::Name(rk_reg()), rk());
3634       SetResult(rd_reg(), MultiplyHighUnsigned(rj_u(), rk_u()));
3635       break;
3636     case MULW_D_W: {
3637       printf_instr("MULW_D_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3638                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3639                    rj(), Registers::Name(rk_reg()), rk());
3640       int64_t rj_i32 = static_cast<int32_t>(rj());
3641       int64_t rk_i32 = static_cast<int32_t>(rk());
3642       SetResult(rd_reg(), rj_i32 * rk_i32);
3643       break;
3644     }
3645     case MULW_D_WU: {
3646       printf_instr("MULW_D_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3647                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3648                    rj(), Registers::Name(rk_reg()), rk());
3649       uint64_t rj_u32 = static_cast<uint32_t>(rj_u());
3650       uint64_t rk_u32 = static_cast<uint32_t>(rk_u());
3651       SetResult(rd_reg(), rj_u32 * rk_u32);
3652       break;
3653     }
3654     case DIV_W: {
3655       printf_instr("DIV_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3656                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3657                    rj(), Registers::Name(rk_reg()), rk());
3658       int32_t rj_i32 = static_cast<int32_t>(rj());
3659       int32_t rk_i32 = static_cast<int32_t>(rk());
3660       if (rj_i32 == INT_MIN && rk_i32 == -1) {
3661         SetResult(rd_reg(), INT_MIN);
3662       } else if (rk_i32 != 0) {
3663         SetResult(rd_reg(), rj_i32 / rk_i32);
3664       }
3665       break;
3666     }
3667     case MOD_W: {
3668       printf_instr("MOD_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3669                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3670                    rj(), Registers::Name(rk_reg()), rk());
3671       int32_t rj_i32 = static_cast<int32_t>(rj());
3672       int32_t rk_i32 = static_cast<int32_t>(rk());
3673       if (rj_i32 == INT_MIN && rk_i32 == -1) {
3674         SetResult(rd_reg(), 0);
3675       } else if (rk_i32 != 0) {
3676         SetResult(rd_reg(), rj_i32 % rk_i32);
3677       }
3678       break;
3679     }
3680     case DIV_WU: {
3681       printf_instr("DIV_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3682                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3683                    rj(), Registers::Name(rk_reg()), rk());
3684       uint32_t rj_u32 = static_cast<uint32_t>(rj());
3685       uint32_t rk_u32 = static_cast<uint32_t>(rk());
3686       if (rk_u32 != 0) {
3687         SetResult(rd_reg(), static_cast<int32_t>(rj_u32 / rk_u32));
3688       }
3689       break;
3690     }
3691     case MOD_WU: {
3692       printf_instr("MOD_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3693                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3694                    rj(), Registers::Name(rk_reg()), rk());
3695       uint32_t rj_u32 = static_cast<uint32_t>(rj());
3696       uint32_t rk_u32 = static_cast<uint32_t>(rk());
3697       if (rk_u32 != 0) {
3698         SetResult(rd_reg(), static_cast<int32_t>(rj_u32 % rk_u32));
3699       }
3700       break;
3701     }
3702     case DIV_D: {
3703       printf_instr("DIV_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3704                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3705                    rj(), Registers::Name(rk_reg()), rk());
3706       if (rj() == LONG_MIN && rk() == -1) {
3707         SetResult(rd_reg(), LONG_MIN);
3708       } else if (rk() != 0) {
3709         SetResult(rd_reg(), rj() / rk());
3710       }
3711       break;
3712     }
3713     case MOD_D: {
3714       printf_instr("MOD_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3715                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3716                    rj(), Registers::Name(rk_reg()), rk());
3717       if (rj() == LONG_MIN && rk() == -1) {
3718         SetResult(rd_reg(), 0);
3719       } else if (rk() != 0) {
3720         SetResult(rd_reg(), rj() % rk());
3721       }
3722       break;
3723     }
3724     case DIV_DU: {
3725       printf_instr("DIV_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3726                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3727                    rj(), Registers::Name(rk_reg()), rk());
3728       if (rk_u() != 0) {
3729         SetResult(rd_reg(), static_cast<int64_t>(rj_u() / rk_u()));
3730       }
3731       break;
3732     }
3733     case MOD_DU: {
3734       printf_instr("MOD_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3735                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3736                    rj(), Registers::Name(rk_reg()), rk());
3737       if (rk_u() != 0) {
3738         SetResult(rd_reg(), static_cast<int64_t>(rj_u() % rk_u()));
3739       }
3740       break;
3741     }
3742     case BREAK:
3743       printf_instr("BREAK\t code: %x\n", instr_.Bits(14, 0));
3744       SoftwareInterrupt();
3745       break;
3746     case FADD_S: {
3747       printf_instr("FADD_S\t %s: %016f, %s, %016f, %s, %016f\n",
3748                    FPURegisters::Name(fd_reg()), fd_float(),
3749                    FPURegisters::Name(fj_reg()), fj_float(),
3750                    FPURegisters::Name(fk_reg()), fk_float());
3751       SetFPUFloatResult(
3752           fd_reg(),
3753           FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
3754                                  fj_float(), fk_float()));
3755       break;
3756     }
3757     case FADD_D: {
3758       printf_instr("FADD_D\t %s: %016f, %s, %016f, %s, %016f\n",
3759                    FPURegisters::Name(fd_reg()), fd_double(),
3760                    FPURegisters::Name(fj_reg()), fj_double(),
3761                    FPURegisters::Name(fk_reg()), fk_double());
3762       SetFPUDoubleResult(fd_reg(),
3763                          FPUCanonalizeOperation(
3764                              [](double lhs, double rhs) { return lhs + rhs; },
3765                              fj_double(), fk_double()));
3766       break;
3767     }
3768     case FSUB_S: {
3769       printf_instr("FSUB_S\t %s: %016f, %s, %016f, %s, %016f\n",
3770                    FPURegisters::Name(fd_reg()), fd_float(),
3771                    FPURegisters::Name(fj_reg()), fj_float(),
3772                    FPURegisters::Name(fk_reg()), fk_float());
3773       SetFPUFloatResult(
3774           fd_reg(),
3775           FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
3776                                  fj_float(), fk_float()));
3777       break;
3778     }
3779     case FSUB_D: {
3780       printf_instr("FSUB_D\t %s: %016f, %s, %016f, %s, %016f\n",
3781                    FPURegisters::Name(fd_reg()), fd_double(),
3782                    FPURegisters::Name(fj_reg()), fj_double(),
3783                    FPURegisters::Name(fk_reg()), fk_double());
3784       SetFPUDoubleResult(fd_reg(),
3785                          FPUCanonalizeOperation(
3786                              [](double lhs, double rhs) { return lhs - rhs; },
3787                              fj_double(), fk_double()));
3788       break;
3789     }
3790     case FMUL_S: {
3791       printf_instr("FMUL_S\t %s: %016f, %s, %016f, %s, %016f\n",
3792                    FPURegisters::Name(fd_reg()), fd_float(),
3793                    FPURegisters::Name(fj_reg()), fj_float(),
3794                    FPURegisters::Name(fk_reg()), fk_float());
3795       SetFPUFloatResult(
3796           fd_reg(),
3797           FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
3798                                  fj_float(), fk_float()));
3799       break;
3800     }
3801     case FMUL_D: {
3802       printf_instr("FMUL_D\t %s: %016f, %s, %016f, %s, %016f\n",
3803                    FPURegisters::Name(fd_reg()), fd_double(),
3804                    FPURegisters::Name(fj_reg()), fj_double(),
3805                    FPURegisters::Name(fk_reg()), fk_double());
3806       SetFPUDoubleResult(fd_reg(),
3807                          FPUCanonalizeOperation(
3808                              [](double lhs, double rhs) { return lhs * rhs; },
3809                              fj_double(), fk_double()));
3810       break;
3811     }
3812     case FDIV_S: {
3813       printf_instr("FDIV_S\t %s: %016f, %s, %016f, %s, %016f\n",
3814                    FPURegisters::Name(fd_reg()), fd_float(),
3815                    FPURegisters::Name(fj_reg()), fj_float(),
3816                    FPURegisters::Name(fk_reg()), fk_float());
3817       SetFPUFloatResult(
3818           fd_reg(),
3819           FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
3820                                  fj_float(), fk_float()));
3821       break;
3822     }
3823     case FDIV_D: {
3824       printf_instr("FDIV_D\t %s: %016f, %s, %016f, %s, %016f\n",
3825                    FPURegisters::Name(fd_reg()), fd_double(),
3826                    FPURegisters::Name(fj_reg()), fj_double(),
3827                    FPURegisters::Name(fk_reg()), fk_double());
3828       SetFPUDoubleResult(fd_reg(),
3829                          FPUCanonalizeOperation(
3830                              [](double lhs, double rhs) { return lhs / rhs; },
3831                              fj_double(), fk_double()));
3832       break;
3833     }
3834     case FMAX_S:
3835       printf_instr("FMAX_S\t %s: %016f, %s, %016f, %s, %016f\n",
3836                    FPURegisters::Name(fd_reg()), fd_float(),
3837                    FPURegisters::Name(fj_reg()), fj_float(),
3838                    FPURegisters::Name(fk_reg()), fk_float());
3839       SetFPUFloatResult(fd_reg(), FPUMax(fk_float(), fj_float()));
3840       break;
3841     case FMAX_D:
3842       printf_instr("FMAX_D\t %s: %016f, %s, %016f, %s, %016f\n",
3843                    FPURegisters::Name(fd_reg()), fd_double(),
3844                    FPURegisters::Name(fj_reg()), fj_double(),
3845                    FPURegisters::Name(fk_reg()), fk_double());
3846       SetFPUDoubleResult(fd_reg(), FPUMax(fk_double(), fj_double()));
3847       break;
3848     case FMIN_S:
3849       printf_instr("FMIN_S\t %s: %016f, %s, %016f, %s, %016f\n",
3850                    FPURegisters::Name(fd_reg()), fd_float(),
3851                    FPURegisters::Name(fj_reg()), fj_float(),
3852                    FPURegisters::Name(fk_reg()), fk_float());
3853       SetFPUFloatResult(fd_reg(), FPUMin(fk_float(), fj_float()));
3854       break;
3855     case FMIN_D:
3856       printf_instr("FMIN_D\t %s: %016f, %s, %016f, %s, %016f\n",
3857                    FPURegisters::Name(fd_reg()), fd_double(),
3858                    FPURegisters::Name(fj_reg()), fj_double(),
3859                    FPURegisters::Name(fk_reg()), fk_double());
3860       SetFPUDoubleResult(fd_reg(), FPUMin(fk_double(), fj_double()));
3861       break;
3862     case FMAXA_S:
3863       printf_instr("FMAXA_S\t %s: %016f, %s, %016f, %s, %016f\n",
3864                    FPURegisters::Name(fd_reg()), fd_float(),
3865                    FPURegisters::Name(fj_reg()), fj_float(),
3866                    FPURegisters::Name(fk_reg()), fk_float());
3867       SetFPUFloatResult(fd_reg(), FPUMaxA(fk_float(), fj_float()));
3868       break;
3869     case FMAXA_D:
3870       printf_instr("FMAXA_D\t %s: %016f, %s, %016f, %s, %016f\n",
3871                    FPURegisters::Name(fd_reg()), fd_double(),
3872                    FPURegisters::Name(fj_reg()), fj_double(),
3873                    FPURegisters::Name(fk_reg()), fk_double());
3874       SetFPUDoubleResult(fd_reg(), FPUMaxA(fk_double(), fj_double()));
3875       break;
3876     case FMINA_S:
3877       printf_instr("FMINA_S\t %s: %016f, %s, %016f, %s, %016f\n",
3878                    FPURegisters::Name(fd_reg()), fd_float(),
3879                    FPURegisters::Name(fj_reg()), fj_float(),
3880                    FPURegisters::Name(fk_reg()), fk_float());
3881       SetFPUFloatResult(fd_reg(), FPUMinA(fk_float(), fj_float()));
3882       break;
3883     case FMINA_D:
3884       printf_instr("FMINA_D\t %s: %016f, %s, %016f, %s, %016f\n",
3885                    FPURegisters::Name(fd_reg()), fd_double(),
3886                    FPURegisters::Name(fj_reg()), fj_double(),
3887                    FPURegisters::Name(fk_reg()), fk_double());
3888       SetFPUDoubleResult(fd_reg(), FPUMinA(fk_double(), fj_double()));
3889       break;
3890     case LDX_B:
3891       printf_instr("LDX_B\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3892                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3893                    rj(), Registers::Name(rk_reg()), rk());
3894       set_register(rd_reg(), ReadB(rj() + rk()));
3895       break;
3896     case LDX_H:
3897       printf_instr("LDX_H\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3898                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3899                    rj(), Registers::Name(rk_reg()), rk());
3900       set_register(rd_reg(), ReadH(rj() + rk(), instr_.instr()));
3901       break;
3902     case LDX_W:
3903       printf_instr("LDX_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3904                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3905                    rj(), Registers::Name(rk_reg()), rk());
3906       set_register(rd_reg(), ReadW(rj() + rk(), instr_.instr()));
3907       break;
3908     case LDX_D:
3909       printf_instr("LDX_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3910                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3911                    rj(), Registers::Name(rk_reg()), rk());
3912       set_register(rd_reg(), Read2W(rj() + rk(), instr_.instr()));
3913       break;
3914     case STX_B:
3915       printf_instr("STX_B\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3916                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3917                    rj(), Registers::Name(rk_reg()), rk());
3918       WriteB(rj() + rk(), static_cast<int8_t>(rd()));
3919       break;
3920     case STX_H:
3921       printf_instr("STX_H\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3922                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3923                    rj(), Registers::Name(rk_reg()), rk());
3924       WriteH(rj() + rk(), static_cast<int16_t>(rd()), instr_.instr());
3925       break;
3926     case STX_W:
3927       printf_instr("STX_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3928                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3929                    rj(), Registers::Name(rk_reg()), rk());
3930       WriteW(rj() + rk(), static_cast<int32_t>(rd()), instr_.instr());
3931       break;
3932     case STX_D:
3933       printf_instr("STX_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3934                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3935                    rj(), Registers::Name(rk_reg()), rk());
3936       Write2W(rj() + rk(), rd(), instr_.instr());
3937       break;
3938     case LDX_BU:
3939       printf_instr("LDX_BU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3940                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3941                    rj(), Registers::Name(rk_reg()), rk());
3942       set_register(rd_reg(), ReadBU(rj() + rk()));
3943       break;
3944     case LDX_HU:
3945       printf_instr("LDX_HU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3946                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3947                    rj(), Registers::Name(rk_reg()), rk());
3948       set_register(rd_reg(), ReadHU(rj() + rk(), instr_.instr()));
3949       break;
3950     case LDX_WU:
3951       printf_instr("LDX_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3952                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3953                    rj(), Registers::Name(rk_reg()), rk());
3954       set_register(rd_reg(), ReadWU(rj() + rk(), instr_.instr()));
3955       break;
3956     case FLDX_S:
3957       printf_instr("FLDX_S\t %s: %016f, %s: %016lx, %s: %016lx\n",
3958                    FPURegisters::Name(fd_reg()), fd_float(),
3959                    Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
3960                    rk());
3961       set_fpu_register(fd_reg(), kFPUInvalidResult);  // Trash upper 32 bits.
3962       set_fpu_register_word(fd_reg(),
3963                             ReadW(rj() + rk(), instr_.instr(), FLOAT_DOUBLE));
3964       break;
3965     case FLDX_D:
3966       printf_instr("FLDX_D\t %s: %016f, %s: %016lx, %s: %016lx\n",
3967                    FPURegisters::Name(fd_reg()), fd_double(),
3968                    Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
3969                    rk());
3970       set_fpu_register_double(fd_reg(), ReadD(rj() + rk(), instr_.instr()));
3971       break;
3972     case FSTX_S:
3973       printf_instr("FSTX_S\t %s: %016f, %s: %016lx, %s: %016lx\n",
3974                    FPURegisters::Name(fd_reg()), fd_float(),
3975                    Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
3976                    rk());
3977       WriteW(rj() + rk(), static_cast<int32_t>(get_fpu_register(fd_reg())),
3978              instr_.instr());
3979       break;
3980     case FSTX_D:
3981       printf_instr("FSTX_D\t %s: %016f, %s: %016lx, %s: %016lx\n",
3982                    FPURegisters::Name(fd_reg()), fd_double(),
3983                    Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
3984                    rk());
3985       WriteD(rj() + rk(), get_fpu_register_double(fd_reg()), instr_.instr());
3986       break;
3987     case AMSWAP_W:
3988       printf("Sim UNIMPLEMENTED: AMSWAP_W\n");
3989       UNIMPLEMENTED();
3990     case AMSWAP_D:
3991       printf("Sim UNIMPLEMENTED: AMSWAP_D\n");
3992       UNIMPLEMENTED();
3993     case AMADD_W:
3994       printf("Sim UNIMPLEMENTED: AMADD_W\n");
3995       UNIMPLEMENTED();
3996     case AMADD_D:
3997       printf("Sim UNIMPLEMENTED: AMADD_D\n");
3998       UNIMPLEMENTED();
3999     case AMAND_W:
4000       printf("Sim UNIMPLEMENTED: AMAND_W\n");
4001       UNIMPLEMENTED();
4002     case AMAND_D:
4003       printf("Sim UNIMPLEMENTED: AMAND_D\n");
4004       UNIMPLEMENTED();
4005     case AMOR_W:
4006       printf("Sim UNIMPLEMENTED: AMOR_W\n");
4007       UNIMPLEMENTED();
4008     case AMOR_D:
4009       printf("Sim UNIMPLEMENTED: AMOR_D\n");
4010       UNIMPLEMENTED();
4011     case AMXOR_W:
4012       printf("Sim UNIMPLEMENTED: AMXOR_W\n");
4013       UNIMPLEMENTED();
4014     case AMXOR_D:
4015       printf("Sim UNIMPLEMENTED: AMXOR_D\n");
4016       UNIMPLEMENTED();
4017     case AMMAX_W:
4018       printf("Sim UNIMPLEMENTED: AMMAX_W\n");
4019       UNIMPLEMENTED();
4020     case AMMAX_D:
4021       printf("Sim UNIMPLEMENTED: AMMAX_D\n");
4022       UNIMPLEMENTED();
4023     case AMMIN_W:
4024       printf("Sim UNIMPLEMENTED: AMMIN_W\n");
4025       UNIMPLEMENTED();
4026     case AMMIN_D:
4027       printf("Sim UNIMPLEMENTED: AMMIN_D\n");
4028       UNIMPLEMENTED();
4029     case AMMAX_WU:
4030       printf("Sim UNIMPLEMENTED: AMMAX_WU\n");
4031       UNIMPLEMENTED();
4032     case AMMAX_DU:
4033       printf("Sim UNIMPLEMENTED: AMMAX_DU\n");
4034       UNIMPLEMENTED();
4035     case AMMIN_WU:
4036       printf("Sim UNIMPLEMENTED: AMMIN_WU\n");
4037       UNIMPLEMENTED();
4038     case AMMIN_DU:
4039       printf("Sim UNIMPLEMENTED: AMMIN_DU\n");
4040       UNIMPLEMENTED();
4041     case AMSWAP_DB_W: {
4042       printf_instr("AMSWAP_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4043                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4044                    rk(), Registers::Name(rj_reg()), rj());
4045       int32_t rdvalue;
4046       do {
4047         {
4048           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4049           set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4050           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4051           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4052               rj(), &global_monitor_thread_);
4053         }
4054         rdvalue = get_register(rd_reg());
4055         WriteConditionalW(rj(), static_cast<int32_t>(rk()), instr_.instr(),
4056                           rd_reg());
4057       } while (!get_register(rd_reg()));
4058       set_register(rd_reg(), rdvalue);
4059     } break;
4060     case AMSWAP_DB_D: {
4061       printf_instr("AMSWAP_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4062                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4063                    rk(), Registers::Name(rj_reg()), rj());
4064       int64_t rdvalue;
4065       do {
4066         {
4067           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4068           set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4069           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4070           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4071               rj(), &global_monitor_thread_);
4072         }
4073         rdvalue = get_register(rd_reg());
4074         WriteConditional2W(rj(), rk(), instr_.instr(), rd_reg());
4075       } while (!get_register(rd_reg()));
4076       set_register(rd_reg(), rdvalue);
4077     } break;
4078     case AMADD_DB_W: {
4079       printf_instr("AMADD_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4080                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4081                    rk(), Registers::Name(rj_reg()), rj());
4082       int32_t rdvalue;
4083       do {
4084         {
4085           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4086           set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4087           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4088           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4089               rj(), &global_monitor_thread_);
4090         }
4091         rdvalue = get_register(rd_reg());
4092         WriteConditionalW(rj(),
4093                           static_cast<int32_t>(static_cast<int32_t>(rk()) +
4094                                                static_cast<int32_t>(rd())),
4095                           instr_.instr(), rd_reg());
4096       } while (!get_register(rd_reg()));
4097       set_register(rd_reg(), rdvalue);
4098     } break;
4099     case AMADD_DB_D: {
4100       printf_instr("AMADD_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4101                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4102                    rk(), Registers::Name(rj_reg()), rj());
4103       int64_t rdvalue;
4104       do {
4105         {
4106           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4107           set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4108           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4109           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4110               rj(), &global_monitor_thread_);
4111         }
4112         rdvalue = get_register(rd_reg());
4113         WriteConditional2W(rj(), rk() + rd(), instr_.instr(), rd_reg());
4114       } while (!get_register(rd_reg()));
4115       set_register(rd_reg(), rdvalue);
4116     } break;
4117     case AMAND_DB_W: {
4118       printf_instr("AMAND_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4119                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4120                    rk(), Registers::Name(rj_reg()), rj());
4121       int32_t rdvalue;
4122       do {
4123         {
4124           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4125           set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4126           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4127           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4128               rj(), &global_monitor_thread_);
4129         }
4130         rdvalue = get_register(rd_reg());
4131         WriteConditionalW(rj(),
4132                           static_cast<int32_t>(static_cast<int32_t>(rk()) &
4133                                                static_cast<int32_t>(rd())),
4134                           instr_.instr(), rd_reg());
4135       } while (!get_register(rd_reg()));
4136       set_register(rd_reg(), rdvalue);
4137     } break;
4138     case AMAND_DB_D: {
4139       printf_instr("AMAND_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4140                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4141                    rk(), Registers::Name(rj_reg()), rj());
4142       int64_t rdvalue;
4143       do {
4144         {
4145           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4146           set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4147           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4148           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4149               rj(), &global_monitor_thread_);
4150         }
4151         rdvalue = get_register(rd_reg());
4152         WriteConditional2W(rj(), rk() & rd(), instr_.instr(), rd_reg());
4153       } while (!get_register(rd_reg()));
4154       set_register(rd_reg(), rdvalue);
4155     } break;
4156     case AMOR_DB_W: {
4157       printf_instr("AMOR_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4158                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4159                    rk(), Registers::Name(rj_reg()), rj());
4160       int32_t rdvalue;
4161       do {
4162         {
4163           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4164           set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4165           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4166           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4167               rj(), &global_monitor_thread_);
4168         }
4169         rdvalue = get_register(rd_reg());
4170         WriteConditionalW(rj(),
4171                           static_cast<int32_t>(static_cast<int32_t>(rk()) |
4172                                                static_cast<int32_t>(rd())),
4173                           instr_.instr(), rd_reg());
4174       } while (!get_register(rd_reg()));
4175       set_register(rd_reg(), rdvalue);
4176     } break;
4177     case AMOR_DB_D: {
4178       printf_instr("AMOR_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4179                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4180                    rk(), Registers::Name(rj_reg()), rj());
4181       int64_t rdvalue;
4182       do {
4183         {
4184           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4185           set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4186           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4187           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4188               rj(), &global_monitor_thread_);
4189         }
4190         rdvalue = get_register(rd_reg());
4191         WriteConditional2W(rj(), rk() | rd(), instr_.instr(), rd_reg());
4192       } while (!get_register(rd_reg()));
4193       set_register(rd_reg(), rdvalue);
4194     } break;
4195     case AMXOR_DB_W: {
4196       printf_instr("AMXOR_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4197                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4198                    rk(), Registers::Name(rj_reg()), rj());
4199       int32_t rdvalue;
4200       do {
4201         {
4202           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4203           set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4204           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4205           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4206               rj(), &global_monitor_thread_);
4207         }
4208         rdvalue = get_register(rd_reg());
4209         WriteConditionalW(rj(),
4210                           static_cast<int32_t>(static_cast<int32_t>(rk()) ^
4211                                                static_cast<int32_t>(rd())),
4212                           instr_.instr(), rd_reg());
4213       } while (!get_register(rd_reg()));
4214       set_register(rd_reg(), rdvalue);
4215     } break;
4216     case AMXOR_DB_D: {
4217       printf_instr("AMXOR_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4218                    Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4219                    rk(), Registers::Name(rj_reg()), rj());
4220       int64_t rdvalue;
4221       do {
4222         {
4223           base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4224           set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4225           local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4226           GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4227               rj(), &global_monitor_thread_);
4228         }
4229         rdvalue = get_register(rd_reg());
4230         WriteConditional2W(rj(), rk() ^ rd(), instr_.instr(), rd_reg());
4231       } while (!get_register(rd_reg()));
4232       set_register(rd_reg(), rdvalue);
4233     } break;
4234     case AMMAX_DB_W:
4235       printf("Sim UNIMPLEMENTED: AMMAX_DB_W\n");
4236       UNIMPLEMENTED();
4237     case AMMAX_DB_D:
4238       printf("Sim UNIMPLEMENTED: AMMAX_DB_D\n");
4239       UNIMPLEMENTED();
4240     case AMMIN_DB_W:
4241       printf("Sim UNIMPLEMENTED: AMMIN_DB_W\n");
4242       UNIMPLEMENTED();
4243     case AMMIN_DB_D:
4244       printf("Sim UNIMPLEMENTED: AMMIN_DB_D\n");
4245       UNIMPLEMENTED();
4246     case AMMAX_DB_WU:
4247       printf("Sim UNIMPLEMENTED: AMMAX_DB_WU\n");
4248       UNIMPLEMENTED();
4249     case AMMAX_DB_DU:
4250       printf("Sim UNIMPLEMENTED: AMMAX_DB_DU\n");
4251       UNIMPLEMENTED();
4252     case AMMIN_DB_WU:
4253       printf("Sim UNIMPLEMENTED: AMMIN_DB_WU\n");
4254       UNIMPLEMENTED();
4255     case AMMIN_DB_DU:
4256       printf("Sim UNIMPLEMENTED: AMMIN_DB_DU\n");
4257       UNIMPLEMENTED();
4258     case DBAR:
4259       printf_instr("DBAR\n");
4260       break;
4261     case IBAR:
4262       printf("Sim UNIMPLEMENTED: IBAR\n");
4263       UNIMPLEMENTED();
4264     case FSCALEB_S:
4265       printf("Sim UNIMPLEMENTED: FSCALEB_S\n");
4266       UNIMPLEMENTED();
4267     case FSCALEB_D:
4268       printf("Sim UNIMPLEMENTED: FSCALEB_D\n");
4269       UNIMPLEMENTED();
4270     case FCOPYSIGN_S: {
4271       printf_instr("FCOPYSIGN_S\t %s: %016f, %s, %016f, %s, %016f\n",
4272                    FPURegisters::Name(fd_reg()), fd_float(),
4273                    FPURegisters::Name(fj_reg()), fj_float(),
4274                    FPURegisters::Name(fk_reg()), fk_float());
4275       SetFPUFloatResult(fd_reg(), std::copysign(fj_float(), fk_float()));
4276     } break;
4277     case FCOPYSIGN_D: {
4278       printf_instr("FCOPYSIGN_d\t %s: %016f, %s, %016f, %s, %016f\n",
4279                    FPURegisters::Name(fd_reg()), fd_double(),
4280                    FPURegisters::Name(fj_reg()), fj_double(),
4281                    FPURegisters::Name(fk_reg()), fk_double());
4282       SetFPUDoubleResult(fd_reg(), std::copysign(fj_double(), fk_double()));
4283     } break;
4284     default:
4285       UNREACHABLE();
4286   }
4287 }
4288 
DecodeTypeOp22()4289 void Simulator::DecodeTypeOp22() {
4290   int64_t alu_out;
4291 
4292   switch (instr_.Bits(31, 10) << 10) {
4293     case CLZ_W: {
4294       printf_instr("CLZ_W\t %s: %016lx, %s, %016lx\n",
4295                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4296                    rj());
4297       alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rj_u()));
4298       SetResult(rd_reg(), alu_out);
4299       break;
4300     }
4301     case CTZ_W: {
4302       printf_instr("CTZ_W\t %s: %016lx, %s, %016lx\n",
4303                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4304                    rj());
4305       alu_out = base::bits::CountTrailingZeros32(static_cast<int32_t>(rj_u()));
4306       SetResult(rd_reg(), alu_out);
4307       break;
4308     }
4309     case CLZ_D: {
4310       printf_instr("CLZ_D\t %s: %016lx, %s, %016lx\n",
4311                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4312                    rj());
4313       alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rj_u()));
4314       SetResult(rd_reg(), alu_out);
4315       break;
4316     }
4317     case CTZ_D: {
4318       printf_instr("CTZ_D\t %s: %016lx, %s, %016lx\n",
4319                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4320                    rj());
4321       alu_out = base::bits::CountTrailingZeros64(static_cast<int64_t>(rj_u()));
4322       SetResult(rd_reg(), alu_out);
4323       break;
4324     }
4325     case REVB_2H: {
4326       printf_instr("REVB_2H\t %s: %016lx, %s, %016lx\n",
4327                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4328                    rj());
4329       uint32_t input = static_cast<uint32_t>(rj());
4330       uint64_t output = 0;
4331 
4332       uint32_t mask = 0xFF000000;
4333       for (int i = 0; i < 4; i++) {
4334         uint32_t tmp = mask & input;
4335         if (i % 2 == 0) {
4336           tmp = tmp >> 8;
4337         } else {
4338           tmp = tmp << 8;
4339         }
4340         output = output | tmp;
4341         mask = mask >> 8;
4342       }
4343 
4344       alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4345       SetResult(rd_reg(), alu_out);
4346       break;
4347     }
4348     case REVB_4H: {
4349       printf_instr("REVB_4H\t %s: %016lx, %s, %016lx\n",
4350                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4351                    rj());
4352       uint64_t input = rj_u();
4353       uint64_t output = 0;
4354 
4355       uint64_t mask = 0xFF00000000000000;
4356       for (int i = 0; i < 8; i++) {
4357         uint64_t tmp = mask & input;
4358         if (i % 2 == 0) {
4359           tmp = tmp >> 8;
4360         } else {
4361           tmp = tmp << 8;
4362         }
4363         output = output | tmp;
4364         mask = mask >> 8;
4365       }
4366 
4367       alu_out = static_cast<int64_t>(output);
4368       SetResult(rd_reg(), alu_out);
4369       break;
4370     }
4371     case REVB_2W: {
4372       printf_instr("REVB_2W\t %s: %016lx, %s, %016lx\n",
4373                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4374                    rj());
4375       uint64_t input = rj_u();
4376       uint64_t output = 0;
4377 
4378       uint64_t mask = 0xFF000000FF000000;
4379       for (int i = 0; i < 4; i++) {
4380         uint64_t tmp = mask & input;
4381         if (i <= 1) {
4382           tmp = tmp >> (24 - i * 16);
4383         } else {
4384           tmp = tmp << (i * 16 - 24);
4385         }
4386         output = output | tmp;
4387         mask = mask >> 8;
4388       }
4389 
4390       alu_out = static_cast<int64_t>(output);
4391       SetResult(rd_reg(), alu_out);
4392       break;
4393     }
4394     case REVB_D: {
4395       printf_instr("REVB_D\t %s: %016lx, %s, %016lx\n",
4396                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4397                    rj());
4398       uint64_t input = rj_u();
4399       uint64_t output = 0;
4400 
4401       uint64_t mask = 0xFF00000000000000;
4402       for (int i = 0; i < 8; i++) {
4403         uint64_t tmp = mask & input;
4404         if (i <= 3) {
4405           tmp = tmp >> (56 - i * 16);
4406         } else {
4407           tmp = tmp << (i * 16 - 56);
4408         }
4409         output = output | tmp;
4410         mask = mask >> 8;
4411       }
4412 
4413       alu_out = static_cast<int64_t>(output);
4414       SetResult(rd_reg(), alu_out);
4415       break;
4416     }
4417     case REVH_2W: {
4418       printf_instr("REVH_2W\t %s: %016lx, %s, %016lx\n",
4419                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4420                    rj());
4421       uint64_t input = rj_u();
4422       uint64_t output = 0;
4423 
4424       uint64_t mask = 0xFFFF000000000000;
4425       for (int i = 0; i < 4; i++) {
4426         uint64_t tmp = mask & input;
4427         if (i % 2 == 0) {
4428           tmp = tmp >> 16;
4429         } else {
4430           tmp = tmp << 16;
4431         }
4432         output = output | tmp;
4433         mask = mask >> 16;
4434       }
4435 
4436       alu_out = static_cast<int64_t>(output);
4437       SetResult(rd_reg(), alu_out);
4438       break;
4439     }
4440     case REVH_D: {
4441       printf_instr("REVH_D\t %s: %016lx, %s, %016lx\n",
4442                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4443                    rj());
4444       uint64_t input = rj_u();
4445       uint64_t output = 0;
4446 
4447       uint64_t mask = 0xFFFF000000000000;
4448       for (int i = 0; i < 4; i++) {
4449         uint64_t tmp = mask & input;
4450         if (i <= 1) {
4451           tmp = tmp >> (48 - i * 32);
4452         } else {
4453           tmp = tmp << (i * 32 - 48);
4454         }
4455         output = output | tmp;
4456         mask = mask >> 16;
4457       }
4458 
4459       alu_out = static_cast<int64_t>(output);
4460       SetResult(rd_reg(), alu_out);
4461       break;
4462     }
4463     case BITREV_4B: {
4464       printf_instr("BITREV_4B\t %s: %016lx, %s, %016lx\n",
4465                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4466                    rj());
4467       uint32_t input = static_cast<uint32_t>(rj());
4468       uint32_t output = 0;
4469       uint8_t i_byte, o_byte;
4470 
4471       // Reverse the bit in byte for each individual byte
4472       for (int i = 0; i < 4; i++) {
4473         output = output >> 8;
4474         i_byte = input & 0xFF;
4475 
4476         // Fast way to reverse bits in byte
4477         // Devised by Sean Anderson, July 13, 2001
4478         o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4479                                        (i_byte * 0x8020LU & 0x88440LU)) *
4480                                           0x10101LU >>
4481                                       16);
4482 
4483         output = output | (static_cast<uint32_t>(o_byte << 24));
4484         input = input >> 8;
4485       }
4486 
4487       alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4488       SetResult(rd_reg(), alu_out);
4489       break;
4490     }
4491     case BITREV_8B: {
4492       printf_instr("BITREV_8B\t %s: %016lx, %s, %016lx\n",
4493                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4494                    rj());
4495       uint64_t input = rj_u();
4496       uint64_t output = 0;
4497       uint8_t i_byte, o_byte;
4498 
4499       // Reverse the bit in byte for each individual byte
4500       for (int i = 0; i < 8; i++) {
4501         output = output >> 8;
4502         i_byte = input & 0xFF;
4503 
4504         // Fast way to reverse bits in byte
4505         // Devised by Sean Anderson, July 13, 2001
4506         o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4507                                        (i_byte * 0x8020LU & 0x88440LU)) *
4508                                           0x10101LU >>
4509                                       16);
4510 
4511         output = output | (static_cast<uint64_t>(o_byte) << 56);
4512         input = input >> 8;
4513       }
4514 
4515       alu_out = static_cast<int64_t>(output);
4516       SetResult(rd_reg(), alu_out);
4517       break;
4518     }
4519     case BITREV_W: {
4520       printf_instr("BITREV_W\t %s: %016lx, %s, %016lx\n",
4521                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4522                    rj());
4523       uint32_t input = static_cast<uint32_t>(rj());
4524       uint32_t output = 0;
4525       output = base::bits::ReverseBits(input);
4526       alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4527       SetResult(rd_reg(), alu_out);
4528       break;
4529     }
4530     case BITREV_D: {
4531       printf_instr("BITREV_D\t %s: %016lx, %s, %016lx\n",
4532                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4533                    rj());
4534       alu_out = static_cast<int64_t>(base::bits::ReverseBits(rj_u()));
4535       SetResult(rd_reg(), alu_out);
4536       break;
4537     }
4538     case EXT_W_B: {
4539       printf_instr("EXT_W_B\t %s: %016lx, %s, %016lx\n",
4540                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4541                    rj());
4542       uint8_t input = static_cast<uint8_t>(rj());
4543       alu_out = static_cast<int64_t>(static_cast<int8_t>(input));
4544       SetResult(rd_reg(), alu_out);
4545       break;
4546     }
4547     case EXT_W_H: {
4548       printf_instr("EXT_W_H\t %s: %016lx, %s, %016lx\n",
4549                    Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4550                    rj());
4551       uint16_t input = static_cast<uint16_t>(rj());
4552       alu_out = static_cast<int64_t>(static_cast<int16_t>(input));
4553       SetResult(rd_reg(), alu_out);
4554       break;
4555     }
4556     case FABS_S:
4557       printf_instr("FABS_S\t %s: %016f, %s, %016f\n",
4558                    FPURegisters::Name(fd_reg()), fd_float(),
4559                    FPURegisters::Name(fj_reg()), fj_float());
4560       SetFPUFloatResult(fd_reg(), std::abs(fj_float()));
4561       break;
4562     case FABS_D:
4563       printf_instr("FABS_D\t %s: %016f, %s, %016f\n",
4564                    FPURegisters::Name(fd_reg()), fd_double(),
4565                    FPURegisters::Name(fj_reg()), fj_double());
4566       SetFPUDoubleResult(fd_reg(), std::abs(fj_double()));
4567       break;
4568     case FNEG_S:
4569       printf_instr("FNEG_S\t %s: %016f, %s, %016f\n",
4570                    FPURegisters::Name(fd_reg()), fd_float(),
4571                    FPURegisters::Name(fj_reg()), fj_float());
4572       SetFPUFloatResult(fd_reg(), -fj_float());
4573       break;
4574     case FNEG_D:
4575       printf_instr("FNEG_D\t %s: %016f, %s, %016f\n",
4576                    FPURegisters::Name(fd_reg()), fd_double(),
4577                    FPURegisters::Name(fj_reg()), fj_double());
4578       SetFPUDoubleResult(fd_reg(), -fj_double());
4579       break;
4580     case FSQRT_S: {
4581       printf_instr("FSQRT_S\t %s: %016f, %s, %016f\n",
4582                    FPURegisters::Name(fd_reg()), fd_float(),
4583                    FPURegisters::Name(fj_reg()), fj_float());
4584       if (fj_float() >= 0) {
4585         SetFPUFloatResult(fd_reg(), std::sqrt(fj_float()));
4586         set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
4587       } else {
4588         SetFPUFloatResult(fd_reg(), std::sqrt(-1));  // qnan
4589         set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
4590       }
4591       break;
4592     }
4593     case FSQRT_D: {
4594       printf_instr("FSQRT_D\t %s: %016f, %s, %016f\n",
4595                    FPURegisters::Name(fd_reg()), fd_double(),
4596                    FPURegisters::Name(fj_reg()), fj_double());
4597       if (fj_double() >= 0) {
4598         SetFPUDoubleResult(fd_reg(), std::sqrt(fj_double()));
4599         set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
4600       } else {
4601         SetFPUDoubleResult(fd_reg(), std::sqrt(-1));  // qnan
4602         set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
4603       }
4604       break;
4605     }
4606     case FMOV_S:
4607       printf_instr("FMOV_S\t %s: %016f, %s, %016f\n",
4608                    FPURegisters::Name(fd_reg()), fd_float(),
4609                    FPURegisters::Name(fj_reg()), fj_float());
4610       SetFPUFloatResult(fd_reg(), fj_float());
4611       break;
4612     case FMOV_D:
4613       printf_instr("FMOV_D\t %s: %016f, %s, %016f\n",
4614                    FPURegisters::Name(fd_reg()), fd_float(),
4615                    FPURegisters::Name(fj_reg()), fj_float());
4616       SetFPUDoubleResult(fd_reg(), fj_double());
4617       break;
4618     case MOVGR2FR_W: {
4619       printf_instr("MOVGR2FR_W\t %s: %016f, %s, %016lx\n",
4620                    FPURegisters::Name(fd_reg()), fd_double(),
4621                    Registers::Name(rj_reg()), rj());
4622       set_fpu_register_word(fd_reg(), static_cast<int32_t>(rj()));
4623       TraceRegWr(get_fpu_register(fd_reg()), FLOAT_DOUBLE);
4624       break;
4625     }
4626     case MOVGR2FR_D:
4627       printf_instr("MOVGR2FR_D\t %s: %016f, %s, %016lx\n",
4628                    FPURegisters::Name(fd_reg()), fd_double(),
4629                    Registers::Name(rj_reg()), rj());
4630       SetFPUResult2(fd_reg(), rj());
4631       break;
4632     case MOVGR2FRH_W: {
4633       printf_instr("MOVGR2FRH_W\t %s: %016f, %s, %016lx\n",
4634                    FPURegisters::Name(fd_reg()), fd_double(),
4635                    Registers::Name(rj_reg()), rj());
4636       set_fpu_register_hi_word(fd_reg(), static_cast<int32_t>(rj()));
4637       TraceRegWr(get_fpu_register(fd_reg()), DOUBLE);
4638       break;
4639     }
4640     case MOVFR2GR_S: {
4641       printf_instr("MOVFR2GR_S\t %s: %016lx, %s, %016f\n",
4642                    Registers::Name(rd_reg()), rd(),
4643                    FPURegisters::Name(fj_reg()), fj_float());
4644       set_register(rd_reg(),
4645                    static_cast<int64_t>(get_fpu_register_word(fj_reg())));
4646       TraceRegWr(get_register(rd_reg()), WORD_DWORD);
4647       break;
4648     }
4649     case MOVFR2GR_D:
4650       printf_instr("MOVFR2GR_D\t %s: %016lx, %s, %016f\n",
4651                    Registers::Name(rd_reg()), rd(),
4652                    FPURegisters::Name(fj_reg()), fj_double());
4653       SetResult(rd_reg(), get_fpu_register(fj_reg()));
4654       break;
4655     case MOVFRH2GR_S:
4656       printf_instr("MOVFRH2GR_S\t %s: %016lx, %s, %016f\n",
4657                    Registers::Name(rd_reg()), rd(),
4658                    FPURegisters::Name(fj_reg()), fj_double());
4659       SetResult(rd_reg(), get_fpu_register_hi_word(fj_reg()));
4660       break;
4661     case MOVGR2FCSR: {
4662       printf_instr("MOVGR2FCSR\t fcsr: %016x, %s, %016lx\n", FCSR_,
4663                    Registers::Name(rj_reg()), rj());
4664       // fcsr could be 0-3
4665       CHECK_LT(rd_reg(), 4);
4666       FCSR_ = static_cast<uint32_t>(rj());
4667       TraceRegWr(FCSR_);
4668       break;
4669     }
4670     case MOVFCSR2GR: {
4671       printf_instr("MOVFCSR2GR\t %s, %016lx, FCSR: %016x\n",
4672                    Registers::Name(rd_reg()), rd(), FCSR_);
4673       // fcsr could be 0-3
4674       CHECK_LT(rj_reg(), 4);
4675       SetResult(rd_reg(), FCSR_);
4676       break;
4677     }
4678     case FCVT_S_D:
4679       printf_instr("FCVT_S_D\t %s: %016f, %s, %016f\n",
4680                    FPURegisters::Name(fd_reg()), fd_double(),
4681                    FPURegisters::Name(fj_reg()), fj_double());
4682       SetFPUFloatResult(fd_reg(), static_cast<float>(fj_double()));
4683       break;
4684     case FCVT_D_S:
4685       printf_instr("FCVT_D_S\t %s: %016f, %s, %016f\n",
4686                    FPURegisters::Name(fd_reg()), fd_double(),
4687                    FPURegisters::Name(fj_reg()), fj_float());
4688       SetFPUDoubleResult(fd_reg(), static_cast<double>(fj_float()));
4689       break;
4690     case FTINTRM_W_S: {
4691       printf_instr("FTINTRM_W_S\t %s: %016f, %s, %016f\n",
4692                    FPURegisters::Name(fd_reg()), fd_double(),
4693                    FPURegisters::Name(fj_reg()), fj_float());
4694       float fj = fj_float();
4695       float rounded = std::floor(fj);
4696       int32_t result = static_cast<int32_t>(rounded);
4697       SetFPUWordResult(fd_reg(), result);
4698       if (set_fcsr_round_error(fj, rounded)) {
4699         set_fpu_register_word_invalid_result(fj, rounded);
4700       }
4701       break;
4702     }
4703     case FTINTRM_W_D: {
4704       printf_instr("FTINTRM_W_D\t %s: %016f, %s, %016f\n",
4705                    FPURegisters::Name(fd_reg()), fd_double(),
4706                    FPURegisters::Name(fj_reg()), fj_double());
4707       double fj = fj_double();
4708       double rounded = std::floor(fj);
4709       int32_t result = static_cast<int32_t>(rounded);
4710       SetFPUWordResult(fd_reg(), result);
4711       if (set_fcsr_round_error(fj, rounded)) {
4712         set_fpu_register_invalid_result(fj, rounded);
4713       }
4714       break;
4715     }
4716     case FTINTRM_L_S: {
4717       printf_instr("FTINTRM_L_S\t %s: %016f, %s, %016f\n",
4718                    FPURegisters::Name(fd_reg()), fd_double(),
4719                    FPURegisters::Name(fj_reg()), fj_float());
4720       float fj = fj_float();
4721       float rounded = std::floor(fj);
4722       int64_t result = static_cast<int64_t>(rounded);
4723       SetFPUResult(fd_reg(), result);
4724       if (set_fcsr_round64_error(fj, rounded)) {
4725         set_fpu_register_invalid_result64(fj, rounded);
4726       }
4727       break;
4728     }
4729     case FTINTRM_L_D: {
4730       printf_instr("FTINTRM_L_D\t %s: %016f, %s, %016f\n",
4731                    FPURegisters::Name(fd_reg()), fd_double(),
4732                    FPURegisters::Name(fj_reg()), fj_double());
4733       double fj = fj_double();
4734       double rounded = std::floor(fj);
4735       int64_t result = static_cast<int64_t>(rounded);
4736       SetFPUResult(fd_reg(), result);
4737       if (set_fcsr_round64_error(fj, rounded)) {
4738         set_fpu_register_invalid_result64(fj, rounded);
4739       }
4740       break;
4741     }
4742     case FTINTRP_W_S: {
4743       printf_instr("FTINTRP_W_S\t %s: %016f, %s, %016f\n",
4744                    FPURegisters::Name(fd_reg()), fd_double(),
4745                    FPURegisters::Name(fj_reg()), fj_float());
4746       float fj = fj_float();
4747       float rounded = std::ceil(fj);
4748       int32_t result = static_cast<int32_t>(rounded);
4749       SetFPUWordResult(fd_reg(), result);
4750       if (set_fcsr_round_error(fj, rounded)) {
4751         set_fpu_register_word_invalid_result(fj, rounded);
4752       }
4753       break;
4754     }
4755     case FTINTRP_W_D: {
4756       printf_instr("FTINTRP_W_D\t %s: %016f, %s, %016f\n",
4757                    FPURegisters::Name(fd_reg()), fd_double(),
4758                    FPURegisters::Name(fj_reg()), fj_double());
4759       double fj = fj_double();
4760       double rounded = std::ceil(fj);
4761       int32_t result = static_cast<int32_t>(rounded);
4762       SetFPUWordResult(fd_reg(), result);
4763       if (set_fcsr_round_error(fj, rounded)) {
4764         set_fpu_register_invalid_result(fj, rounded);
4765       }
4766       break;
4767     }
4768     case FTINTRP_L_S: {
4769       printf_instr("FTINTRP_L_S\t %s: %016f, %s, %016f\n",
4770                    FPURegisters::Name(fd_reg()), fd_double(),
4771                    FPURegisters::Name(fj_reg()), fj_float());
4772       float fj = fj_float();
4773       float rounded = std::ceil(fj);
4774       int64_t result = static_cast<int64_t>(rounded);
4775       SetFPUResult(fd_reg(), result);
4776       if (set_fcsr_round64_error(fj, rounded)) {
4777         set_fpu_register_invalid_result64(fj, rounded);
4778       }
4779       break;
4780     }
4781     case FTINTRP_L_D: {
4782       printf_instr("FTINTRP_L_D\t %s: %016f, %s, %016f\n",
4783                    FPURegisters::Name(fd_reg()), fd_double(),
4784                    FPURegisters::Name(fj_reg()), fj_double());
4785       double fj = fj_double();
4786       double rounded = std::ceil(fj);
4787       int64_t result = static_cast<int64_t>(rounded);
4788       SetFPUResult(fd_reg(), result);
4789       if (set_fcsr_round64_error(fj, rounded)) {
4790         set_fpu_register_invalid_result64(fj, rounded);
4791       }
4792       break;
4793     }
4794     case FTINTRZ_W_S: {
4795       printf_instr("FTINTRZ_W_S\t %s: %016f, %s, %016f\n",
4796                    FPURegisters::Name(fd_reg()), fd_double(),
4797                    FPURegisters::Name(fj_reg()), fj_float());
4798       float fj = fj_float();
4799       float rounded = std::trunc(fj);
4800       int32_t result = static_cast<int32_t>(rounded);
4801       SetFPUWordResult(fd_reg(), result);
4802       if (set_fcsr_round_error(fj, rounded)) {
4803         set_fpu_register_word_invalid_result(fj, rounded);
4804       }
4805       break;
4806     }
4807     case FTINTRZ_W_D: {
4808       printf_instr("FTINTRZ_W_D\t %s: %016f, %s, %016f\n",
4809                    FPURegisters::Name(fd_reg()), fd_double(),
4810                    FPURegisters::Name(fj_reg()), fj_double());
4811       double fj = fj_double();
4812       double rounded = std::trunc(fj);
4813       int32_t result = static_cast<int32_t>(rounded);
4814       SetFPUWordResult(fd_reg(), result);
4815       if (set_fcsr_round_error(fj, rounded)) {
4816         set_fpu_register_invalid_result(fj, rounded);
4817       }
4818       break;
4819     }
4820     case FTINTRZ_L_S: {
4821       printf_instr("FTINTRZ_L_S\t %s: %016f, %s, %016f\n",
4822                    FPURegisters::Name(fd_reg()), fd_double(),
4823                    FPURegisters::Name(fj_reg()), fj_float());
4824       float fj = fj_float();
4825       float rounded = std::trunc(fj);
4826       int64_t result = static_cast<int64_t>(rounded);
4827       SetFPUResult(fd_reg(), result);
4828       if (set_fcsr_round64_error(fj, rounded)) {
4829         set_fpu_register_invalid_result64(fj, rounded);
4830       }
4831       break;
4832     }
4833     case FTINTRZ_L_D: {
4834       printf_instr("FTINTRZ_L_D\t %s: %016f, %s, %016f\n",
4835                    FPURegisters::Name(fd_reg()), fd_double(),
4836                    FPURegisters::Name(fj_reg()), fj_double());
4837       double fj = fj_double();
4838       double rounded = std::trunc(fj);
4839       int64_t result = static_cast<int64_t>(rounded);
4840       SetFPUResult(fd_reg(), result);
4841       if (set_fcsr_round64_error(fj, rounded)) {
4842         set_fpu_register_invalid_result64(fj, rounded);
4843       }
4844       break;
4845     }
4846     case FTINTRNE_W_S: {
4847       printf_instr("FTINTRNE_W_S\t %s: %016f, %s, %016f\n",
4848                    FPURegisters::Name(fd_reg()), fd_double(),
4849                    FPURegisters::Name(fj_reg()), fj_float());
4850       float fj = fj_float();
4851       float rounded = std::floor(fj + 0.5);
4852       int32_t result = static_cast<int32_t>(rounded);
4853       if ((result & 1) != 0 && result - fj == 0.5) {
4854         // If the number is halfway between two integers,
4855         // round to the even one.
4856         result--;
4857       }
4858       SetFPUWordResult(fd_reg(), result);
4859       if (set_fcsr_round_error(fj, rounded)) {
4860         set_fpu_register_word_invalid_result(fj, rounded);
4861       }
4862       break;
4863     }
4864     case FTINTRNE_W_D: {
4865       printf_instr("FTINTRNE_W_D\t %s: %016f, %s, %016f\n",
4866                    FPURegisters::Name(fd_reg()), fd_double(),
4867                    FPURegisters::Name(fj_reg()), fj_double());
4868       double fj = fj_double();
4869       double rounded = std::floor(fj + 0.5);
4870       int32_t result = static_cast<int32_t>(rounded);
4871       if ((result & 1) != 0 && result - fj == 0.5) {
4872         // If the number is halfway between two integers,
4873         // round to the even one.
4874         result--;
4875       }
4876       SetFPUWordResult(fd_reg(), result);
4877       if (set_fcsr_round_error(fj, rounded)) {
4878         set_fpu_register_invalid_result(fj, rounded);
4879       }
4880       break;
4881     }
4882     case FTINTRNE_L_S: {
4883       printf_instr("FTINTRNE_L_S\t %s: %016f, %s, %016f\n",
4884                    FPURegisters::Name(fd_reg()), fd_double(),
4885                    FPURegisters::Name(fj_reg()), fj_float());
4886       float fj = fj_float();
4887       float rounded = std::floor(fj + 0.5);
4888       int64_t result = static_cast<int64_t>(rounded);
4889       if ((result & 1) != 0 && result - fj == 0.5) {
4890         // If the number is halfway between two integers,
4891         // round to the even one.
4892         result--;
4893       }
4894       SetFPUResult(fd_reg(), result);
4895       if (set_fcsr_round64_error(fj, rounded)) {
4896         set_fpu_register_invalid_result64(fj, rounded);
4897       }
4898       break;
4899     }
4900     case FTINTRNE_L_D: {
4901       printf_instr("FTINTRNE_L_D\t %s: %016f, %s, %016f\n",
4902                    FPURegisters::Name(fd_reg()), fd_double(),
4903                    FPURegisters::Name(fj_reg()), fj_double());
4904       double fj = fj_double();
4905       double rounded = std::floor(fj + 0.5);
4906       int64_t result = static_cast<int64_t>(rounded);
4907       if ((result & 1) != 0 && result - fj == 0.5) {
4908         // If the number is halfway between two integers,
4909         // round to the even one.
4910         result--;
4911       }
4912       SetFPUResult(fd_reg(), result);
4913       if (set_fcsr_round64_error(fj, rounded)) {
4914         set_fpu_register_invalid_result64(fj, rounded);
4915       }
4916       break;
4917     }
4918     case FTINT_W_S: {
4919       printf_instr("FTINT_W_S\t %s: %016f, %s, %016f\n",
4920                    FPURegisters::Name(fd_reg()), fd_double(),
4921                    FPURegisters::Name(fj_reg()), fj_float());
4922       float fj = fj_float();
4923       float rounded;
4924       int32_t result;
4925       round_according_to_fcsr(fj, &rounded, &result);
4926       SetFPUWordResult(fd_reg(), result);
4927       if (set_fcsr_round_error(fj, rounded)) {
4928         set_fpu_register_word_invalid_result(fj, rounded);
4929       }
4930       break;
4931     }
4932     case FTINT_W_D: {
4933       printf_instr("FTINT_W_D\t %s: %016f, %s, %016f\n",
4934                    FPURegisters::Name(fd_reg()), fd_double(),
4935                    FPURegisters::Name(fj_reg()), fj_double());
4936       double fj = fj_double();
4937       double rounded;
4938       int32_t result;
4939       round_according_to_fcsr(fj, &rounded, &result);
4940       SetFPUWordResult(fd_reg(), result);
4941       if (set_fcsr_round_error(fj, rounded)) {
4942         set_fpu_register_word_invalid_result(fj, rounded);
4943       }
4944       break;
4945     }
4946     case FTINT_L_S: {
4947       printf_instr("FTINT_L_S\t %s: %016f, %s, %016f\n",
4948                    FPURegisters::Name(fd_reg()), fd_double(),
4949                    FPURegisters::Name(fj_reg()), fj_float());
4950       float fj = fj_float();
4951       float rounded;
4952       int64_t result;
4953       round64_according_to_fcsr(fj, &rounded, &result);
4954       SetFPUResult(fd_reg(), result);
4955       if (set_fcsr_round64_error(fj, rounded)) {
4956         set_fpu_register_invalid_result64(fj, rounded);
4957       }
4958       break;
4959     }
4960     case FTINT_L_D: {
4961       printf_instr("FTINT_L_D\t %s: %016f, %s, %016f\n",
4962                    FPURegisters::Name(fd_reg()), fd_double(),
4963                    FPURegisters::Name(fj_reg()), fj_double());
4964       double fj = fj_double();
4965       double rounded;
4966       int64_t result;
4967       round64_according_to_fcsr(fj, &rounded, &result);
4968       SetFPUResult(fd_reg(), result);
4969       if (set_fcsr_round64_error(fj, rounded)) {
4970         set_fpu_register_invalid_result64(fj, rounded);
4971       }
4972       break;
4973     }
4974     case FFINT_S_W: {
4975       alu_out = get_fpu_register_signed_word(fj_reg());
4976       printf_instr("FFINT_S_W\t %s: %016f, %s, %016x\n",
4977                    FPURegisters::Name(fd_reg()), fd_double(),
4978                    FPURegisters::Name(fj_reg()), static_cast<int>(alu_out));
4979       SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
4980       break;
4981     }
4982     case FFINT_S_L: {
4983       alu_out = get_fpu_register(fj_reg());
4984       printf_instr("FFINT_S_L\t %s: %016f, %s, %016lx\n",
4985                    FPURegisters::Name(fd_reg()), fd_double(),
4986                    FPURegisters::Name(fj_reg()), alu_out);
4987       SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
4988       break;
4989     }
4990     case FFINT_D_W: {
4991       alu_out = get_fpu_register_signed_word(fj_reg());
4992       printf_instr("FFINT_D_W\t %s: %016f, %s, %016x\n",
4993                    FPURegisters::Name(fd_reg()), fd_double(),
4994                    FPURegisters::Name(fj_reg()), static_cast<int>(alu_out));
4995       SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
4996       break;
4997     }
4998     case FFINT_D_L: {
4999       alu_out = get_fpu_register(fj_reg());
5000       printf_instr("FFINT_D_L\t %s: %016f, %s, %016lx\n",
5001                    FPURegisters::Name(fd_reg()), fd_double(),
5002                    FPURegisters::Name(fj_reg()), alu_out);
5003       SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
5004       break;
5005     }
5006     case FRINT_S: {
5007       printf_instr("FRINT_S\t %s: %016f, %s, %016f mode : ",
5008                    FPURegisters::Name(fd_reg()), fd_float(),
5009                    FPURegisters::Name(fj_reg()), fj_float());
5010       float fj = fj_float();
5011       float result, temp_result;
5012       double temp;
5013       float upper = std::ceil(fj);
5014       float lower = std::floor(fj);
5015       switch (get_fcsr_rounding_mode()) {
5016         case kRoundToNearest:
5017           printf_instr(" kRoundToNearest\n");
5018           if (upper - fj < fj - lower) {
5019             result = upper;
5020           } else if (upper - fj > fj - lower) {
5021             result = lower;
5022           } else {
5023             temp_result = upper / 2;
5024             float reminder = std::modf(temp_result, &temp);
5025             if (reminder == 0) {
5026               result = upper;
5027             } else {
5028               result = lower;
5029             }
5030           }
5031           break;
5032         case kRoundToZero:
5033           printf_instr(" kRoundToZero\n");
5034           result = (fj > 0 ? lower : upper);
5035           break;
5036         case kRoundToPlusInf:
5037           printf_instr(" kRoundToPlusInf\n");
5038           result = upper;
5039           break;
5040         case kRoundToMinusInf:
5041           printf_instr(" kRoundToMinusInf\n");
5042           result = lower;
5043           break;
5044       }
5045       SetFPUFloatResult(fd_reg(), result);
5046       set_fcsr_bit(kFCSRInexactCauseBit, result != fj);
5047       break;
5048     }
5049     case FRINT_D: {
5050       printf_instr("FRINT_D\t %s: %016f, %s, %016f mode : ",
5051                    FPURegisters::Name(fd_reg()), fd_double(),
5052                    FPURegisters::Name(fj_reg()), fj_double());
5053       double fj = fj_double();
5054       double result, temp, temp_result;
5055       double upper = std::ceil(fj);
5056       double lower = std::floor(fj);
5057       switch (get_fcsr_rounding_mode()) {
5058         case kRoundToNearest:
5059           printf_instr(" kRoundToNearest\n");
5060           if (upper - fj < fj - lower) {
5061             result = upper;
5062           } else if (upper - fj > fj - lower) {
5063             result = lower;
5064           } else {
5065             temp_result = upper / 2;
5066             double reminder = std::modf(temp_result, &temp);
5067             if (reminder == 0) {
5068               result = upper;
5069             } else {
5070               result = lower;
5071             }
5072           }
5073           break;
5074         case kRoundToZero:
5075           printf_instr(" kRoundToZero\n");
5076           result = (fj > 0 ? lower : upper);
5077           break;
5078         case kRoundToPlusInf:
5079           printf_instr(" kRoundToPlusInf\n");
5080           result = upper;
5081           break;
5082         case kRoundToMinusInf:
5083           printf_instr(" kRoundToMinusInf\n");
5084           result = lower;
5085           break;
5086       }
5087       SetFPUDoubleResult(fd_reg(), result);
5088       set_fcsr_bit(kFCSRInexactCauseBit, result != fj);
5089       break;
5090     }
5091     case MOVFR2CF:
5092       printf("Sim UNIMPLEMENTED: MOVFR2CF\n");
5093       UNIMPLEMENTED();
5094     case MOVCF2FR:
5095       printf("Sim UNIMPLEMENTED: MOVCF2FR\n");
5096       UNIMPLEMENTED();
5097     case MOVGR2CF:
5098       printf_instr("MOVGR2CF\t FCC%d, %s: %016lx\n", cd_reg(),
5099                    Registers::Name(rj_reg()), rj());
5100       set_cf_register(cd_reg(), rj() & 1);
5101       break;
5102     case MOVCF2GR:
5103       printf_instr("MOVCF2GR\t %s: %016lx, FCC%d\n", Registers::Name(rd_reg()),
5104                    rd(), cj_reg());
5105       SetResult(rd_reg(), cj());
5106       break;
5107     case FRECIP_S:
5108       printf("Sim UNIMPLEMENTED: FRECIP_S\n");
5109       UNIMPLEMENTED();
5110     case FRECIP_D:
5111       printf("Sim UNIMPLEMENTED: FRECIP_D\n");
5112       UNIMPLEMENTED();
5113     case FRSQRT_S:
5114       printf("Sim UNIMPLEMENTED: FRSQRT_S\n");
5115       UNIMPLEMENTED();
5116     case FRSQRT_D:
5117       printf("Sim UNIMPLEMENTED: FRSQRT_D\n");
5118       UNIMPLEMENTED();
5119     case FCLASS_S:
5120       printf("Sim UNIMPLEMENTED: FCLASS_S\n");
5121       UNIMPLEMENTED();
5122     case FCLASS_D:
5123       printf("Sim UNIMPLEMENTED: FCLASS_D\n");
5124       UNIMPLEMENTED();
5125     case FLOGB_S:
5126       printf("Sim UNIMPLEMENTED: FLOGB_S\n");
5127       UNIMPLEMENTED();
5128     case FLOGB_D:
5129       printf("Sim UNIMPLEMENTED: FLOGB_D\n");
5130       UNIMPLEMENTED();
5131     case CLO_W:
5132       printf("Sim UNIMPLEMENTED: CLO_W\n");
5133       UNIMPLEMENTED();
5134     case CTO_W:
5135       printf("Sim UNIMPLEMENTED: CTO_W\n");
5136       UNIMPLEMENTED();
5137     case CLO_D:
5138       printf("Sim UNIMPLEMENTED: CLO_D\n");
5139       UNIMPLEMENTED();
5140     case CTO_D:
5141       printf("Sim UNIMPLEMENTED: CTO_D\n");
5142       UNIMPLEMENTED();
5143     // Unimplemented opcodes raised an error in the configuration step before,
5144     // so we can use the default here to set the destination register in common
5145     // cases.
5146     default:
5147       UNREACHABLE();
5148   }
5149 }
5150 
5151 // Executes the current instruction.
InstructionDecode(Instruction * instr)5152 void Simulator::InstructionDecode(Instruction* instr) {
5153   if (v8::internal::FLAG_check_icache) {
5154     CheckICache(i_cache(), instr);
5155   }
5156   pc_modified_ = false;
5157 
5158   v8::base::EmbeddedVector<char, 256> buffer;
5159 
5160   if (::v8::internal::FLAG_trace_sim) {
5161     base::SNPrintF(trace_buf_, " ");
5162     disasm::NameConverter converter;
5163     disasm::Disassembler dasm(converter);
5164     // Use a reasonably large buffer.
5165     dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
5166   }
5167 
5168   static int instr_count = 0;
5169   USE(instr_count);
5170   instr_ = instr;
5171   printf_instr("\nInstr%3d: %08x, PC: %016lx\t", instr_count++,
5172                instr_.Bits(31, 0), get_pc());
5173   switch (instr_.InstructionType()) {
5174     case Instruction::kOp6Type:
5175       DecodeTypeOp6();
5176       break;
5177     case Instruction::kOp7Type:
5178       DecodeTypeOp7();
5179       break;
5180     case Instruction::kOp8Type:
5181       DecodeTypeOp8();
5182       break;
5183     case Instruction::kOp10Type:
5184       DecodeTypeOp10();
5185       break;
5186     case Instruction::kOp12Type:
5187       DecodeTypeOp12();
5188       break;
5189     case Instruction::kOp14Type:
5190       DecodeTypeOp14();
5191       break;
5192     case Instruction::kOp17Type:
5193       DecodeTypeOp17();
5194       break;
5195     case Instruction::kOp22Type:
5196       DecodeTypeOp22();
5197       break;
5198     default: {
5199       printf("instr_: %x\n", instr_.Bits(31, 0));
5200       UNREACHABLE();
5201     }
5202   }
5203 
5204   if (::v8::internal::FLAG_trace_sim) {
5205     PrintF("  0x%08" PRIxPTR "   %-44s   %s\n",
5206            reinterpret_cast<intptr_t>(instr), buffer.begin(),
5207            trace_buf_.begin());
5208   }
5209 
5210   if (!pc_modified_) {
5211     set_register(pc, reinterpret_cast<int64_t>(instr) + kInstrSize);
5212   }
5213 }
5214 
Execute()5215 void Simulator::Execute() {
5216   // Get the PC to simulate. Cannot use the accessor here as we need the
5217   // raw PC value and not the one used as input to arithmetic instructions.
5218   int64_t program_counter = get_pc();
5219   if (::v8::internal::FLAG_stop_sim_at == 0) {
5220     // Fast version of the dispatch loop without checking whether the simulator
5221     // should be stopping at a particular executed instruction.
5222     while (program_counter != end_sim_pc) {
5223       Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5224       icount_++;
5225       InstructionDecode(instr);
5226       program_counter = get_pc();
5227     }
5228   } else {
5229     // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
5230     // we reach the particular instruction count.
5231     while (program_counter != end_sim_pc) {
5232       Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5233       icount_++;
5234       if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) {
5235         Loong64Debugger dbg(this);
5236         dbg.Debug();
5237       } else {
5238         InstructionDecode(instr);
5239       }
5240       program_counter = get_pc();
5241     }
5242   }
5243 }
5244 
CallInternal(Address entry)5245 void Simulator::CallInternal(Address entry) {
5246   // Adjust JS-based stack limit to C-based stack limit.
5247   isolate_->stack_guard()->AdjustStackLimitForSimulator();
5248 
5249   // Prepare to execute the code at entry.
5250   set_register(pc, static_cast<int64_t>(entry));
5251   // Put down marker for end of simulation. The simulator will stop simulation
5252   // when the PC reaches this value. By saving the "end simulation" value into
5253   // the LR the simulation stops when returning to this call point.
5254   set_register(ra, end_sim_pc);
5255 
5256   // Remember the values of callee-saved registers.
5257   int64_t s0_val = get_register(s0);
5258   int64_t s1_val = get_register(s1);
5259   int64_t s2_val = get_register(s2);
5260   int64_t s3_val = get_register(s3);
5261   int64_t s4_val = get_register(s4);
5262   int64_t s5_val = get_register(s5);
5263   int64_t s6_val = get_register(s6);
5264   int64_t s7_val = get_register(s7);
5265   int64_t s8_val = get_register(s8);
5266   int64_t gp_val = get_register(gp);
5267   int64_t sp_val = get_register(sp);
5268   int64_t tp_val = get_register(tp);
5269   int64_t fp_val = get_register(fp);
5270 
5271   // Set up the callee-saved registers with a known value. To be able to check
5272   // that they are preserved properly across JS execution.
5273   int64_t callee_saved_value = icount_;
5274   set_register(s0, callee_saved_value);
5275   set_register(s1, callee_saved_value);
5276   set_register(s2, callee_saved_value);
5277   set_register(s3, callee_saved_value);
5278   set_register(s4, callee_saved_value);
5279   set_register(s5, callee_saved_value);
5280   set_register(s6, callee_saved_value);
5281   set_register(s7, callee_saved_value);
5282   set_register(s8, callee_saved_value);
5283   set_register(gp, callee_saved_value);
5284   set_register(tp, callee_saved_value);
5285   set_register(fp, callee_saved_value);
5286 
5287   // Start the simulation.
5288   Execute();
5289 
5290   // Check that the callee-saved registers have been preserved.
5291   CHECK_EQ(callee_saved_value, get_register(s0));
5292   CHECK_EQ(callee_saved_value, get_register(s1));
5293   CHECK_EQ(callee_saved_value, get_register(s2));
5294   CHECK_EQ(callee_saved_value, get_register(s3));
5295   CHECK_EQ(callee_saved_value, get_register(s4));
5296   CHECK_EQ(callee_saved_value, get_register(s5));
5297   CHECK_EQ(callee_saved_value, get_register(s6));
5298   CHECK_EQ(callee_saved_value, get_register(s7));
5299   CHECK_EQ(callee_saved_value, get_register(s8));
5300   CHECK_EQ(callee_saved_value, get_register(gp));
5301   CHECK_EQ(callee_saved_value, get_register(tp));
5302   CHECK_EQ(callee_saved_value, get_register(fp));
5303 
5304   // Restore callee-saved registers with the original value.
5305   set_register(s0, s0_val);
5306   set_register(s1, s1_val);
5307   set_register(s2, s2_val);
5308   set_register(s3, s3_val);
5309   set_register(s4, s4_val);
5310   set_register(s5, s5_val);
5311   set_register(s6, s6_val);
5312   set_register(s7, s7_val);
5313   set_register(s8, s8_val);
5314   set_register(gp, gp_val);
5315   set_register(sp, sp_val);
5316   set_register(tp, tp_val);
5317   set_register(fp, fp_val);
5318 }
5319 
CallImpl(Address entry,int argument_count,const intptr_t * arguments)5320 intptr_t Simulator::CallImpl(Address entry, int argument_count,
5321                              const intptr_t* arguments) {
5322   constexpr int kRegisterPassedArguments = 8;
5323   // Set up arguments.
5324 
5325   int reg_arg_count = std::min(kRegisterPassedArguments, argument_count);
5326   if (reg_arg_count > 0) set_register(a0, arguments[0]);
5327   if (reg_arg_count > 1) set_register(a1, arguments[1]);
5328   if (reg_arg_count > 2) set_register(a2, arguments[2]);
5329   if (reg_arg_count > 3) set_register(a3, arguments[3]);
5330   if (reg_arg_count > 4) set_register(a4, arguments[4]);
5331   if (reg_arg_count > 5) set_register(a5, arguments[5]);
5332   if (reg_arg_count > 6) set_register(a6, arguments[6]);
5333   if (reg_arg_count > 7) set_register(a7, arguments[7]);
5334 
5335   // Remaining arguments passed on stack.
5336   int64_t original_stack = get_register(sp);
5337   // Compute position of stack on entry to generated code.
5338   int stack_args_count = argument_count - reg_arg_count;
5339   int stack_args_size = stack_args_count * sizeof(*arguments);
5340   int64_t entry_stack = original_stack - stack_args_size;
5341 
5342   if (base::OS::ActivationFrameAlignment() != 0) {
5343     entry_stack &= -base::OS::ActivationFrameAlignment();
5344   }
5345   // Store remaining arguments on stack, from low to high memory.
5346   intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
5347   memcpy(stack_argument, arguments + reg_arg_count,
5348          stack_args_count * sizeof(*arguments));
5349   set_register(sp, entry_stack);
5350 
5351   CallInternal(entry);
5352 
5353   // Pop stack passed arguments.
5354   CHECK_EQ(entry_stack, get_register(sp));
5355   set_register(sp, original_stack);
5356 
5357   return get_register(a0);
5358 }
5359 
CallFP(Address entry,double d0,double d1)5360 double Simulator::CallFP(Address entry, double d0, double d1) {
5361   const FPURegister fparg2 = f1;
5362   set_fpu_register_double(f0, d0);
5363   set_fpu_register_double(fparg2, d1);
5364   CallInternal(entry);
5365   return get_fpu_register_double(f0);
5366 }
5367 
PushAddress(uintptr_t address)5368 uintptr_t Simulator::PushAddress(uintptr_t address) {
5369   int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
5370   uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
5371   *stack_slot = address;
5372   set_register(sp, new_sp);
5373   return new_sp;
5374 }
5375 
PopAddress()5376 uintptr_t Simulator::PopAddress() {
5377   int64_t current_sp = get_register(sp);
5378   uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
5379   uintptr_t address = *stack_slot;
5380   set_register(sp, current_sp + sizeof(uintptr_t));
5381   return address;
5382 }
5383 
LocalMonitor()5384 Simulator::LocalMonitor::LocalMonitor()
5385     : access_state_(MonitorAccess::Open),
5386       tagged_addr_(0),
5387       size_(TransactionSize::None) {}
5388 
Clear()5389 void Simulator::LocalMonitor::Clear() {
5390   access_state_ = MonitorAccess::Open;
5391   tagged_addr_ = 0;
5392   size_ = TransactionSize::None;
5393 }
5394 
NotifyLoad()5395 void Simulator::LocalMonitor::NotifyLoad() {
5396   if (access_state_ == MonitorAccess::RMW) {
5397     // A non linked load could clear the local monitor. As a result, it's
5398     // most strict to unconditionally clear the local monitor on load.
5399     Clear();
5400   }
5401 }
5402 
NotifyLoadLinked(uintptr_t addr,TransactionSize size)5403 void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
5404                                                TransactionSize size) {
5405   access_state_ = MonitorAccess::RMW;
5406   tagged_addr_ = addr;
5407   size_ = size;
5408 }
5409 
NotifyStore()5410 void Simulator::LocalMonitor::NotifyStore() {
5411   if (access_state_ == MonitorAccess::RMW) {
5412     // A non exclusive store could clear the local monitor. As a result, it's
5413     // most strict to unconditionally clear the local monitor on store.
5414     Clear();
5415   }
5416 }
5417 
NotifyStoreConditional(uintptr_t addr,TransactionSize size)5418 bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
5419                                                      TransactionSize size) {
5420   if (access_state_ == MonitorAccess::RMW) {
5421     if (addr == tagged_addr_ && size_ == size) {
5422       Clear();
5423       return true;
5424     } else {
5425       return false;
5426     }
5427   } else {
5428     DCHECK(access_state_ == MonitorAccess::Open);
5429     return false;
5430   }
5431 }
5432 
LinkedAddress()5433 Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
5434     : access_state_(MonitorAccess::Open),
5435       tagged_addr_(0),
5436       next_(nullptr),
5437       prev_(nullptr),
5438       failure_counter_(0) {}
5439 
Clear_Locked()5440 void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
5441   access_state_ = MonitorAccess::Open;
5442   tagged_addr_ = 0;
5443 }
5444 
NotifyLoadLinked_Locked(uintptr_t addr)5445 void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
5446     uintptr_t addr) {
5447   access_state_ = MonitorAccess::RMW;
5448   tagged_addr_ = addr;
5449 }
5450 
NotifyStore_Locked()5451 void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
5452   if (access_state_ == MonitorAccess::RMW) {
5453     // A non exclusive store could clear the global monitor. As a result, it's
5454     // most strict to unconditionally clear global monitors on store.
5455     Clear_Locked();
5456   }
5457 }
5458 
NotifyStoreConditional_Locked(uintptr_t addr,bool is_requesting_thread)5459 bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
5460     uintptr_t addr, bool is_requesting_thread) {
5461   if (access_state_ == MonitorAccess::RMW) {
5462     if (is_requesting_thread) {
5463       if (addr == tagged_addr_) {
5464         Clear_Locked();
5465         // Introduce occasional sc/scd failures. This is to simulate the
5466         // behavior of hardware, which can randomly fail due to background
5467         // cache evictions.
5468         if (failure_counter_++ >= kMaxFailureCounter) {
5469           failure_counter_ = 0;
5470           return false;
5471         } else {
5472           return true;
5473         }
5474       }
5475     } else if ((addr & kExclusiveTaggedAddrMask) ==
5476                (tagged_addr_ & kExclusiveTaggedAddrMask)) {
5477       // Check the masked addresses when responding to a successful lock by
5478       // another thread so the implementation is more conservative (i.e. the
5479       // granularity of locking is as large as possible.)
5480       Clear_Locked();
5481       return false;
5482     }
5483   }
5484   return false;
5485 }
5486 
NotifyLoadLinked_Locked(uintptr_t addr,LinkedAddress * linked_address)5487 void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
5488     uintptr_t addr, LinkedAddress* linked_address) {
5489   linked_address->NotifyLoadLinked_Locked(addr);
5490   PrependProcessor_Locked(linked_address);
5491 }
5492 
NotifyStore_Locked(LinkedAddress * linked_address)5493 void Simulator::GlobalMonitor::NotifyStore_Locked(
5494     LinkedAddress* linked_address) {
5495   // Notify each thread of the store operation.
5496   for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
5497     iter->NotifyStore_Locked();
5498   }
5499 }
5500 
NotifyStoreConditional_Locked(uintptr_t addr,LinkedAddress * linked_address)5501 bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
5502     uintptr_t addr, LinkedAddress* linked_address) {
5503   DCHECK(IsProcessorInLinkedList_Locked(linked_address));
5504   if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
5505     // Notify the other processors that this StoreConditional succeeded.
5506     for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
5507       if (iter != linked_address) {
5508         iter->NotifyStoreConditional_Locked(addr, false);
5509       }
5510     }
5511     return true;
5512   } else {
5513     return false;
5514   }
5515 }
5516 
IsProcessorInLinkedList_Locked(LinkedAddress * linked_address) const5517 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
5518     LinkedAddress* linked_address) const {
5519   return head_ == linked_address || linked_address->next_ ||
5520          linked_address->prev_;
5521 }
5522 
PrependProcessor_Locked(LinkedAddress * linked_address)5523 void Simulator::GlobalMonitor::PrependProcessor_Locked(
5524     LinkedAddress* linked_address) {
5525   if (IsProcessorInLinkedList_Locked(linked_address)) {
5526     return;
5527   }
5528 
5529   if (head_) {
5530     head_->prev_ = linked_address;
5531   }
5532   linked_address->prev_ = nullptr;
5533   linked_address->next_ = head_;
5534   head_ = linked_address;
5535 }
5536 
RemoveLinkedAddress(LinkedAddress * linked_address)5537 void Simulator::GlobalMonitor::RemoveLinkedAddress(
5538     LinkedAddress* linked_address) {
5539   base::MutexGuard lock_guard(&mutex);
5540   if (!IsProcessorInLinkedList_Locked(linked_address)) {
5541     return;
5542   }
5543 
5544   if (linked_address->prev_) {
5545     linked_address->prev_->next_ = linked_address->next_;
5546   } else {
5547     head_ = linked_address->next_;
5548   }
5549   if (linked_address->next_) {
5550     linked_address->next_->prev_ = linked_address->prev_;
5551   }
5552   linked_address->prev_ = nullptr;
5553   linked_address->next_ = nullptr;
5554 }
5555 
5556 #undef SScanF
5557 
5558 }  // namespace internal
5559 }  // namespace v8
5560 
5561 #endif  // USE_SIMULATOR
5562