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, ®isters_[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