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