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