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