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 "src/execution/mips64/simulator-mips64.h"
6
7 // Only build the simulator if not compiling for real MIPS hardware.
8 #if defined(USE_SIMULATOR)
9
10 #include <limits.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13
14 #include <cmath>
15
16 #include "src/base/bits.h"
17 #include "src/base/platform/platform.h"
18 #include "src/base/platform/wrappers.h"
19 #include "src/base/strings.h"
20 #include "src/base/vector.h"
21 #include "src/codegen/assembler-inl.h"
22 #include "src/codegen/macro-assembler.h"
23 #include "src/codegen/mips64/constants-mips64.h"
24 #include "src/diagnostics/disasm.h"
25 #include "src/heap/combined-heap.h"
26 #include "src/runtime/runtime-utils.h"
27 #include "src/utils/ostreams.h"
28
29 namespace v8 {
30 namespace internal {
31
DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,Simulator::GlobalMonitor::Get)32 DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
33 Simulator::GlobalMonitor::Get)
34
35 // Util functions.
36 inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); }
37
get_fcsr_condition_bit(uint32_t cc)38 uint32_t get_fcsr_condition_bit(uint32_t cc) {
39 if (cc == 0) {
40 return 23;
41 } else {
42 return 24 + cc;
43 }
44 }
45
MultiplyHighSigned(int64_t u,int64_t v)46 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
47 uint64_t u0, v0, w0;
48 int64_t u1, v1, w1, w2, t;
49
50 u0 = u & 0xFFFFFFFFL;
51 u1 = u >> 32;
52 v0 = v & 0xFFFFFFFFL;
53 v1 = v >> 32;
54
55 w0 = u0 * v0;
56 t = u1 * v0 + (w0 >> 32);
57 w1 = t & 0xFFFFFFFFL;
58 w2 = t >> 32;
59 w1 = u0 * v1 + w1;
60
61 return u1 * v1 + w2 + (w1 >> 32);
62 }
63
64 // This macro provides a platform independent use of sscanf. The reason for
65 // SScanF not being implemented in a platform independent was through
66 // ::v8::internal::OS in the same way as base::SNPrintF is that the Windows C
67 // Run-Time Library does not provide vsscanf.
68 #define SScanF sscanf
69
70 // The MipsDebugger class is used by the simulator while debugging simulated
71 // code.
72 class MipsDebugger {
73 public:
MipsDebugger(Simulator * sim)74 explicit MipsDebugger(Simulator* sim) : sim_(sim) {}
75
76 void Stop(Instruction* instr);
77 void Debug();
78 // Print all registers with a nice formatting.
79 void PrintAllRegs();
80 void PrintAllRegsIncludingFPU();
81
82 private:
83 // We set the breakpoint code to 0xFFFFF to easily recognize it.
84 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xFFFFF << 6;
85 static const Instr kNopInstr = 0x0;
86
87 Simulator* sim_;
88
89 int64_t GetRegisterValue(int regnum);
90 int64_t GetFPURegisterValue(int regnum);
91 float GetFPURegisterValueFloat(int regnum);
92 double GetFPURegisterValueDouble(int regnum);
93 bool GetValue(const char* desc, int64_t* value);
94
95 // Set or delete a breakpoint. Returns true if successful.
96 bool SetBreakpoint(Instruction* breakpc);
97 bool DeleteBreakpoint(Instruction* breakpc);
98
99 // Undo and redo all breakpoints. This is needed to bracket disassembly and
100 // execution to skip past breakpoints when run from the debugger.
101 void UndoBreakpoints();
102 void RedoBreakpoints();
103 };
104
UNSUPPORTED()105 inline void UNSUPPORTED() { printf("Sim: Unsupported instruction.\n"); }
106
Stop(Instruction * instr)107 void MipsDebugger::Stop(Instruction* instr) {
108 // Get the stop code.
109 uint32_t code = instr->Bits(25, 6);
110 PrintF("Simulator hit (%u)\n", code);
111 Debug();
112 }
113
GetRegisterValue(int regnum)114 int64_t MipsDebugger::GetRegisterValue(int regnum) {
115 if (regnum == kNumSimuRegisters) {
116 return sim_->get_pc();
117 } else {
118 return sim_->get_register(regnum);
119 }
120 }
121
GetFPURegisterValue(int regnum)122 int64_t MipsDebugger::GetFPURegisterValue(int regnum) {
123 if (regnum == kNumFPURegisters) {
124 return sim_->get_pc();
125 } else {
126 return sim_->get_fpu_register(regnum);
127 }
128 }
129
GetFPURegisterValueFloat(int regnum)130 float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
131 if (regnum == kNumFPURegisters) {
132 return sim_->get_pc();
133 } else {
134 return sim_->get_fpu_register_float(regnum);
135 }
136 }
137
GetFPURegisterValueDouble(int regnum)138 double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
139 if (regnum == kNumFPURegisters) {
140 return sim_->get_pc();
141 } else {
142 return sim_->get_fpu_register_double(regnum);
143 }
144 }
145
GetValue(const char * desc,int64_t * value)146 bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
147 int regnum = Registers::Number(desc);
148 int fpuregnum = FPURegisters::Number(desc);
149
150 if (regnum != kInvalidRegister) {
151 *value = GetRegisterValue(regnum);
152 return true;
153 } else if (fpuregnum != kInvalidFPURegister) {
154 *value = GetFPURegisterValue(fpuregnum);
155 return true;
156 } else if (strncmp(desc, "0x", 2) == 0) {
157 return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<uint64_t*>(value)) ==
158 1;
159 } else {
160 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
161 }
162 }
163
SetBreakpoint(Instruction * breakpc)164 bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
165 // Check if a breakpoint can be set. If not return without any side-effects.
166 if (sim_->break_pc_ != nullptr) {
167 return false;
168 }
169
170 // Set the breakpoint.
171 sim_->break_pc_ = breakpc;
172 sim_->break_instr_ = breakpc->InstructionBits();
173 // Not setting the breakpoint instruction in the code itself. It will be set
174 // when the debugger shell continues.
175 return true;
176 }
177
DeleteBreakpoint(Instruction * breakpc)178 bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
179 if (sim_->break_pc_ != nullptr) {
180 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
181 }
182
183 sim_->break_pc_ = nullptr;
184 sim_->break_instr_ = 0;
185 return true;
186 }
187
UndoBreakpoints()188 void MipsDebugger::UndoBreakpoints() {
189 if (sim_->break_pc_ != nullptr) {
190 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
191 }
192 }
193
RedoBreakpoints()194 void MipsDebugger::RedoBreakpoints() {
195 if (sim_->break_pc_ != nullptr) {
196 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
197 }
198 }
199
PrintAllRegs()200 void MipsDebugger::PrintAllRegs() {
201 #define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
202
203 PrintF("\n");
204 // at, v0, a0.
205 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64
206 "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n",
207 REG_INFO(1), REG_INFO(2), REG_INFO(4));
208 // v1, a1.
209 PrintF("%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
210 " %14" PRId64 " \n",
211 "", REG_INFO(3), REG_INFO(5));
212 // a2.
213 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
214 REG_INFO(6));
215 // a3.
216 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
217 REG_INFO(7));
218 PrintF("\n");
219 // a4-t3, s0-s7
220 for (int i = 0; i < 8; i++) {
221 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
222 " %14" PRId64 " \n",
223 REG_INFO(8 + i), REG_INFO(16 + i));
224 }
225 PrintF("\n");
226 // t8, k0, LO.
227 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
228 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
229 REG_INFO(24), REG_INFO(26), REG_INFO(32));
230 // t9, k1, HI.
231 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
232 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
233 REG_INFO(25), REG_INFO(27), REG_INFO(33));
234 // sp, fp, gp.
235 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
236 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
237 REG_INFO(29), REG_INFO(30), REG_INFO(28));
238 // pc.
239 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
240 " %14" PRId64 " \n",
241 REG_INFO(31), REG_INFO(34));
242
243 #undef REG_INFO
244 }
245
PrintAllRegsIncludingFPU()246 void MipsDebugger::PrintAllRegsIncludingFPU() {
247 #define FPU_REG_INFO(n) \
248 FPURegisters::Name(n), GetFPURegisterValue(n), GetFPURegisterValueDouble(n)
249
250 PrintAllRegs();
251
252 PrintF("\n\n");
253 // f0, f1, f2, ... f31.
254 // TODO(plind): consider printing 2 columns for space efficiency.
255 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(0));
256 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(1));
257 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(2));
258 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(3));
259 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(4));
260 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(5));
261 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(6));
262 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(7));
263 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(8));
264 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(9));
265 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(10));
266 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(11));
267 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(12));
268 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(13));
269 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(14));
270 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(15));
271 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(16));
272 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(17));
273 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(18));
274 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(19));
275 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(20));
276 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(21));
277 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(22));
278 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(23));
279 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(24));
280 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(25));
281 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(26));
282 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(27));
283 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(28));
284 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(29));
285 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(30));
286 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(31));
287
288 #undef FPU_REG_INFO
289 }
290
Debug()291 void MipsDebugger::Debug() {
292 intptr_t last_pc = -1;
293 bool done = false;
294
295 #define COMMAND_SIZE 63
296 #define ARG_SIZE 255
297
298 #define STR(a) #a
299 #define XSTR(a) STR(a)
300
301 char cmd[COMMAND_SIZE + 1];
302 char arg1[ARG_SIZE + 1];
303 char arg2[ARG_SIZE + 1];
304 char* argv[3] = {cmd, arg1, arg2};
305
306 // Make sure to have a proper terminating character if reaching the limit.
307 cmd[COMMAND_SIZE] = 0;
308 arg1[ARG_SIZE] = 0;
309 arg2[ARG_SIZE] = 0;
310
311 // Undo all set breakpoints while running in the debugger shell. This will
312 // make them invisible to all commands.
313 UndoBreakpoints();
314
315 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
316 if (last_pc != sim_->get_pc()) {
317 disasm::NameConverter converter;
318 disasm::Disassembler dasm(converter);
319 // Use a reasonably large buffer.
320 v8::base::EmbeddedVector<char, 256> buffer;
321 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
322 PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.begin());
323 last_pc = sim_->get_pc();
324 }
325 char* line = ReadLine("sim> ");
326 if (line == nullptr) {
327 break;
328 } else {
329 char* last_input = sim_->last_debugger_input();
330 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
331 line = last_input;
332 } else {
333 // Ownership is transferred to sim_;
334 sim_->set_last_debugger_input(line);
335 }
336 // Use sscanf to parse the individual parts of the command line. At the
337 // moment no command expects more than two parameters.
338 int argc = SScanF(line,
339 "%" XSTR(COMMAND_SIZE) "s "
340 "%" XSTR(ARG_SIZE) "s "
341 "%" XSTR(ARG_SIZE) "s",
342 cmd, arg1, arg2);
343 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
344 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
345 if (!(instr->IsTrap()) ||
346 instr->InstructionBits() == rtCallRedirInstr) {
347 sim_->InstructionDecode(
348 reinterpret_cast<Instruction*>(sim_->get_pc()));
349 } else {
350 // Allow si to jump over generated breakpoints.
351 PrintF("/!\\ Jumping over generated breakpoint.\n");
352 sim_->set_pc(sim_->get_pc() + kInstrSize);
353 }
354 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
355 // Execute the one instruction we broke at with breakpoints disabled.
356 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
357 // Leave the debugger shell.
358 done = true;
359 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
360 if (argc == 2) {
361 int64_t value;
362 double dvalue;
363 if (strcmp(arg1, "all") == 0) {
364 PrintAllRegs();
365 } else if (strcmp(arg1, "allf") == 0) {
366 PrintAllRegsIncludingFPU();
367 } else {
368 int regnum = Registers::Number(arg1);
369 int fpuregnum = FPURegisters::Number(arg1);
370
371 if (regnum != kInvalidRegister) {
372 value = GetRegisterValue(regnum);
373 PrintF("%s: 0x%08" PRIx64 " %" PRId64 " \n", arg1, value,
374 value);
375 } else if (fpuregnum != kInvalidFPURegister) {
376 value = GetFPURegisterValue(fpuregnum);
377 dvalue = GetFPURegisterValueDouble(fpuregnum);
378 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n",
379 FPURegisters::Name(fpuregnum), value, dvalue);
380 } else {
381 PrintF("%s unrecognized\n", arg1);
382 }
383 }
384 } else {
385 if (argc == 3) {
386 if (strcmp(arg2, "single") == 0) {
387 int64_t value;
388 float fvalue;
389 int fpuregnum = FPURegisters::Number(arg1);
390
391 if (fpuregnum != kInvalidFPURegister) {
392 value = GetFPURegisterValue(fpuregnum);
393 value &= 0xFFFFFFFFUL;
394 fvalue = GetFPURegisterValueFloat(fpuregnum);
395 PrintF("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue);
396 } else {
397 PrintF("%s unrecognized\n", arg1);
398 }
399 } else {
400 PrintF("print <fpu register> single\n");
401 }
402 } else {
403 PrintF("print <register> or print <fpu register> single\n");
404 }
405 }
406 } else if ((strcmp(cmd, "po") == 0) ||
407 (strcmp(cmd, "printobject") == 0)) {
408 if (argc == 2) {
409 int64_t value;
410 StdoutStream os;
411 if (GetValue(arg1, &value)) {
412 Object obj(value);
413 os << arg1 << ": \n";
414 #ifdef DEBUG
415 obj.Print(os);
416 os << "\n";
417 #else
418 os << Brief(obj) << "\n";
419 #endif
420 } else {
421 os << arg1 << " unrecognized\n";
422 }
423 } else {
424 PrintF("printobject <value>\n");
425 }
426 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
427 strcmp(cmd, "dump") == 0) {
428 int64_t* cur = nullptr;
429 int64_t* end = nullptr;
430 int next_arg = 1;
431
432 if (strcmp(cmd, "stack") == 0) {
433 cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
434 } else { // Command "mem".
435 int64_t value;
436 if (!GetValue(arg1, &value)) {
437 PrintF("%s unrecognized\n", arg1);
438 continue;
439 }
440 cur = reinterpret_cast<int64_t*>(value);
441 next_arg++;
442 }
443
444 int64_t words;
445 if (argc == next_arg) {
446 words = 10;
447 } else {
448 if (!GetValue(argv[next_arg], &words)) {
449 words = 10;
450 }
451 }
452 end = cur + words;
453
454 bool skip_obj_print = (strcmp(cmd, "dump") == 0);
455 while (cur < end) {
456 PrintF(" 0x%012" PRIxPTR " : 0x%016" PRIx64 " %14" PRId64 " ",
457 reinterpret_cast<intptr_t>(cur), *cur, *cur);
458 Object obj(*cur);
459 Heap* current_heap = sim_->isolate_->heap();
460 if (!skip_obj_print) {
461 if (obj.IsSmi() ||
462 IsValidHeapObject(current_heap, HeapObject::cast(obj))) {
463 PrintF(" (");
464 if (obj.IsSmi()) {
465 PrintF("smi %d", Smi::ToInt(obj));
466 } else {
467 obj.ShortPrint();
468 }
469 PrintF(")");
470 }
471 }
472 PrintF("\n");
473 cur++;
474 }
475
476 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
477 (strcmp(cmd, "di") == 0)) {
478 disasm::NameConverter converter;
479 disasm::Disassembler dasm(converter);
480 // Use a reasonably large buffer.
481 v8::base::EmbeddedVector<char, 256> buffer;
482
483 byte* cur = nullptr;
484 byte* end = nullptr;
485
486 if (argc == 1) {
487 cur = reinterpret_cast<byte*>(sim_->get_pc());
488 end = cur + (10 * kInstrSize);
489 } else if (argc == 2) {
490 int regnum = Registers::Number(arg1);
491 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
492 // The argument is an address or a register name.
493 int64_t value;
494 if (GetValue(arg1, &value)) {
495 cur = reinterpret_cast<byte*>(value);
496 // Disassemble 10 instructions at <arg1>.
497 end = cur + (10 * kInstrSize);
498 }
499 } else {
500 // The argument is the number of instructions.
501 int64_t value;
502 if (GetValue(arg1, &value)) {
503 cur = reinterpret_cast<byte*>(sim_->get_pc());
504 // Disassemble <arg1> instructions.
505 end = cur + (value * kInstrSize);
506 }
507 }
508 } else {
509 int64_t value1;
510 int64_t value2;
511 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
512 cur = reinterpret_cast<byte*>(value1);
513 end = cur + (value2 * kInstrSize);
514 }
515 }
516
517 while (cur < end) {
518 dasm.InstructionDecode(buffer, cur);
519 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
520 buffer.begin());
521 cur += kInstrSize;
522 }
523 } else if (strcmp(cmd, "gdb") == 0) {
524 PrintF("relinquishing control to gdb\n");
525 v8::base::OS::DebugBreak();
526 PrintF("regaining control from gdb\n");
527 } else if (strcmp(cmd, "break") == 0) {
528 if (argc == 2) {
529 int64_t value;
530 if (GetValue(arg1, &value)) {
531 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
532 PrintF("setting breakpoint failed\n");
533 }
534 } else {
535 PrintF("%s unrecognized\n", arg1);
536 }
537 } else {
538 PrintF("break <address>\n");
539 }
540 } else if (strcmp(cmd, "del") == 0) {
541 if (!DeleteBreakpoint(nullptr)) {
542 PrintF("deleting breakpoint failed\n");
543 }
544 } else if (strcmp(cmd, "flags") == 0) {
545 PrintF("No flags on MIPS !\n");
546 } else if (strcmp(cmd, "stop") == 0) {
547 int64_t value;
548 intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
549 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
550 Instruction* msg_address =
551 reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
552 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
553 // Remove the current stop.
554 if (sim_->IsStopInstruction(stop_instr)) {
555 stop_instr->SetInstructionBits(kNopInstr);
556 msg_address->SetInstructionBits(kNopInstr);
557 } else {
558 PrintF("Not at debugger stop.\n");
559 }
560 } else if (argc == 3) {
561 // Print information about all/the specified breakpoint(s).
562 if (strcmp(arg1, "info") == 0) {
563 if (strcmp(arg2, "all") == 0) {
564 PrintF("Stop information:\n");
565 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
566 i++) {
567 sim_->PrintStopInfo(i);
568 }
569 } else if (GetValue(arg2, &value)) {
570 sim_->PrintStopInfo(value);
571 } else {
572 PrintF("Unrecognized argument.\n");
573 }
574 } else if (strcmp(arg1, "enable") == 0) {
575 // Enable all/the specified breakpoint(s).
576 if (strcmp(arg2, "all") == 0) {
577 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
578 i++) {
579 sim_->EnableStop(i);
580 }
581 } else if (GetValue(arg2, &value)) {
582 sim_->EnableStop(value);
583 } else {
584 PrintF("Unrecognized argument.\n");
585 }
586 } else if (strcmp(arg1, "disable") == 0) {
587 // Disable all/the specified breakpoint(s).
588 if (strcmp(arg2, "all") == 0) {
589 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
590 i++) {
591 sim_->DisableStop(i);
592 }
593 } else if (GetValue(arg2, &value)) {
594 sim_->DisableStop(value);
595 } else {
596 PrintF("Unrecognized argument.\n");
597 }
598 }
599 } else {
600 PrintF("Wrong usage. Use help command for more information.\n");
601 }
602 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
603 // Print registers and disassemble.
604 PrintAllRegs();
605 PrintF("\n");
606
607 disasm::NameConverter converter;
608 disasm::Disassembler dasm(converter);
609 // Use a reasonably large buffer.
610 v8::base::EmbeddedVector<char, 256> buffer;
611
612 byte* cur = nullptr;
613 byte* end = nullptr;
614
615 if (argc == 1) {
616 cur = reinterpret_cast<byte*>(sim_->get_pc());
617 end = cur + (10 * kInstrSize);
618 } else if (argc == 2) {
619 int64_t value;
620 if (GetValue(arg1, &value)) {
621 cur = reinterpret_cast<byte*>(value);
622 // no length parameter passed, assume 10 instructions
623 end = cur + (10 * kInstrSize);
624 }
625 } else {
626 int64_t value1;
627 int64_t value2;
628 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
629 cur = reinterpret_cast<byte*>(value1);
630 end = cur + (value2 * kInstrSize);
631 }
632 }
633
634 while (cur < end) {
635 dasm.InstructionDecode(buffer, cur);
636 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
637 buffer.begin());
638 cur += kInstrSize;
639 }
640 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
641 PrintF("cont\n");
642 PrintF(" continue execution (alias 'c')\n");
643 PrintF("stepi\n");
644 PrintF(" step one instruction (alias 'si')\n");
645 PrintF("print <register>\n");
646 PrintF(" print register content (alias 'p')\n");
647 PrintF(" use register name 'all' to print all registers\n");
648 PrintF("printobject <register>\n");
649 PrintF(" print an object from a register (alias 'po')\n");
650 PrintF("stack [<words>]\n");
651 PrintF(" dump stack content, default dump 10 words)\n");
652 PrintF("mem <address> [<words>]\n");
653 PrintF(" dump memory content, default dump 10 words)\n");
654 PrintF("dump [<words>]\n");
655 PrintF(
656 " dump memory content without pretty printing JS objects, default "
657 "dump 10 words)\n");
658 PrintF("flags\n");
659 PrintF(" print flags\n");
660 PrintF("disasm [<instructions>]\n");
661 PrintF("disasm [<address/register>]\n");
662 PrintF("disasm [[<address/register>] <instructions>]\n");
663 PrintF(" disassemble code, default is 10 instructions\n");
664 PrintF(" from pc (alias 'di')\n");
665 PrintF("gdb\n");
666 PrintF(" enter gdb\n");
667 PrintF("break <address>\n");
668 PrintF(" set a break point on the address\n");
669 PrintF("del\n");
670 PrintF(" delete the breakpoint\n");
671 PrintF("stop feature:\n");
672 PrintF(" Description:\n");
673 PrintF(" Stops are debug instructions inserted by\n");
674 PrintF(" the Assembler::stop() function.\n");
675 PrintF(" When hitting a stop, the Simulator will\n");
676 PrintF(" stop and give control to the Debugger.\n");
677 PrintF(" All stop codes are watched:\n");
678 PrintF(" - They can be enabled / disabled: the Simulator\n");
679 PrintF(" will / won't stop when hitting them.\n");
680 PrintF(" - The Simulator keeps track of how many times they \n");
681 PrintF(" are met. (See the info command.) Going over a\n");
682 PrintF(" disabled stop still increases its counter. \n");
683 PrintF(" Commands:\n");
684 PrintF(" stop info all/<code> : print infos about number <code>\n");
685 PrintF(" or all stop(s).\n");
686 PrintF(" stop enable/disable all/<code> : enables / disables\n");
687 PrintF(" all or number <code> stop(s)\n");
688 PrintF(" stop unstop\n");
689 PrintF(" ignore the stop instruction at the current location\n");
690 PrintF(" from now on\n");
691 } else {
692 PrintF("Unknown command: %s\n", cmd);
693 }
694 }
695 }
696
697 // Add all the breakpoints back to stop execution and enter the debugger
698 // shell when hit.
699 RedoBreakpoints();
700
701 #undef COMMAND_SIZE
702 #undef ARG_SIZE
703
704 #undef STR
705 #undef XSTR
706 }
707
ICacheMatch(void * one,void * two)708 bool Simulator::ICacheMatch(void* one, void* two) {
709 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
710 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
711 return one == two;
712 }
713
ICacheHash(void * key)714 static uint32_t ICacheHash(void* key) {
715 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
716 }
717
AllOnOnePage(uintptr_t start,size_t size)718 static bool AllOnOnePage(uintptr_t start, size_t size) {
719 intptr_t start_page = (start & ~CachePage::kPageMask);
720 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
721 return start_page == end_page;
722 }
723
set_last_debugger_input(char * input)724 void Simulator::set_last_debugger_input(char* input) {
725 DeleteArray(last_debugger_input_);
726 last_debugger_input_ = input;
727 }
728
SetRedirectInstruction(Instruction * instruction)729 void Simulator::SetRedirectInstruction(Instruction* instruction) {
730 instruction->SetInstructionBits(rtCallRedirInstr);
731 }
732
FlushICache(base::CustomMatcherHashMap * i_cache,void * start_addr,size_t size)733 void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
734 void* start_addr, size_t size) {
735 int64_t start = reinterpret_cast<int64_t>(start_addr);
736 int64_t intra_line = (start & CachePage::kLineMask);
737 start -= intra_line;
738 size += intra_line;
739 size = ((size - 1) | CachePage::kLineMask) + 1;
740 int offset = (start & CachePage::kPageMask);
741 while (!AllOnOnePage(start, size - 1)) {
742 int bytes_to_flush = CachePage::kPageSize - offset;
743 FlushOnePage(i_cache, start, bytes_to_flush);
744 start += bytes_to_flush;
745 size -= bytes_to_flush;
746 DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
747 offset = 0;
748 }
749 if (size != 0) {
750 FlushOnePage(i_cache, start, size);
751 }
752 }
753
GetCachePage(base::CustomMatcherHashMap * i_cache,void * page)754 CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
755 void* page) {
756 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
757 if (entry->value == nullptr) {
758 CachePage* new_page = new CachePage();
759 entry->value = new_page;
760 }
761 return reinterpret_cast<CachePage*>(entry->value);
762 }
763
764 // Flush from start up to and not including start + size.
FlushOnePage(base::CustomMatcherHashMap * i_cache,intptr_t start,size_t size)765 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
766 intptr_t start, size_t size) {
767 DCHECK_LE(size, CachePage::kPageSize);
768 DCHECK(AllOnOnePage(start, size - 1));
769 DCHECK_EQ(start & CachePage::kLineMask, 0);
770 DCHECK_EQ(size & CachePage::kLineMask, 0);
771 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
772 int offset = (start & CachePage::kPageMask);
773 CachePage* cache_page = GetCachePage(i_cache, page);
774 char* valid_bytemap = cache_page->ValidityByte(offset);
775 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
776 }
777
CheckICache(base::CustomMatcherHashMap * i_cache,Instruction * instr)778 void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
779 Instruction* instr) {
780 int64_t address = reinterpret_cast<int64_t>(instr);
781 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
782 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
783 int offset = (address & CachePage::kPageMask);
784 CachePage* cache_page = GetCachePage(i_cache, page);
785 char* cache_valid_byte = cache_page->ValidityByte(offset);
786 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
787 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
788 if (cache_hit) {
789 // Check that the data in memory matches the contents of the I-cache.
790 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
791 cache_page->CachedData(offset), kInstrSize));
792 } else {
793 // Cache miss. Load memory into the cache.
794 memcpy(cached_line, line, CachePage::kLineLength);
795 *cache_valid_byte = CachePage::LINE_VALID;
796 }
797 }
798
Simulator(Isolate * isolate)799 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
800 // Set up simulator support first. Some of this information is needed to
801 // setup the architecture state.
802 stack_size_ = FLAG_sim_stack_size * KB;
803 stack_ = reinterpret_cast<char*>(base::Malloc(stack_size_));
804 pc_modified_ = false;
805 icount_ = 0;
806 break_count_ = 0;
807 break_pc_ = nullptr;
808 break_instr_ = 0;
809
810 // Set up architecture state.
811 // All registers are initialized to zero to start with.
812 for (int i = 0; i < kNumSimuRegisters; i++) {
813 registers_[i] = 0;
814 }
815 for (int i = 0; i < kNumFPURegisters; i++) {
816 FPUregisters_[2 * i] = 0;
817 FPUregisters_[2 * i + 1] = 0; // upper part for MSA ASE
818 }
819
820 if (kArchVariant == kMips64r6) {
821 FCSR_ = kFCSRNaN2008FlagMask;
822 MSACSR_ = 0;
823 } else {
824 FCSR_ = 0;
825 }
826
827 // The sp is initialized to point to the bottom (high address) of the
828 // allocated stack area. To be safe in potential stack underflows we leave
829 // some buffer below.
830 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64;
831 // The ra and pc are initialized to a known bad value that will cause an
832 // access violation if the simulator ever tries to execute it.
833 registers_[pc] = bad_ra;
834 registers_[ra] = bad_ra;
835
836 last_debugger_input_ = nullptr;
837 }
838
~Simulator()839 Simulator::~Simulator() {
840 GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
841 base::Free(stack_);
842 }
843
844 // Get the active Simulator for the current thread.
current(Isolate * isolate)845 Simulator* Simulator::current(Isolate* isolate) {
846 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
847 isolate->FindOrAllocatePerThreadDataForThisThread();
848 DCHECK_NOT_NULL(isolate_data);
849
850 Simulator* sim = isolate_data->simulator();
851 if (sim == nullptr) {
852 // TODO(146): delete the simulator object when a thread/isolate goes away.
853 sim = new Simulator(isolate);
854 isolate_data->set_simulator(sim);
855 }
856 return sim;
857 }
858
859 // Sets the register in the architecture state. It will also deal with updating
860 // Simulator internal state for special registers such as PC.
set_register(int reg,int64_t value)861 void Simulator::set_register(int reg, int64_t value) {
862 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
863 if (reg == pc) {
864 pc_modified_ = true;
865 }
866
867 // Zero register always holds 0.
868 registers_[reg] = (reg == 0) ? 0 : value;
869 }
870
set_dw_register(int reg,const int * dbl)871 void Simulator::set_dw_register(int reg, const int* dbl) {
872 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
873 registers_[reg] = dbl[1];
874 registers_[reg] = registers_[reg] << 32;
875 registers_[reg] += dbl[0];
876 }
877
set_fpu_register(int fpureg,int64_t value)878 void Simulator::set_fpu_register(int fpureg, int64_t value) {
879 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
880 FPUregisters_[fpureg * 2] = value;
881 }
882
set_fpu_register_word(int fpureg,int32_t value)883 void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
884 // Set ONLY lower 32-bits, leaving upper bits untouched.
885 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
886 int32_t* pword;
887 if (kArchEndian == kLittle) {
888 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
889 } else {
890 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]) + 1;
891 }
892 *pword = value;
893 }
894
set_fpu_register_hi_word(int fpureg,int32_t value)895 void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
896 // Set ONLY upper 32-bits, leaving lower bits untouched.
897 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
898 int32_t* phiword;
899 if (kArchEndian == kLittle) {
900 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
901 } else {
902 phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
903 }
904 *phiword = value;
905 }
906
set_fpu_register_float(int fpureg,float value)907 void Simulator::set_fpu_register_float(int fpureg, float value) {
908 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
909 *bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
910 }
911
set_fpu_register_double(int fpureg,double value)912 void Simulator::set_fpu_register_double(int fpureg, double value) {
913 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
914 *bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
915 }
916
917 // Get the register from the architecture state. This function does handle
918 // the special case of accessing the PC register.
get_register(int reg) const919 int64_t Simulator::get_register(int reg) const {
920 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
921 if (reg == 0)
922 return 0;
923 else
924 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
925 }
926
get_double_from_register_pair(int reg)927 double Simulator::get_double_from_register_pair(int reg) {
928 // TODO(plind): bad ABI stuff, refactor or remove.
929 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
930
931 double dm_val = 0.0;
932 // Read the bits from the unsigned integer register_[] array
933 // into the double precision floating point value and return it.
934 char buffer[sizeof(registers_[0])];
935 memcpy(buffer, ®isters_[reg], sizeof(registers_[0]));
936 memcpy(&dm_val, buffer, sizeof(registers_[0]));
937 return (dm_val);
938 }
939
get_fpu_register(int fpureg) const940 int64_t Simulator::get_fpu_register(int fpureg) const {
941 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
942 return FPUregisters_[fpureg * 2];
943 }
944
get_fpu_register_word(int fpureg) const945 int32_t Simulator::get_fpu_register_word(int fpureg) const {
946 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
947 return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
948 }
949
get_fpu_register_signed_word(int fpureg) const950 int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
951 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
952 return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
953 }
954
get_fpu_register_hi_word(int fpureg) const955 int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
956 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
957 return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xFFFFFFFF);
958 }
959
get_fpu_register_float(int fpureg) const960 float Simulator::get_fpu_register_float(int fpureg) const {
961 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
962 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
963 }
964
get_fpu_register_double(int fpureg) const965 double Simulator::get_fpu_register_double(int fpureg) const {
966 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
967 return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
968 }
969
970 template <typename T>
get_msa_register(int wreg,T * value)971 void Simulator::get_msa_register(int wreg, T* value) {
972 DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
973 memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
974 }
975
976 template <typename T>
set_msa_register(int wreg,const T * value)977 void Simulator::set_msa_register(int wreg, const T* value) {
978 DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
979 memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
980 }
981
982 // Runtime FP routines take up to two double arguments and zero
983 // or one integer arguments. All are constructed here,
984 // from a0-a3 or f12 and f13 (n64), or f14 (O32).
GetFpArgs(double * x,double * y,int32_t * z)985 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
986 if (!IsMipsSoftFloatABI) {
987 const int fparg2 = 13;
988 *x = get_fpu_register_double(12);
989 *y = get_fpu_register_double(fparg2);
990 *z = static_cast<int32_t>(get_register(a2));
991 } else {
992 // TODO(plind): bad ABI stuff, refactor or remove.
993 // We use a char buffer to get around the strict-aliasing rules which
994 // otherwise allow the compiler to optimize away the copy.
995 char buffer[sizeof(*x)];
996 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
997
998 // Registers a0 and a1 -> x.
999 reg_buffer[0] = get_register(a0);
1000 reg_buffer[1] = get_register(a1);
1001 memcpy(x, buffer, sizeof(buffer));
1002 // Registers a2 and a3 -> y.
1003 reg_buffer[0] = get_register(a2);
1004 reg_buffer[1] = get_register(a3);
1005 memcpy(y, buffer, sizeof(buffer));
1006 // Register 2 -> z.
1007 reg_buffer[0] = get_register(a2);
1008 memcpy(z, buffer, sizeof(*z));
1009 }
1010 }
1011
1012 // The return value is either in v0/v1 or f0.
SetFpResult(const double & result)1013 void Simulator::SetFpResult(const double& result) {
1014 if (!IsMipsSoftFloatABI) {
1015 set_fpu_register_double(0, result);
1016 } else {
1017 char buffer[2 * sizeof(registers_[0])];
1018 int64_t* reg_buffer = reinterpret_cast<int64_t*>(buffer);
1019 memcpy(buffer, &result, sizeof(buffer));
1020 // Copy result to v0 and v1.
1021 set_register(v0, reg_buffer[0]);
1022 set_register(v1, reg_buffer[1]);
1023 }
1024 }
1025
1026 // Helper functions for setting and testing the FCSR register's bits.
set_fcsr_bit(uint32_t cc,bool value)1027 void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1028 if (value) {
1029 FCSR_ |= (1 << cc);
1030 } else {
1031 FCSR_ &= ~(1 << cc);
1032 }
1033 }
1034
test_fcsr_bit(uint32_t cc)1035 bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
1036
clear_fcsr_cause()1037 void Simulator::clear_fcsr_cause() {
1038 FCSR_ &= ~kFCSRCauseMask;
1039 }
1040
set_fcsr_rounding_mode(FPURoundingMode mode)1041 void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1042 FCSR_ |= mode & kFPURoundingModeMask;
1043 }
1044
set_msacsr_rounding_mode(FPURoundingMode mode)1045 void Simulator::set_msacsr_rounding_mode(FPURoundingMode mode) {
1046 MSACSR_ |= mode & kFPURoundingModeMask;
1047 }
1048
get_fcsr_rounding_mode()1049 unsigned int Simulator::get_fcsr_rounding_mode() {
1050 return FCSR_ & kFPURoundingModeMask;
1051 }
1052
get_msacsr_rounding_mode()1053 unsigned int Simulator::get_msacsr_rounding_mode() {
1054 return MSACSR_ & kFPURoundingModeMask;
1055 }
1056
1057 // Sets the rounding error codes in FCSR based on the result of the rounding.
1058 // Returns true if the operation was invalid.
set_fcsr_round_error(double original,double rounded)1059 bool Simulator::set_fcsr_round_error(double original, double rounded) {
1060 bool ret = false;
1061 double max_int32 = std::numeric_limits<int32_t>::max();
1062 double min_int32 = std::numeric_limits<int32_t>::min();
1063
1064 clear_fcsr_cause();
1065
1066 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1067 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1068 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1069 ret = true;
1070 }
1071
1072 if (original != rounded) {
1073 set_fcsr_bit(kFCSRInexactFlagBit, true);
1074 set_fcsr_bit(kFCSRInexactCauseBit, true);
1075 }
1076
1077 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1078 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1079 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1080 ret = true;
1081 }
1082
1083 if (rounded > max_int32 || rounded < min_int32) {
1084 set_fcsr_bit(kFCSROverflowFlagBit, true);
1085 set_fcsr_bit(kFCSROverflowCauseBit, true);
1086 // The reference is not really clear but it seems this is required:
1087 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1088 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1089 ret = true;
1090 }
1091
1092 return ret;
1093 }
1094
1095 // Sets the rounding error codes in FCSR based on the result of the rounding.
1096 // Returns true if the operation was invalid.
set_fcsr_round64_error(double original,double rounded)1097 bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1098 bool ret = false;
1099 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1100 // loading the most accurate representation into max_int64, which is 2^63.
1101 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1102 double min_int64 = std::numeric_limits<int64_t>::min();
1103
1104 clear_fcsr_cause();
1105
1106 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1107 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1108 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1109 ret = true;
1110 }
1111
1112 if (original != rounded) {
1113 set_fcsr_bit(kFCSRInexactFlagBit, true);
1114 set_fcsr_bit(kFCSRInexactCauseBit, true);
1115 }
1116
1117 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1118 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1119 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1120 ret = true;
1121 }
1122
1123 if (rounded >= max_int64 || rounded < min_int64) {
1124 set_fcsr_bit(kFCSROverflowFlagBit, true);
1125 set_fcsr_bit(kFCSROverflowCauseBit, true);
1126 // The reference is not really clear but it seems this is required:
1127 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1128 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1129 ret = true;
1130 }
1131
1132 return ret;
1133 }
1134
1135 // Sets the rounding error codes in FCSR based on the result of the rounding.
1136 // Returns true if the operation was invalid.
set_fcsr_round_error(float original,float rounded)1137 bool Simulator::set_fcsr_round_error(float original, float rounded) {
1138 bool ret = false;
1139 double max_int32 = std::numeric_limits<int32_t>::max();
1140 double min_int32 = std::numeric_limits<int32_t>::min();
1141
1142 clear_fcsr_cause();
1143
1144 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1145 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1146 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1147 ret = true;
1148 }
1149
1150 if (original != rounded) {
1151 set_fcsr_bit(kFCSRInexactFlagBit, true);
1152 set_fcsr_bit(kFCSRInexactCauseBit, true);
1153 }
1154
1155 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1156 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1157 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1158 ret = true;
1159 }
1160
1161 if (rounded > max_int32 || rounded < min_int32) {
1162 set_fcsr_bit(kFCSROverflowFlagBit, true);
1163 set_fcsr_bit(kFCSROverflowCauseBit, true);
1164 // The reference is not really clear but it seems this is required:
1165 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1166 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1167 ret = true;
1168 }
1169
1170 return ret;
1171 }
1172
set_fpu_register_word_invalid_result(float original,float rounded)1173 void Simulator::set_fpu_register_word_invalid_result(float original,
1174 float rounded) {
1175 if (FCSR_ & kFCSRNaN2008FlagMask) {
1176 double max_int32 = std::numeric_limits<int32_t>::max();
1177 double min_int32 = std::numeric_limits<int32_t>::min();
1178 if (std::isnan(original)) {
1179 set_fpu_register_word(fd_reg(), 0);
1180 } else if (rounded > max_int32) {
1181 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1182 } else if (rounded < min_int32) {
1183 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1184 } else {
1185 UNREACHABLE();
1186 }
1187 } else {
1188 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1189 }
1190 }
1191
set_fpu_register_invalid_result(float original,float rounded)1192 void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1193 if (FCSR_ & kFCSRNaN2008FlagMask) {
1194 double max_int32 = std::numeric_limits<int32_t>::max();
1195 double min_int32 = std::numeric_limits<int32_t>::min();
1196 if (std::isnan(original)) {
1197 set_fpu_register(fd_reg(), 0);
1198 } else if (rounded > max_int32) {
1199 set_fpu_register(fd_reg(), kFPUInvalidResult);
1200 } else if (rounded < min_int32) {
1201 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1202 } else {
1203 UNREACHABLE();
1204 }
1205 } else {
1206 set_fpu_register(fd_reg(), kFPUInvalidResult);
1207 }
1208 }
1209
set_fpu_register_invalid_result64(float original,float rounded)1210 void Simulator::set_fpu_register_invalid_result64(float original,
1211 float rounded) {
1212 if (FCSR_ & kFCSRNaN2008FlagMask) {
1213 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1214 // loading the most accurate representation into max_int64, which is 2^63.
1215 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1216 double min_int64 = std::numeric_limits<int64_t>::min();
1217 if (std::isnan(original)) {
1218 set_fpu_register(fd_reg(), 0);
1219 } else if (rounded >= max_int64) {
1220 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1221 } else if (rounded < min_int64) {
1222 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1223 } else {
1224 UNREACHABLE();
1225 }
1226 } else {
1227 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1228 }
1229 }
1230
set_fpu_register_word_invalid_result(double original,double rounded)1231 void Simulator::set_fpu_register_word_invalid_result(double original,
1232 double rounded) {
1233 if (FCSR_ & kFCSRNaN2008FlagMask) {
1234 double max_int32 = std::numeric_limits<int32_t>::max();
1235 double min_int32 = std::numeric_limits<int32_t>::min();
1236 if (std::isnan(original)) {
1237 set_fpu_register_word(fd_reg(), 0);
1238 } else if (rounded > max_int32) {
1239 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1240 } else if (rounded < min_int32) {
1241 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1242 } else {
1243 UNREACHABLE();
1244 }
1245 } else {
1246 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1247 }
1248 }
1249
set_fpu_register_invalid_result(double original,double rounded)1250 void Simulator::set_fpu_register_invalid_result(double original,
1251 double rounded) {
1252 if (FCSR_ & kFCSRNaN2008FlagMask) {
1253 double max_int32 = std::numeric_limits<int32_t>::max();
1254 double min_int32 = std::numeric_limits<int32_t>::min();
1255 if (std::isnan(original)) {
1256 set_fpu_register(fd_reg(), 0);
1257 } else if (rounded > max_int32) {
1258 set_fpu_register(fd_reg(), kFPUInvalidResult);
1259 } else if (rounded < min_int32) {
1260 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1261 } else {
1262 UNREACHABLE();
1263 }
1264 } else {
1265 set_fpu_register(fd_reg(), kFPUInvalidResult);
1266 }
1267 }
1268
set_fpu_register_invalid_result64(double original,double rounded)1269 void Simulator::set_fpu_register_invalid_result64(double original,
1270 double rounded) {
1271 if (FCSR_ & kFCSRNaN2008FlagMask) {
1272 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1273 // loading the most accurate representation into max_int64, which is 2^63.
1274 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1275 double min_int64 = std::numeric_limits<int64_t>::min();
1276 if (std::isnan(original)) {
1277 set_fpu_register(fd_reg(), 0);
1278 } else if (rounded >= max_int64) {
1279 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1280 } else if (rounded < min_int64) {
1281 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1282 } else {
1283 UNREACHABLE();
1284 }
1285 } else {
1286 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1287 }
1288 }
1289
1290 // Sets the rounding error codes in FCSR based on the result of the rounding.
1291 // Returns true if the operation was invalid.
set_fcsr_round64_error(float original,float rounded)1292 bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1293 bool ret = false;
1294 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1295 // loading the most accurate representation into max_int64, which is 2^63.
1296 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1297 double min_int64 = std::numeric_limits<int64_t>::min();
1298
1299 clear_fcsr_cause();
1300
1301 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1302 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1303 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1304 ret = true;
1305 }
1306
1307 if (original != rounded) {
1308 set_fcsr_bit(kFCSRInexactFlagBit, true);
1309 set_fcsr_bit(kFCSRInexactCauseBit, true);
1310 }
1311
1312 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1313 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1314 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1315 ret = true;
1316 }
1317
1318 if (rounded >= max_int64 || rounded < min_int64) {
1319 set_fcsr_bit(kFCSROverflowFlagBit, true);
1320 set_fcsr_bit(kFCSROverflowCauseBit, true);
1321 // The reference is not really clear but it seems this is required:
1322 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1323 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1324 ret = true;
1325 }
1326
1327 return ret;
1328 }
1329
1330 // For cvt instructions only
round_according_to_fcsr(double toRound,double * rounded,int32_t * rounded_int,double fs)1331 void Simulator::round_according_to_fcsr(double toRound, double* rounded,
1332 int32_t* rounded_int, double fs) {
1333 // 0 RN (round to nearest): Round a result to the nearest
1334 // representable value; if the result is exactly halfway between
1335 // two representable values, round to zero. Behave like round_w_d.
1336
1337 // 1 RZ (round toward zero): Round a result to the closest
1338 // representable value whose absolute value is less than or
1339 // equal to the infinitely accurate result. Behave like trunc_w_d.
1340
1341 // 2 RP (round up, or toward +infinity): Round a result to the
1342 // next representable value up. Behave like ceil_w_d.
1343
1344 // 3 RN (round down, or toward −infinity): Round a result to
1345 // the next representable value down. Behave like floor_w_d.
1346 switch (FCSR_ & 3) {
1347 case kRoundToNearest:
1348 *rounded = std::floor(fs + 0.5);
1349 *rounded_int = static_cast<int32_t>(*rounded);
1350 if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1351 // If the number is halfway between two integers,
1352 // round to the even one.
1353 *rounded_int -= 1;
1354 *rounded -= 1.;
1355 }
1356 break;
1357 case kRoundToZero:
1358 *rounded = trunc(fs);
1359 *rounded_int = static_cast<int32_t>(*rounded);
1360 break;
1361 case kRoundToPlusInf:
1362 *rounded = std::ceil(fs);
1363 *rounded_int = static_cast<int32_t>(*rounded);
1364 break;
1365 case kRoundToMinusInf:
1366 *rounded = std::floor(fs);
1367 *rounded_int = static_cast<int32_t>(*rounded);
1368 break;
1369 }
1370 }
1371
round64_according_to_fcsr(double toRound,double * rounded,int64_t * rounded_int,double fs)1372 void Simulator::round64_according_to_fcsr(double toRound, double* rounded,
1373 int64_t* rounded_int, double fs) {
1374 // 0 RN (round to nearest): Round a result to the nearest
1375 // representable value; if the result is exactly halfway between
1376 // two representable values, round to zero. Behave like round_w_d.
1377
1378 // 1 RZ (round toward zero): Round a result to the closest
1379 // representable value whose absolute value is less than or.
1380 // equal to the infinitely accurate result. Behave like trunc_w_d.
1381
1382 // 2 RP (round up, or toward +infinity): Round a result to the
1383 // next representable value up. Behave like ceil_w_d.
1384
1385 // 3 RN (round down, or toward −infinity): Round a result to
1386 // the next representable value down. Behave like floor_w_d.
1387 switch (FCSR_ & 3) {
1388 case kRoundToNearest:
1389 *rounded = std::floor(fs + 0.5);
1390 *rounded_int = static_cast<int64_t>(*rounded);
1391 if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1392 // If the number is halfway between two integers,
1393 // round to the even one.
1394 *rounded_int -= 1;
1395 *rounded -= 1.;
1396 }
1397 break;
1398 case kRoundToZero:
1399 *rounded = trunc(fs);
1400 *rounded_int = static_cast<int64_t>(*rounded);
1401 break;
1402 case kRoundToPlusInf:
1403 *rounded = std::ceil(fs);
1404 *rounded_int = static_cast<int64_t>(*rounded);
1405 break;
1406 case kRoundToMinusInf:
1407 *rounded = std::floor(fs);
1408 *rounded_int = static_cast<int64_t>(*rounded);
1409 break;
1410 }
1411 }
1412
1413 // for cvt instructions only
round_according_to_fcsr(float toRound,float * rounded,int32_t * rounded_int,float fs)1414 void Simulator::round_according_to_fcsr(float toRound, float* rounded,
1415 int32_t* rounded_int, float fs) {
1416 // 0 RN (round to nearest): Round a result to the nearest
1417 // representable value; if the result is exactly halfway between
1418 // two representable values, round to zero. Behave like round_w_d.
1419
1420 // 1 RZ (round toward zero): Round a result to the closest
1421 // representable value whose absolute value is less than or
1422 // equal to the infinitely accurate result. Behave like trunc_w_d.
1423
1424 // 2 RP (round up, or toward +infinity): Round a result to the
1425 // next representable value up. Behave like ceil_w_d.
1426
1427 // 3 RN (round down, or toward −infinity): Round a result to
1428 // the next representable value down. Behave like floor_w_d.
1429 switch (FCSR_ & 3) {
1430 case kRoundToNearest:
1431 *rounded = std::floor(fs + 0.5);
1432 *rounded_int = static_cast<int32_t>(*rounded);
1433 if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1434 // If the number is halfway between two integers,
1435 // round to the even one.
1436 *rounded_int -= 1;
1437 *rounded -= 1.f;
1438 }
1439 break;
1440 case kRoundToZero:
1441 *rounded = trunc(fs);
1442 *rounded_int = static_cast<int32_t>(*rounded);
1443 break;
1444 case kRoundToPlusInf:
1445 *rounded = std::ceil(fs);
1446 *rounded_int = static_cast<int32_t>(*rounded);
1447 break;
1448 case kRoundToMinusInf:
1449 *rounded = std::floor(fs);
1450 *rounded_int = static_cast<int32_t>(*rounded);
1451 break;
1452 }
1453 }
1454
round64_according_to_fcsr(float toRound,float * rounded,int64_t * rounded_int,float fs)1455 void Simulator::round64_according_to_fcsr(float toRound, float* rounded,
1456 int64_t* rounded_int, float fs) {
1457 // 0 RN (round to nearest): Round a result to the nearest
1458 // representable value; if the result is exactly halfway between
1459 // two representable values, round to zero. Behave like round_w_d.
1460
1461 // 1 RZ (round toward zero): Round a result to the closest
1462 // representable value whose absolute value is less than or.
1463 // equal to the infinitely accurate result. Behave like trunc_w_d.
1464
1465 // 2 RP (round up, or toward +infinity): Round a result to the
1466 // next representable value up. Behave like ceil_w_d.
1467
1468 // 3 RN (round down, or toward −infinity): Round a result to
1469 // the next representable value down. Behave like floor_w_d.
1470 switch (FCSR_ & 3) {
1471 case kRoundToNearest:
1472 *rounded = std::floor(fs + 0.5);
1473 *rounded_int = static_cast<int64_t>(*rounded);
1474 if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1475 // If the number is halfway between two integers,
1476 // round to the even one.
1477 *rounded_int -= 1;
1478 *rounded -= 1.f;
1479 }
1480 break;
1481 case kRoundToZero:
1482 *rounded = trunc(fs);
1483 *rounded_int = static_cast<int64_t>(*rounded);
1484 break;
1485 case kRoundToPlusInf:
1486 *rounded = std::ceil(fs);
1487 *rounded_int = static_cast<int64_t>(*rounded);
1488 break;
1489 case kRoundToMinusInf:
1490 *rounded = std::floor(fs);
1491 *rounded_int = static_cast<int64_t>(*rounded);
1492 break;
1493 }
1494 }
1495
1496 template <typename T_fp, typename T_int>
round_according_to_msacsr(T_fp toRound,T_fp * rounded,T_int * rounded_int)1497 void Simulator::round_according_to_msacsr(T_fp toRound, T_fp* rounded,
1498 T_int* rounded_int) {
1499 // 0 RN (round to nearest): Round a result to the nearest
1500 // representable value; if the result is exactly halfway between
1501 // two representable values, round to zero. Behave like round_w_d.
1502
1503 // 1 RZ (round toward zero): Round a result to the closest
1504 // representable value whose absolute value is less than or
1505 // equal to the infinitely accurate result. Behave like trunc_w_d.
1506
1507 // 2 RP (round up, or toward +infinity): Round a result to the
1508 // next representable value up. Behave like ceil_w_d.
1509
1510 // 3 RN (round down, or toward −infinity): Round a result to
1511 // the next representable value down. Behave like floor_w_d.
1512 switch (get_msacsr_rounding_mode()) {
1513 case kRoundToNearest:
1514 *rounded = std::floor(toRound + 0.5);
1515 *rounded_int = static_cast<T_int>(*rounded);
1516 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1517 // If the number is halfway between two integers,
1518 // round to the even one.
1519 *rounded_int -= 1;
1520 *rounded -= 1.;
1521 }
1522 break;
1523 case kRoundToZero:
1524 *rounded = trunc(toRound);
1525 *rounded_int = static_cast<T_int>(*rounded);
1526 break;
1527 case kRoundToPlusInf:
1528 *rounded = std::ceil(toRound);
1529 *rounded_int = static_cast<T_int>(*rounded);
1530 break;
1531 case kRoundToMinusInf:
1532 *rounded = std::floor(toRound);
1533 *rounded_int = static_cast<T_int>(*rounded);
1534 break;
1535 }
1536 }
1537
1538 // Raw access to the PC register.
set_pc(int64_t value)1539 void Simulator::set_pc(int64_t value) {
1540 pc_modified_ = true;
1541 registers_[pc] = value;
1542 }
1543
has_bad_pc() const1544 bool Simulator::has_bad_pc() const {
1545 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1546 }
1547
1548 // Raw access to the PC register without the special adjustment when reading.
get_pc() const1549 int64_t Simulator::get_pc() const { return registers_[pc]; }
1550
1551 // The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1552 // interrupt is caused. On others it does a funky rotation thing. For now we
1553 // simply disallow unaligned reads, but at some point we may want to move to
1554 // emulating the rotate behaviour. Note that simulator runs have the runtime
1555 // system running directly on the host system and only generated code is
1556 // executed in the simulator. Since the host is typically IA32 we will not
1557 // get the correct MIPS-like behaviour on unaligned accesses.
1558
1559 // TODO(plind): refactor this messy debug code when we do unaligned access.
DieOrDebug()1560 void Simulator::DieOrDebug() {
1561 if ((1)) { // Flag for this was removed.
1562 MipsDebugger dbg(this);
1563 dbg.Debug();
1564 } else {
1565 base::OS::Abort();
1566 }
1567 }
1568
TraceRegWr(int64_t value,TraceType t)1569 void Simulator::TraceRegWr(int64_t value, TraceType t) {
1570 if (::v8::internal::FLAG_trace_sim) {
1571 union {
1572 int64_t fmt_int64;
1573 int32_t fmt_int32[2];
1574 float fmt_float[2];
1575 double fmt_double;
1576 } v;
1577 v.fmt_int64 = value;
1578
1579 switch (t) {
1580 case WORD:
1581 base::SNPrintF(trace_buf_,
1582 "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32
1583 " uint32:%" PRIu32,
1584 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]);
1585 break;
1586 case DWORD:
1587 base::SNPrintF(trace_buf_,
1588 "%016" PRIx64 " (%" PRId64 ") int64:%" PRId64
1589 " uint64:%" PRIu64,
1590 value, icount_, value, value);
1591 break;
1592 case FLOAT:
1593 base::SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") flt:%e",
1594 v.fmt_int64, icount_, v.fmt_float[0]);
1595 break;
1596 case DOUBLE:
1597 base::SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e",
1598 v.fmt_int64, icount_, v.fmt_double);
1599 break;
1600 case FLOAT_DOUBLE:
1601 base::SNPrintF(trace_buf_,
1602 "%016" PRIx64 " (%" PRId64 ") flt:%e dbl:%e",
1603 v.fmt_int64, icount_, v.fmt_float[0], v.fmt_double);
1604 break;
1605 case WORD_DWORD:
1606 base::SNPrintF(trace_buf_,
1607 "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32
1608 " uint32:%" PRIu32 " int64:%" PRId64 " uint64:%" PRIu64,
1609 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0],
1610 v.fmt_int64, v.fmt_int64);
1611 break;
1612 default:
1613 UNREACHABLE();
1614 }
1615 }
1616 }
1617
1618 template <typename T>
TraceMSARegWr(T * value,TraceType t)1619 void Simulator::TraceMSARegWr(T* value, TraceType t) {
1620 if (::v8::internal::FLAG_trace_sim) {
1621 union {
1622 uint8_t b[16];
1623 uint16_t h[8];
1624 uint32_t w[4];
1625 uint64_t d[2];
1626 float f[4];
1627 double df[2];
1628 } v;
1629 memcpy(v.b, value, kSimd128Size);
1630 switch (t) {
1631 case BYTE:
1632 base::SNPrintF(trace_buf_,
1633 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1634 ")",
1635 v.d[0], v.d[1], icount_);
1636 break;
1637 case HALF:
1638 base::SNPrintF(trace_buf_,
1639 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1640 ")",
1641 v.d[0], v.d[1], icount_);
1642 break;
1643 case WORD:
1644 base::SNPrintF(trace_buf_,
1645 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1646 ") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
1647 " %" PRId32,
1648 v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1649 break;
1650 case DWORD:
1651 base::SNPrintF(trace_buf_,
1652 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1653 ")",
1654 v.d[0], v.d[1], icount_);
1655 break;
1656 case FLOAT:
1657 base::SNPrintF(trace_buf_,
1658 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1659 ") flt[0..3]:%e %e %e %e",
1660 v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1661 break;
1662 case DOUBLE:
1663 base::SNPrintF(trace_buf_,
1664 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1665 ") dbl[0..1]:%e %e",
1666 v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1667 break;
1668 default:
1669 UNREACHABLE();
1670 }
1671 }
1672 }
1673
1674 template <typename T>
TraceMSARegWr(T * value)1675 void Simulator::TraceMSARegWr(T* value) {
1676 if (::v8::internal::FLAG_trace_sim) {
1677 union {
1678 uint8_t b[kMSALanesByte];
1679 uint16_t h[kMSALanesHalf];
1680 uint32_t w[kMSALanesWord];
1681 uint64_t d[kMSALanesDword];
1682 float f[kMSALanesWord];
1683 double df[kMSALanesDword];
1684 } v;
1685 memcpy(v.b, value, kMSALanesByte);
1686
1687 if (std::is_same<T, int32_t>::value) {
1688 base::SNPrintF(trace_buf_,
1689 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1690 ") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
1691 " %" PRId32,
1692 v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1693 } else if (std::is_same<T, float>::value) {
1694 base::SNPrintF(trace_buf_,
1695 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1696 ") flt[0..3]:%e %e %e %e",
1697 v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1698 } else if (std::is_same<T, double>::value) {
1699 base::SNPrintF(trace_buf_,
1700 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
1701 ") dbl[0..1]:%e %e",
1702 v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1703 } else {
1704 base::SNPrintF(trace_buf_,
1705 "LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
1706 v.d[0], v.d[1], icount_);
1707 }
1708 }
1709 }
1710
1711 // TODO(plind): consider making icount_ printing a flag option.
TraceMemRd(int64_t addr,int64_t value,TraceType t)1712 void Simulator::TraceMemRd(int64_t addr, int64_t value, TraceType t) {
1713 if (::v8::internal::FLAG_trace_sim) {
1714 union {
1715 int64_t fmt_int64;
1716 int32_t fmt_int32[2];
1717 float fmt_float[2];
1718 double fmt_double;
1719 } v;
1720 v.fmt_int64 = value;
1721
1722 switch (t) {
1723 case WORD:
1724 base::SNPrintF(trace_buf_,
1725 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1726 ") int32:%" PRId32 " uint32:%" PRIu32,
1727 v.fmt_int64, addr, icount_, v.fmt_int32[0],
1728 v.fmt_int32[0]);
1729 break;
1730 case DWORD:
1731 base::SNPrintF(trace_buf_,
1732 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1733 ") int64:%" PRId64 " uint64:%" PRIu64,
1734 value, addr, icount_, value, value);
1735 break;
1736 case FLOAT:
1737 base::SNPrintF(trace_buf_,
1738 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1739 ") flt:%e",
1740 v.fmt_int64, addr, icount_, v.fmt_float[0]);
1741 break;
1742 case DOUBLE:
1743 base::SNPrintF(trace_buf_,
1744 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1745 ") dbl:%e",
1746 v.fmt_int64, addr, icount_, v.fmt_double);
1747 break;
1748 case FLOAT_DOUBLE:
1749 base::SNPrintF(trace_buf_,
1750 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1751 ") flt:%e dbl:%e",
1752 v.fmt_int64, addr, icount_, v.fmt_float[0],
1753 v.fmt_double);
1754 break;
1755 default:
1756 UNREACHABLE();
1757 }
1758 }
1759 }
1760
TraceMemWr(int64_t addr,int64_t value,TraceType t)1761 void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
1762 if (::v8::internal::FLAG_trace_sim) {
1763 switch (t) {
1764 case BYTE:
1765 base::SNPrintF(trace_buf_,
1766 " %02" PRIx8 " --> [%016" PRIx64
1767 "] (%" PRId64 ")",
1768 static_cast<uint8_t>(value), addr, icount_);
1769 break;
1770 case HALF:
1771 base::SNPrintF(trace_buf_,
1772 " %04" PRIx16 " --> [%016" PRIx64
1773 "] (%" PRId64 ")",
1774 static_cast<uint16_t>(value), addr, icount_);
1775 break;
1776 case WORD:
1777 base::SNPrintF(trace_buf_,
1778 " %08" PRIx32 " --> [%016" PRIx64 "] (%" PRId64
1779 ")",
1780 static_cast<uint32_t>(value), addr, icount_);
1781 break;
1782 case DWORD:
1783 base::SNPrintF(trace_buf_,
1784 "%016" PRIx64 " --> [%016" PRIx64 "] (%" PRId64 " )",
1785 value, addr, icount_);
1786 break;
1787 default:
1788 UNREACHABLE();
1789 }
1790 }
1791 }
1792
1793 template <typename T>
TraceMemRd(int64_t addr,T value)1794 void Simulator::TraceMemRd(int64_t addr, T value) {
1795 if (::v8::internal::FLAG_trace_sim) {
1796 switch (sizeof(T)) {
1797 case 1:
1798 base::SNPrintF(trace_buf_,
1799 "%08" PRIx8 " <-- [%08" PRIx64 "] (%" PRIu64
1800 ") int8:%" PRId8 " uint8:%" PRIu8,
1801 static_cast<uint8_t>(value), addr, icount_,
1802 static_cast<int8_t>(value), static_cast<uint8_t>(value));
1803 break;
1804 case 2:
1805 base::SNPrintF(trace_buf_,
1806 "%08" PRIx16 " <-- [%08" PRIx64 "] (%" PRIu64
1807 ") int16:%" PRId16 " uint16:%" PRIu16,
1808 static_cast<uint16_t>(value), addr, icount_,
1809 static_cast<int16_t>(value),
1810 static_cast<uint16_t>(value));
1811 break;
1812 case 4:
1813 base::SNPrintF(trace_buf_,
1814 "%08" PRIx32 " <-- [%08" PRIx64 "] (%" PRIu64
1815 ") int32:%" PRId32 " uint32:%" PRIu32,
1816 static_cast<uint32_t>(value), addr, icount_,
1817 static_cast<int32_t>(value),
1818 static_cast<uint32_t>(value));
1819 break;
1820 case 8:
1821 base::SNPrintF(trace_buf_,
1822 "%08" PRIx64 " <-- [%08" PRIx64 "] (%" PRIu64
1823 ") int64:%" PRId64 " uint64:%" PRIu64,
1824 static_cast<uint64_t>(value), addr, icount_,
1825 static_cast<int64_t>(value),
1826 static_cast<uint64_t>(value));
1827 break;
1828 default:
1829 UNREACHABLE();
1830 }
1831 }
1832 }
1833
1834 template <typename T>
TraceMemWr(int64_t addr,T value)1835 void Simulator::TraceMemWr(int64_t addr, T value) {
1836 if (::v8::internal::FLAG_trace_sim) {
1837 switch (sizeof(T)) {
1838 case 1:
1839 base::SNPrintF(trace_buf_,
1840 " %02" PRIx8 " --> [%08" PRIx64 "] (%" PRIu64
1841 ")",
1842 static_cast<uint8_t>(value), addr, icount_);
1843 break;
1844 case 2:
1845 base::SNPrintF(trace_buf_,
1846 " %04" PRIx16 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1847 static_cast<uint16_t>(value), addr, icount_);
1848 break;
1849 case 4:
1850 base::SNPrintF(trace_buf_,
1851 "%08" PRIx32 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1852 static_cast<uint32_t>(value), addr, icount_);
1853 break;
1854 case 8:
1855 base::SNPrintF(trace_buf_,
1856 "%16" PRIx64 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1857 static_cast<uint64_t>(value), addr, icount_);
1858 break;
1859 default:
1860 UNREACHABLE();
1861 }
1862 }
1863 }
1864
1865 // TODO(plind): sign-extend and zero-extend not implmented properly
1866 // on all the ReadXX functions, I don't think re-interpret cast does it.
ReadW(int64_t addr,Instruction * instr,TraceType t)1867 int32_t Simulator::ReadW(int64_t addr, Instruction* instr, TraceType t) {
1868 if (addr >= 0 && addr < 0x400) {
1869 // This has to be a nullptr-dereference, drop into debugger.
1870 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1871 " \n",
1872 addr, reinterpret_cast<intptr_t>(instr));
1873 DieOrDebug();
1874 }
1875 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
1876 local_monitor_.NotifyLoad();
1877 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1878 TraceMemRd(addr, static_cast<int64_t>(*ptr), t);
1879 return *ptr;
1880 }
1881 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1882 reinterpret_cast<intptr_t>(instr));
1883 DieOrDebug();
1884 return 0;
1885 }
1886
ReadWU(int64_t addr,Instruction * instr)1887 uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) {
1888 if (addr >= 0 && addr < 0x400) {
1889 // This has to be a nullptr-dereference, drop into debugger.
1890 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1891 " \n",
1892 addr, reinterpret_cast<intptr_t>(instr));
1893 DieOrDebug();
1894 }
1895 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
1896 local_monitor_.NotifyLoad();
1897 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1898 TraceMemRd(addr, static_cast<int64_t>(*ptr), WORD);
1899 return *ptr;
1900 }
1901 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1902 reinterpret_cast<intptr_t>(instr));
1903 DieOrDebug();
1904 return 0;
1905 }
1906
WriteW(int64_t addr,int32_t value,Instruction * instr)1907 void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) {
1908 if (addr >= 0 && addr < 0x400) {
1909 // This has to be a nullptr-dereference, drop into debugger.
1910 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1911 " \n",
1912 addr, reinterpret_cast<intptr_t>(instr));
1913 DieOrDebug();
1914 }
1915 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
1916 local_monitor_.NotifyStore();
1917 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1918 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1919 TraceMemWr(addr, value, WORD);
1920 int* ptr = reinterpret_cast<int*>(addr);
1921 *ptr = value;
1922 return;
1923 }
1924 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1925 reinterpret_cast<intptr_t>(instr));
1926 DieOrDebug();
1927 }
1928
WriteConditionalW(int64_t addr,int32_t value,Instruction * instr,int32_t rt_reg)1929 void Simulator::WriteConditionalW(int64_t addr, int32_t value,
1930 Instruction* instr, int32_t rt_reg) {
1931 if (addr >= 0 && addr < 0x400) {
1932 // This has to be a nullptr-dereference, drop into debugger.
1933 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1934 " \n",
1935 addr, reinterpret_cast<intptr_t>(instr));
1936 DieOrDebug();
1937 }
1938 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
1939 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1940 if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
1941 GlobalMonitor::Get()->NotifyStoreConditional_Locked(
1942 addr, &global_monitor_thread_)) {
1943 local_monitor_.NotifyStore();
1944 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1945 TraceMemWr(addr, value, WORD);
1946 int* ptr = reinterpret_cast<int*>(addr);
1947 *ptr = value;
1948 set_register(rt_reg, 1);
1949 } else {
1950 set_register(rt_reg, 0);
1951 }
1952 return;
1953 }
1954 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1955 reinterpret_cast<intptr_t>(instr));
1956 DieOrDebug();
1957 }
1958
Read2W(int64_t addr,Instruction * instr)1959 int64_t Simulator::Read2W(int64_t addr, Instruction* instr) {
1960 if (addr >= 0 && addr < 0x400) {
1961 // This has to be a nullptr-dereference, drop into debugger.
1962 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1963 " \n",
1964 addr, reinterpret_cast<intptr_t>(instr));
1965 DieOrDebug();
1966 }
1967 if ((addr & kPointerAlignmentMask) == 0 || kArchVariant == kMips64r6) {
1968 local_monitor_.NotifyLoad();
1969 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1970 TraceMemRd(addr, *ptr);
1971 return *ptr;
1972 }
1973 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1974 reinterpret_cast<intptr_t>(instr));
1975 DieOrDebug();
1976 return 0;
1977 }
1978
Write2W(int64_t addr,int64_t value,Instruction * instr)1979 void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) {
1980 if (addr >= 0 && addr < 0x400) {
1981 // This has to be a nullptr-dereference, drop into debugger.
1982 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1983 "\n",
1984 addr, reinterpret_cast<intptr_t>(instr));
1985 DieOrDebug();
1986 }
1987 if ((addr & kPointerAlignmentMask) == 0 || kArchVariant == kMips64r6) {
1988 local_monitor_.NotifyStore();
1989 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1990 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1991 TraceMemWr(addr, value, DWORD);
1992 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1993 *ptr = value;
1994 return;
1995 }
1996 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1997 reinterpret_cast<intptr_t>(instr));
1998 DieOrDebug();
1999 }
2000
WriteConditional2W(int64_t addr,int64_t value,Instruction * instr,int32_t rt_reg)2001 void Simulator::WriteConditional2W(int64_t addr, int64_t value,
2002 Instruction* instr, int32_t rt_reg) {
2003 if (addr >= 0 && addr < 0x400) {
2004 // This has to be a nullptr-dereference, drop into debugger.
2005 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
2006 "\n",
2007 addr, reinterpret_cast<intptr_t>(instr));
2008 DieOrDebug();
2009 }
2010 if ((addr & kPointerAlignmentMask) == 0 || kArchVariant == kMips64r6) {
2011 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2012 if (local_monitor_.NotifyStoreConditional(addr,
2013 TransactionSize::DoubleWord) &&
2014 GlobalMonitor::Get()->NotifyStoreConditional_Locked(
2015 addr, &global_monitor_thread_)) {
2016 local_monitor_.NotifyStore();
2017 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2018 TraceMemWr(addr, value, DWORD);
2019 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
2020 *ptr = value;
2021 set_register(rt_reg, 1);
2022 } else {
2023 set_register(rt_reg, 0);
2024 }
2025 return;
2026 }
2027 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
2028 reinterpret_cast<intptr_t>(instr));
2029 DieOrDebug();
2030 }
2031
ReadD(int64_t addr,Instruction * instr)2032 double Simulator::ReadD(int64_t addr, Instruction* instr) {
2033 if ((addr & kDoubleAlignmentMask) == 0 || kArchVariant == kMips64r6) {
2034 local_monitor_.NotifyLoad();
2035 double* ptr = reinterpret_cast<double*>(addr);
2036 return *ptr;
2037 }
2038 PrintF("Unaligned (double) read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
2039 addr, reinterpret_cast<intptr_t>(instr));
2040 base::OS::Abort();
2041 }
2042
WriteD(int64_t addr,double value,Instruction * instr)2043 void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
2044 if ((addr & kDoubleAlignmentMask) == 0 || kArchVariant == kMips64r6) {
2045 local_monitor_.NotifyStore();
2046 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2047 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2048 double* ptr = reinterpret_cast<double*>(addr);
2049 *ptr = value;
2050 return;
2051 }
2052 PrintF("Unaligned (double) write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
2053 "\n",
2054 addr, reinterpret_cast<intptr_t>(instr));
2055 DieOrDebug();
2056 }
2057
ReadHU(int64_t addr,Instruction * instr)2058 uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
2059 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
2060 local_monitor_.NotifyLoad();
2061 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2062 TraceMemRd(addr, static_cast<int64_t>(*ptr));
2063 return *ptr;
2064 }
2065 PrintF("Unaligned unsigned halfword read at 0x%08" PRIx64
2066 " , pc=0x%08" V8PRIxPTR "\n",
2067 addr, reinterpret_cast<intptr_t>(instr));
2068 DieOrDebug();
2069 return 0;
2070 }
2071
ReadH(int64_t addr,Instruction * instr)2072 int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
2073 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
2074 local_monitor_.NotifyLoad();
2075 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2076 TraceMemRd(addr, static_cast<int64_t>(*ptr));
2077 return *ptr;
2078 }
2079 PrintF("Unaligned signed halfword read at 0x%08" PRIx64
2080 " , pc=0x%08" V8PRIxPTR "\n",
2081 addr, reinterpret_cast<intptr_t>(instr));
2082 DieOrDebug();
2083 return 0;
2084 }
2085
WriteH(int64_t addr,uint16_t value,Instruction * instr)2086 void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
2087 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
2088 local_monitor_.NotifyStore();
2089 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2090 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2091 TraceMemWr(addr, value, HALF);
2092 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2093 *ptr = value;
2094 return;
2095 }
2096 PrintF("Unaligned unsigned halfword write at 0x%08" PRIx64
2097 " , pc=0x%08" V8PRIxPTR "\n",
2098 addr, reinterpret_cast<intptr_t>(instr));
2099 DieOrDebug();
2100 }
2101
WriteH(int64_t addr,int16_t value,Instruction * instr)2102 void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
2103 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
2104 local_monitor_.NotifyStore();
2105 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2106 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2107 TraceMemWr(addr, value, HALF);
2108 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2109 *ptr = value;
2110 return;
2111 }
2112 PrintF("Unaligned halfword write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
2113 "\n",
2114 addr, reinterpret_cast<intptr_t>(instr));
2115 DieOrDebug();
2116 }
2117
ReadBU(int64_t addr)2118 uint32_t Simulator::ReadBU(int64_t addr) {
2119 local_monitor_.NotifyLoad();
2120 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2121 TraceMemRd(addr, static_cast<int64_t>(*ptr));
2122 return *ptr & 0xFF;
2123 }
2124
ReadB(int64_t addr)2125 int32_t Simulator::ReadB(int64_t addr) {
2126 local_monitor_.NotifyLoad();
2127 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2128 TraceMemRd(addr, static_cast<int64_t>(*ptr));
2129 return *ptr;
2130 }
2131
WriteB(int64_t addr,uint8_t value)2132 void Simulator::WriteB(int64_t addr, uint8_t value) {
2133 local_monitor_.NotifyStore();
2134 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2135 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2136 TraceMemWr(addr, value, BYTE);
2137 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2138 *ptr = value;
2139 }
2140
WriteB(int64_t addr,int8_t value)2141 void Simulator::WriteB(int64_t addr, int8_t value) {
2142 local_monitor_.NotifyStore();
2143 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2144 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2145 TraceMemWr(addr, value, BYTE);
2146 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2147 *ptr = value;
2148 }
2149
2150 template <typename T>
ReadMem(int64_t addr,Instruction * instr)2151 T Simulator::ReadMem(int64_t addr, Instruction* instr) {
2152 int alignment_mask = (1 << sizeof(T)) - 1;
2153 if ((addr & alignment_mask) == 0 || kArchVariant == kMips64r6) {
2154 local_monitor_.NotifyLoad();
2155 T* ptr = reinterpret_cast<T*>(addr);
2156 TraceMemRd(addr, *ptr);
2157 return *ptr;
2158 }
2159 PrintF("Unaligned read of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
2160 "\n",
2161 sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2162 base::OS::Abort();
2163 return 0;
2164 }
2165
2166 template <typename T>
WriteMem(int64_t addr,T value,Instruction * instr)2167 void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) {
2168 int alignment_mask = (1 << sizeof(T)) - 1;
2169 if ((addr & alignment_mask) == 0 || kArchVariant == kMips64r6) {
2170 local_monitor_.NotifyStore();
2171 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2172 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2173 T* ptr = reinterpret_cast<T*>(addr);
2174 *ptr = value;
2175 TraceMemWr(addr, value);
2176 return;
2177 }
2178 PrintF("Unaligned write of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
2179 "\n",
2180 sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2181 base::OS::Abort();
2182 }
2183
2184 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const2185 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
2186 // The simulator uses a separate JS stack. If we have exhausted the C stack,
2187 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
2188 if (base::Stack::GetCurrentStackPosition() < c_limit) {
2189 return reinterpret_cast<uintptr_t>(get_sp());
2190 }
2191
2192 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
2193 // to prevent overrunning the stack when pushing values.
2194 return reinterpret_cast<uintptr_t>(stack_) + 1024;
2195 }
2196
2197 // Unsupported instructions use Format to print an error and stop execution.
Format(Instruction * instr,const char * format)2198 void Simulator::Format(Instruction* instr, const char* format) {
2199 PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n",
2200 reinterpret_cast<intptr_t>(instr), format);
2201 UNIMPLEMENTED_MIPS();
2202 }
2203
2204 // Calls into the V8 runtime are based on this very simple interface.
2205 // Note: To be able to return two values from some calls the code in runtime.cc
2206 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
2207 // 64-bit value. With the code below we assume that all runtime calls return
2208 // 64 bits of result. If they don't, the v1 result register contains a bogus
2209 // value, which is fine because it is caller-saved.
2210 using SimulatorRuntimeCall = ObjectPair (*)(
2211 int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4,
2212 int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg9,
2213 int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13, int64_t arg14,
2214 int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18, int64_t arg19);
2215
2216 // These prototypes handle the four types of FP calls.
2217 using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
2218 using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
2219 using SimulatorRuntimeFPCall = double (*)(double darg0);
2220 using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
2221
2222 // This signature supports direct call in to API function native callback
2223 // (refer to InvocationCallback in v8.h).
2224 using SimulatorRuntimeDirectApiCall = void (*)(int64_t arg0);
2225 using SimulatorRuntimeProfilingApiCall = void (*)(int64_t arg0, void* arg1);
2226
2227 // This signature supports direct call to accessor getter callback.
2228 using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1);
2229 using SimulatorRuntimeProfilingGetterCall = void (*)(int64_t arg0, int64_t arg1,
2230 void* arg2);
2231
2232 // Software interrupt instructions are used by the simulator to call into the
2233 // C-based V8 runtime. They are also used for debugging with simulator.
SoftwareInterrupt()2234 void Simulator::SoftwareInterrupt() {
2235 // There are several instructions that could get us here,
2236 // the break_ instruction, or several variants of traps. All
2237 // Are "SPECIAL" class opcode, and are distinuished by function.
2238 int32_t func = instr_.FunctionFieldRaw();
2239 uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
2240 // We first check if we met a call_rt_redirected.
2241 if (instr_.InstructionBits() == rtCallRedirInstr) {
2242 Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2243
2244 int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
2245
2246 int64_t arg0 = get_register(a0);
2247 int64_t arg1 = get_register(a1);
2248 int64_t arg2 = get_register(a2);
2249 int64_t arg3 = get_register(a3);
2250 int64_t arg4 = get_register(a4);
2251 int64_t arg5 = get_register(a5);
2252 int64_t arg6 = get_register(a6);
2253 int64_t arg7 = get_register(a7);
2254 int64_t arg8 = stack_pointer[0];
2255 int64_t arg9 = stack_pointer[1];
2256 int64_t arg10 = stack_pointer[2];
2257 int64_t arg11 = stack_pointer[3];
2258 int64_t arg12 = stack_pointer[4];
2259 int64_t arg13 = stack_pointer[5];
2260 int64_t arg14 = stack_pointer[6];
2261 int64_t arg15 = stack_pointer[7];
2262 int64_t arg16 = stack_pointer[8];
2263 int64_t arg17 = stack_pointer[9];
2264 int64_t arg18 = stack_pointer[10];
2265 int64_t arg19 = stack_pointer[11];
2266 STATIC_ASSERT(kMaxCParameters == 20);
2267
2268 bool fp_call =
2269 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2270 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2271 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2272 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2273
2274 if (!IsMipsSoftFloatABI) {
2275 // With the hard floating point calling convention, double
2276 // arguments are passed in FPU registers. Fetch the arguments
2277 // from there and call the builtin using soft floating point
2278 // convention.
2279 switch (redirection->type()) {
2280 case ExternalReference::BUILTIN_FP_FP_CALL:
2281 case ExternalReference::BUILTIN_COMPARE_CALL:
2282 arg0 = get_fpu_register(f12);
2283 arg1 = get_fpu_register(f13);
2284 arg2 = get_fpu_register(f14);
2285 arg3 = get_fpu_register(f15);
2286 break;
2287 case ExternalReference::BUILTIN_FP_CALL:
2288 arg0 = get_fpu_register(f12);
2289 arg1 = get_fpu_register(f13);
2290 break;
2291 case ExternalReference::BUILTIN_FP_INT_CALL:
2292 arg0 = get_fpu_register(f12);
2293 arg1 = get_fpu_register(f13);
2294 arg2 = get_register(a2);
2295 break;
2296 default:
2297 break;
2298 }
2299 }
2300
2301 // This is dodgy but it works because the C entry stubs are never moved.
2302 // See comment in codegen-arm.cc and bug 1242173.
2303 int64_t saved_ra = get_register(ra);
2304
2305 intptr_t external =
2306 reinterpret_cast<intptr_t>(redirection->external_function());
2307
2308 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2309 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2310 // simulator. Soft-float has additional abstraction of ExternalReference,
2311 // to support serialization.
2312 if (fp_call) {
2313 double dval0, dval1; // one or two double parameters
2314 int32_t ival; // zero or one integer parameters
2315 int64_t iresult = 0; // integer return value
2316 double dresult = 0; // double return value
2317 GetFpArgs(&dval0, &dval1, &ival);
2318 SimulatorRuntimeCall generic_target =
2319 reinterpret_cast<SimulatorRuntimeCall>(external);
2320 if (::v8::internal::FLAG_trace_sim) {
2321 switch (redirection->type()) {
2322 case ExternalReference::BUILTIN_FP_FP_CALL:
2323 case ExternalReference::BUILTIN_COMPARE_CALL:
2324 PrintF("Call to host function at %p with args %f, %f",
2325 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2326 dval0, dval1);
2327 break;
2328 case ExternalReference::BUILTIN_FP_CALL:
2329 PrintF("Call to host function at %p with arg %f",
2330 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2331 dval0);
2332 break;
2333 case ExternalReference::BUILTIN_FP_INT_CALL:
2334 PrintF("Call to host function at %p with args %f, %d",
2335 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2336 dval0, ival);
2337 break;
2338 default:
2339 UNREACHABLE();
2340 }
2341 }
2342 switch (redirection->type()) {
2343 case ExternalReference::BUILTIN_COMPARE_CALL: {
2344 SimulatorRuntimeCompareCall target =
2345 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2346 iresult = target(dval0, dval1);
2347 set_register(v0, static_cast<int64_t>(iresult));
2348 // set_register(v1, static_cast<int64_t>(iresult >> 32));
2349 break;
2350 }
2351 case ExternalReference::BUILTIN_FP_FP_CALL: {
2352 SimulatorRuntimeFPFPCall target =
2353 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2354 dresult = target(dval0, dval1);
2355 SetFpResult(dresult);
2356 break;
2357 }
2358 case ExternalReference::BUILTIN_FP_CALL: {
2359 SimulatorRuntimeFPCall target =
2360 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2361 dresult = target(dval0);
2362 SetFpResult(dresult);
2363 break;
2364 }
2365 case ExternalReference::BUILTIN_FP_INT_CALL: {
2366 SimulatorRuntimeFPIntCall target =
2367 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2368 dresult = target(dval0, ival);
2369 SetFpResult(dresult);
2370 break;
2371 }
2372 default:
2373 UNREACHABLE();
2374 }
2375 if (::v8::internal::FLAG_trace_sim) {
2376 switch (redirection->type()) {
2377 case ExternalReference::BUILTIN_COMPARE_CALL:
2378 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2379 break;
2380 case ExternalReference::BUILTIN_FP_FP_CALL:
2381 case ExternalReference::BUILTIN_FP_CALL:
2382 case ExternalReference::BUILTIN_FP_INT_CALL:
2383 PrintF("Returned %f\n", dresult);
2384 break;
2385 default:
2386 UNREACHABLE();
2387 }
2388 }
2389 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2390 if (::v8::internal::FLAG_trace_sim) {
2391 PrintF("Call to host function at %p args %08" PRIx64 " \n",
2392 reinterpret_cast<void*>(external), arg0);
2393 }
2394 SimulatorRuntimeDirectApiCall target =
2395 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2396 target(arg0);
2397 } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
2398 if (::v8::internal::FLAG_trace_sim) {
2399 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2400 " \n",
2401 reinterpret_cast<void*>(external), arg0, arg1);
2402 }
2403 SimulatorRuntimeProfilingApiCall target =
2404 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2405 target(arg0, Redirection::ReverseRedirection(arg1));
2406 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2407 if (::v8::internal::FLAG_trace_sim) {
2408 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2409 " \n",
2410 reinterpret_cast<void*>(external), arg0, arg1);
2411 }
2412 SimulatorRuntimeDirectGetterCall target =
2413 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2414 target(arg0, arg1);
2415 } else if (redirection->type() ==
2416 ExternalReference::PROFILING_GETTER_CALL) {
2417 if (::v8::internal::FLAG_trace_sim) {
2418 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2419 " %08" PRIx64 " \n",
2420 reinterpret_cast<void*>(external), arg0, arg1, arg2);
2421 }
2422 SimulatorRuntimeProfilingGetterCall target =
2423 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2424 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2425 } else {
2426 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2427 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2428 SimulatorRuntimeCall target =
2429 reinterpret_cast<SimulatorRuntimeCall>(external);
2430 if (::v8::internal::FLAG_trace_sim) {
2431 PrintF(
2432 "Call to host function at %p "
2433 "args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2434 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2435 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2436 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2437 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2438 " \n",
2439 reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
2440 arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
2441 arg13, arg14, arg15, arg16, arg17, arg18, arg19);
2442 }
2443 ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
2444 arg8, arg9, arg10, arg11, arg12, arg13, arg14,
2445 arg15, arg16, arg17, arg18, arg19);
2446 set_register(v0, (int64_t)(result.x));
2447 set_register(v1, (int64_t)(result.y));
2448 }
2449 if (::v8::internal::FLAG_trace_sim) {
2450 PrintF("Returned %08" PRIx64 " : %08" PRIx64 " \n", get_register(v1),
2451 get_register(v0));
2452 }
2453 set_register(ra, saved_ra);
2454 set_pc(get_register(ra));
2455
2456 } else if (func == BREAK && code <= kMaxStopCode) {
2457 if (IsWatchpoint(code)) {
2458 PrintWatchpoint(code);
2459 } else {
2460 IncreaseStopCounter(code);
2461 HandleStop(code, instr_.instr());
2462 }
2463 } else {
2464 // All remaining break_ codes, and all traps are handled here.
2465 MipsDebugger dbg(this);
2466 dbg.Debug();
2467 }
2468 }
2469
2470 // Stop helper functions.
IsWatchpoint(uint64_t code)2471 bool Simulator::IsWatchpoint(uint64_t code) {
2472 return (code <= kMaxWatchpointCode);
2473 }
2474
PrintWatchpoint(uint64_t code)2475 void Simulator::PrintWatchpoint(uint64_t code) {
2476 MipsDebugger dbg(this);
2477 ++break_count_;
2478 PrintF("\n---- break %" PRId64 " marker: %3d (instr count: %8" PRId64
2479 " ) ----------"
2480 "----------------------------------",
2481 code, break_count_, icount_);
2482 dbg.PrintAllRegs(); // Print registers and continue running.
2483 }
2484
HandleStop(uint64_t code,Instruction * instr)2485 void Simulator::HandleStop(uint64_t code, Instruction* instr) {
2486 // Stop if it is enabled, otherwise go on jumping over the stop
2487 // and the message address.
2488 if (IsEnabledStop(code)) {
2489 MipsDebugger dbg(this);
2490 dbg.Stop(instr);
2491 }
2492 }
2493
IsStopInstruction(Instruction * instr)2494 bool Simulator::IsStopInstruction(Instruction* instr) {
2495 int32_t func = instr->FunctionFieldRaw();
2496 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2497 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2498 }
2499
IsEnabledStop(uint64_t code)2500 bool Simulator::IsEnabledStop(uint64_t code) {
2501 DCHECK_LE(code, kMaxStopCode);
2502 DCHECK_GT(code, kMaxWatchpointCode);
2503 return !(watched_stops_[code].count & kStopDisabledBit);
2504 }
2505
EnableStop(uint64_t code)2506 void Simulator::EnableStop(uint64_t code) {
2507 if (!IsEnabledStop(code)) {
2508 watched_stops_[code].count &= ~kStopDisabledBit;
2509 }
2510 }
2511
DisableStop(uint64_t code)2512 void Simulator::DisableStop(uint64_t code) {
2513 if (IsEnabledStop(code)) {
2514 watched_stops_[code].count |= kStopDisabledBit;
2515 }
2516 }
2517
IncreaseStopCounter(uint64_t code)2518 void Simulator::IncreaseStopCounter(uint64_t code) {
2519 DCHECK_LE(code, kMaxStopCode);
2520 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2521 PrintF("Stop counter for code %" PRId64
2522 " has overflowed.\n"
2523 "Enabling this code and reseting the counter to 0.\n",
2524 code);
2525 watched_stops_[code].count = 0;
2526 EnableStop(code);
2527 } else {
2528 watched_stops_[code].count++;
2529 }
2530 }
2531
2532 // Print a stop status.
PrintStopInfo(uint64_t code)2533 void Simulator::PrintStopInfo(uint64_t code) {
2534 if (code <= kMaxWatchpointCode) {
2535 PrintF("That is a watchpoint, not a stop.\n");
2536 return;
2537 } else if (code > kMaxStopCode) {
2538 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2539 return;
2540 }
2541 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2542 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2543 // Don't print the state of unused breakpoints.
2544 if (count != 0) {
2545 if (watched_stops_[code].desc) {
2546 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i, \t%s\n",
2547 code, code, state, count, watched_stops_[code].desc);
2548 } else {
2549 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i\n", code,
2550 code, state, count);
2551 }
2552 }
2553 }
2554
SignalException(Exception e)2555 void Simulator::SignalException(Exception e) {
2556 FATAL("Error: Exception %i raised.", static_cast<int>(e));
2557 }
2558
2559 // Min/Max template functions for Double and Single arguments.
2560
2561 template <typename T>
2562 static T FPAbs(T a);
2563
2564 template <>
FPAbs(double a)2565 double FPAbs<double>(double a) {
2566 return fabs(a);
2567 }
2568
2569 template <>
FPAbs(float a)2570 float FPAbs<float>(float a) {
2571 return fabsf(a);
2572 }
2573
2574 template <typename T>
FPUProcessNaNsAndZeros(T a,T b,MaxMinKind kind,T * result)2575 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
2576 if (std::isnan(a) && std::isnan(b)) {
2577 *result = a;
2578 } else if (std::isnan(a)) {
2579 *result = b;
2580 } else if (std::isnan(b)) {
2581 *result = a;
2582 } else if (b == a) {
2583 // Handle -0.0 == 0.0 case.
2584 // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2585 // negates the result.
2586 *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2587 } else {
2588 return false;
2589 }
2590 return true;
2591 }
2592
2593 template <typename T>
FPUMin(T a,T b)2594 static T FPUMin(T a, T b) {
2595 T result;
2596 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2597 return result;
2598 } else {
2599 return b < a ? b : a;
2600 }
2601 }
2602
2603 template <typename T>
FPUMax(T a,T b)2604 static T FPUMax(T a, T b) {
2605 T result;
2606 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
2607 return result;
2608 } else {
2609 return b > a ? b : a;
2610 }
2611 }
2612
2613 template <typename T>
FPUMinA(T a,T b)2614 static T FPUMinA(T a, T b) {
2615 T result;
2616 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2617 if (FPAbs(a) < FPAbs(b)) {
2618 result = a;
2619 } else if (FPAbs(b) < FPAbs(a)) {
2620 result = b;
2621 } else {
2622 result = a < b ? a : b;
2623 }
2624 }
2625 return result;
2626 }
2627
2628 template <typename T>
FPUMaxA(T a,T b)2629 static T FPUMaxA(T a, T b) {
2630 T result;
2631 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2632 if (FPAbs(a) > FPAbs(b)) {
2633 result = a;
2634 } else if (FPAbs(b) > FPAbs(a)) {
2635 result = b;
2636 } else {
2637 result = a > b ? a : b;
2638 }
2639 }
2640 return result;
2641 }
2642
2643 enum class KeepSign : bool { no = false, yes };
2644
2645 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2646 int>::type = 0>
FPUCanonalizeNaNArg(T result,T arg,KeepSign keepSign=KeepSign::no)2647 T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2648 DCHECK(std::isnan(arg));
2649 T qNaN = std::numeric_limits<T>::quiet_NaN();
2650 if (keepSign == KeepSign::yes) {
2651 return std::copysign(qNaN, result);
2652 }
2653 return qNaN;
2654 }
2655
2656 template <typename T>
FPUCanonalizeNaNArgs(T result,KeepSign keepSign,T first)2657 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2658 if (std::isnan(first)) {
2659 return FPUCanonalizeNaNArg(result, first, keepSign);
2660 }
2661 return result;
2662 }
2663
2664 template <typename T, typename... Args>
FPUCanonalizeNaNArgs(T result,KeepSign keepSign,T first,Args...args)2665 T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2666 if (std::isnan(first)) {
2667 return FPUCanonalizeNaNArg(result, first, keepSign);
2668 }
2669 return FPUCanonalizeNaNArgs(result, keepSign, args...);
2670 }
2671
2672 template <typename Func, typename T, typename... Args>
FPUCanonalizeOperation(Func f,T first,Args...args)2673 T FPUCanonalizeOperation(Func f, T first, Args... args) {
2674 return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2675 }
2676
2677 template <typename Func, typename T, typename... Args>
FPUCanonalizeOperation(Func f,KeepSign keepSign,T first,Args...args)2678 T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2679 T result = f(first, args...);
2680 if (std::isnan(result)) {
2681 result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2682 }
2683 return result;
2684 }
2685
2686 // Handle execution based on instruction types.
2687
DecodeTypeRegisterSRsType()2688 void Simulator::DecodeTypeRegisterSRsType() {
2689 float fs, ft, fd;
2690 fs = get_fpu_register_float(fs_reg());
2691 ft = get_fpu_register_float(ft_reg());
2692 fd = get_fpu_register_float(fd_reg());
2693 int32_t ft_int = bit_cast<int32_t>(ft);
2694 int32_t fd_int = bit_cast<int32_t>(fd);
2695 uint32_t cc, fcsr_cc;
2696 cc = instr_.FCccValue();
2697 fcsr_cc = get_fcsr_condition_bit(cc);
2698 switch (instr_.FunctionFieldRaw()) {
2699 case RINT: {
2700 DCHECK_EQ(kArchVariant, kMips64r6);
2701 float result, temp_result;
2702 double temp;
2703 float upper = std::ceil(fs);
2704 float lower = std::floor(fs);
2705 switch (get_fcsr_rounding_mode()) {
2706 case kRoundToNearest:
2707 if (upper - fs < fs - lower) {
2708 result = upper;
2709 } else if (upper - fs > fs - lower) {
2710 result = lower;
2711 } else {
2712 temp_result = upper / 2;
2713 float reminder = modf(temp_result, &temp);
2714 if (reminder == 0) {
2715 result = upper;
2716 } else {
2717 result = lower;
2718 }
2719 }
2720 break;
2721 case kRoundToZero:
2722 result = (fs > 0 ? lower : upper);
2723 break;
2724 case kRoundToPlusInf:
2725 result = upper;
2726 break;
2727 case kRoundToMinusInf:
2728 result = lower;
2729 break;
2730 }
2731 SetFPUFloatResult(fd_reg(), result);
2732 if (result != fs) {
2733 set_fcsr_bit(kFCSRInexactFlagBit, true);
2734 }
2735 break;
2736 }
2737 case ADD_S:
2738 SetFPUFloatResult(
2739 fd_reg(),
2740 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
2741 fs, ft));
2742 break;
2743 case SUB_S:
2744 SetFPUFloatResult(
2745 fd_reg(),
2746 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
2747 fs, ft));
2748 break;
2749 case MADDF_S:
2750 DCHECK_EQ(kArchVariant, kMips64r6);
2751 SetFPUFloatResult(fd_reg(), std::fma(fs, ft, fd));
2752 break;
2753 case MSUBF_S:
2754 DCHECK_EQ(kArchVariant, kMips64r6);
2755 SetFPUFloatResult(fd_reg(), std::fma(-fs, ft, fd));
2756 break;
2757 case MUL_S:
2758 SetFPUFloatResult(
2759 fd_reg(),
2760 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
2761 fs, ft));
2762 break;
2763 case DIV_S:
2764 SetFPUFloatResult(
2765 fd_reg(),
2766 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
2767 fs, ft));
2768 break;
2769 case ABS_S:
2770 SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
2771 [](float fs) { return FPAbs(fs); }, fs));
2772 break;
2773 case MOV_S:
2774 SetFPUFloatResult(fd_reg(), fs);
2775 break;
2776 case NEG_S:
2777 SetFPUFloatResult(fd_reg(),
2778 FPUCanonalizeOperation([](float src) { return -src; },
2779 KeepSign::yes, fs));
2780 break;
2781 case SQRT_S:
2782 SetFPUFloatResult(
2783 fd_reg(),
2784 FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs));
2785 break;
2786 case RSQRT_S:
2787 SetFPUFloatResult(
2788 fd_reg(), FPUCanonalizeOperation(
2789 [](float src) { return 1.0 / std::sqrt(src); }, fs));
2790 break;
2791 case RECIP_S:
2792 SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
2793 [](float src) { return 1.0 / src; }, fs));
2794 break;
2795 case C_F_D:
2796 set_fcsr_bit(fcsr_cc, false);
2797 TraceRegWr(test_fcsr_bit(fcsr_cc));
2798 break;
2799 case C_UN_D:
2800 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2801 TraceRegWr(test_fcsr_bit(fcsr_cc));
2802 break;
2803 case C_EQ_D:
2804 set_fcsr_bit(fcsr_cc, (fs == ft));
2805 TraceRegWr(test_fcsr_bit(fcsr_cc));
2806 break;
2807 case C_UEQ_D:
2808 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2809 TraceRegWr(test_fcsr_bit(fcsr_cc));
2810 break;
2811 case C_OLT_D:
2812 set_fcsr_bit(fcsr_cc, (fs < ft));
2813 TraceRegWr(test_fcsr_bit(fcsr_cc));
2814 break;
2815 case C_ULT_D:
2816 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2817 TraceRegWr(test_fcsr_bit(fcsr_cc));
2818 break;
2819 case C_OLE_D:
2820 set_fcsr_bit(fcsr_cc, (fs <= ft));
2821 TraceRegWr(test_fcsr_bit(fcsr_cc));
2822 break;
2823 case C_ULE_D:
2824 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2825 TraceRegWr(test_fcsr_bit(fcsr_cc));
2826 break;
2827 case CVT_D_S:
2828 SetFPUDoubleResult(fd_reg(), static_cast<double>(fs));
2829 break;
2830 case CLASS_S: { // Mips64r6 instruction
2831 // Convert float input to uint32_t for easier bit manipulation
2832 uint32_t classed = bit_cast<uint32_t>(fs);
2833
2834 // Extracting sign, exponent and mantissa from the input float
2835 uint32_t sign = (classed >> 31) & 1;
2836 uint32_t exponent = (classed >> 23) & 0x000000FF;
2837 uint32_t mantissa = classed & 0x007FFFFF;
2838 uint32_t result;
2839 float fResult;
2840
2841 // Setting flags if input float is negative infinity,
2842 // positive infinity, negative zero or positive zero
2843 bool negInf = (classed == 0xFF800000);
2844 bool posInf = (classed == 0x7F800000);
2845 bool negZero = (classed == 0x80000000);
2846 bool posZero = (classed == 0x00000000);
2847
2848 bool signalingNan;
2849 bool quietNan;
2850 bool negSubnorm;
2851 bool posSubnorm;
2852 bool negNorm;
2853 bool posNorm;
2854
2855 // Setting flags if float is NaN
2856 signalingNan = false;
2857 quietNan = false;
2858 if (!negInf && !posInf && (exponent == 0xFF)) {
2859 quietNan = ((mantissa & 0x00200000) == 0) &&
2860 ((mantissa & (0x00200000 - 1)) == 0);
2861 signalingNan = !quietNan;
2862 }
2863
2864 // Setting flags if float is subnormal number
2865 posSubnorm = false;
2866 negSubnorm = false;
2867 if ((exponent == 0) && (mantissa != 0)) {
2868 DCHECK(sign == 0 || sign == 1);
2869 posSubnorm = (sign == 0);
2870 negSubnorm = (sign == 1);
2871 }
2872
2873 // Setting flags if float is normal number
2874 posNorm = false;
2875 negNorm = false;
2876 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2877 !quietNan && !negZero && !posZero) {
2878 DCHECK(sign == 0 || sign == 1);
2879 posNorm = (sign == 0);
2880 negNorm = (sign == 1);
2881 }
2882
2883 // Calculating result according to description of CLASS.S instruction
2884 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2885 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2886 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2887
2888 DCHECK_NE(result, 0);
2889
2890 fResult = bit_cast<float>(result);
2891 SetFPUFloatResult(fd_reg(), fResult);
2892 break;
2893 }
2894 case CVT_L_S: {
2895 float rounded;
2896 int64_t result;
2897 round64_according_to_fcsr(fs, &rounded, &result, fs);
2898 SetFPUResult(fd_reg(), result);
2899 if (set_fcsr_round64_error(fs, rounded)) {
2900 set_fpu_register_invalid_result64(fs, rounded);
2901 }
2902 break;
2903 }
2904 case CVT_W_S: {
2905 float rounded;
2906 int32_t result;
2907 round_according_to_fcsr(fs, &rounded, &result, fs);
2908 SetFPUWordResult(fd_reg(), result);
2909 if (set_fcsr_round_error(fs, rounded)) {
2910 set_fpu_register_word_invalid_result(fs, rounded);
2911 }
2912 break;
2913 }
2914 case TRUNC_W_S: { // Truncate single to word (round towards 0).
2915 float rounded = trunc(fs);
2916 int32_t result = static_cast<int32_t>(rounded);
2917 SetFPUWordResult(fd_reg(), result);
2918 if (set_fcsr_round_error(fs, rounded)) {
2919 set_fpu_register_word_invalid_result(fs, rounded);
2920 }
2921 } break;
2922 case TRUNC_L_S: { // Mips64r2 instruction.
2923 float rounded = trunc(fs);
2924 int64_t result = static_cast<int64_t>(rounded);
2925 SetFPUResult(fd_reg(), result);
2926 if (set_fcsr_round64_error(fs, rounded)) {
2927 set_fpu_register_invalid_result64(fs, rounded);
2928 }
2929 break;
2930 }
2931 case ROUND_W_S: {
2932 float rounded = std::floor(fs + 0.5);
2933 int32_t result = static_cast<int32_t>(rounded);
2934 if ((result & 1) != 0 && result - fs == 0.5) {
2935 // If the number is halfway between two integers,
2936 // round to the even one.
2937 result--;
2938 }
2939 SetFPUWordResult(fd_reg(), result);
2940 if (set_fcsr_round_error(fs, rounded)) {
2941 set_fpu_register_word_invalid_result(fs, rounded);
2942 }
2943 break;
2944 }
2945 case ROUND_L_S: { // Mips64r2 instruction.
2946 float rounded = std::floor(fs + 0.5);
2947 int64_t result = static_cast<int64_t>(rounded);
2948 if ((result & 1) != 0 && result - fs == 0.5) {
2949 // If the number is halfway between two integers,
2950 // round to the even one.
2951 result--;
2952 }
2953 int64_t i64 = static_cast<int64_t>(result);
2954 SetFPUResult(fd_reg(), i64);
2955 if (set_fcsr_round64_error(fs, rounded)) {
2956 set_fpu_register_invalid_result64(fs, rounded);
2957 }
2958 break;
2959 }
2960 case FLOOR_L_S: { // Mips64r2 instruction.
2961 float rounded = floor(fs);
2962 int64_t result = static_cast<int64_t>(rounded);
2963 SetFPUResult(fd_reg(), result);
2964 if (set_fcsr_round64_error(fs, rounded)) {
2965 set_fpu_register_invalid_result64(fs, rounded);
2966 }
2967 break;
2968 }
2969 case FLOOR_W_S: // Round double to word towards negative infinity.
2970 {
2971 float rounded = std::floor(fs);
2972 int32_t result = static_cast<int32_t>(rounded);
2973 SetFPUWordResult(fd_reg(), result);
2974 if (set_fcsr_round_error(fs, rounded)) {
2975 set_fpu_register_word_invalid_result(fs, rounded);
2976 }
2977 } break;
2978 case CEIL_W_S: // Round double to word towards positive infinity.
2979 {
2980 float rounded = std::ceil(fs);
2981 int32_t result = static_cast<int32_t>(rounded);
2982 SetFPUWordResult(fd_reg(), result);
2983 if (set_fcsr_round_error(fs, rounded)) {
2984 set_fpu_register_invalid_result(fs, rounded);
2985 }
2986 } break;
2987 case CEIL_L_S: { // Mips64r2 instruction.
2988 float rounded = ceil(fs);
2989 int64_t result = static_cast<int64_t>(rounded);
2990 SetFPUResult(fd_reg(), result);
2991 if (set_fcsr_round64_error(fs, rounded)) {
2992 set_fpu_register_invalid_result64(fs, rounded);
2993 }
2994 break;
2995 }
2996 case MINA:
2997 DCHECK_EQ(kArchVariant, kMips64r6);
2998 SetFPUFloatResult(fd_reg(), FPUMinA(ft, fs));
2999 break;
3000 case MAXA:
3001 DCHECK_EQ(kArchVariant, kMips64r6);
3002 SetFPUFloatResult(fd_reg(), FPUMaxA(ft, fs));
3003 break;
3004 case MIN:
3005 DCHECK_EQ(kArchVariant, kMips64r6);
3006 SetFPUFloatResult(fd_reg(), FPUMin(ft, fs));
3007 break;
3008 case MAX:
3009 DCHECK_EQ(kArchVariant, kMips64r6);
3010 SetFPUFloatResult(fd_reg(), FPUMax(ft, fs));
3011 break;
3012 case SEL:
3013 DCHECK_EQ(kArchVariant, kMips64r6);
3014 SetFPUFloatResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3015 break;
3016 case SELEQZ_C:
3017 DCHECK_EQ(kArchVariant, kMips64r6);
3018 SetFPUFloatResult(fd_reg(), (ft_int & 0x1) == 0
3019 ? get_fpu_register_float(fs_reg())
3020 : 0.0);
3021 break;
3022 case SELNEZ_C:
3023 DCHECK_EQ(kArchVariant, kMips64r6);
3024 SetFPUFloatResult(fd_reg(), (ft_int & 0x1) != 0
3025 ? get_fpu_register_float(fs_reg())
3026 : 0.0);
3027 break;
3028 case MOVZ_C: {
3029 DCHECK_EQ(kArchVariant, kMips64r2);
3030 if (rt() == 0) {
3031 SetFPUFloatResult(fd_reg(), fs);
3032 }
3033 break;
3034 }
3035 case MOVN_C: {
3036 DCHECK_EQ(kArchVariant, kMips64r2);
3037 if (rt() != 0) {
3038 SetFPUFloatResult(fd_reg(), fs);
3039 }
3040 break;
3041 }
3042 case MOVF: {
3043 // Same function field for MOVT.D and MOVF.D
3044 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3045 ft_cc = get_fcsr_condition_bit(ft_cc);
3046
3047 if (instr_.Bit(16)) { // Read Tf bit.
3048 // MOVT.D
3049 if (test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3050 } else {
3051 // MOVF.D
3052 if (!test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3053 }
3054 break;
3055 }
3056 default:
3057 // TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3058 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3059 UNREACHABLE();
3060 }
3061 }
3062
DecodeTypeRegisterDRsType()3063 void Simulator::DecodeTypeRegisterDRsType() {
3064 double ft, fs, fd;
3065 uint32_t cc, fcsr_cc;
3066 fs = get_fpu_register_double(fs_reg());
3067 ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
3068 : 0.0;
3069 fd = get_fpu_register_double(fd_reg());
3070 cc = instr_.FCccValue();
3071 fcsr_cc = get_fcsr_condition_bit(cc);
3072 int64_t ft_int = bit_cast<int64_t>(ft);
3073 int64_t fd_int = bit_cast<int64_t>(fd);
3074 switch (instr_.FunctionFieldRaw()) {
3075 case RINT: {
3076 DCHECK_EQ(kArchVariant, kMips64r6);
3077 double result, temp, temp_result;
3078 double upper = std::ceil(fs);
3079 double lower = std::floor(fs);
3080 switch (get_fcsr_rounding_mode()) {
3081 case kRoundToNearest:
3082 if (upper - fs < fs - lower) {
3083 result = upper;
3084 } else if (upper - fs > fs - lower) {
3085 result = lower;
3086 } else {
3087 temp_result = upper / 2;
3088 double reminder = modf(temp_result, &temp);
3089 if (reminder == 0) {
3090 result = upper;
3091 } else {
3092 result = lower;
3093 }
3094 }
3095 break;
3096 case kRoundToZero:
3097 result = (fs > 0 ? lower : upper);
3098 break;
3099 case kRoundToPlusInf:
3100 result = upper;
3101 break;
3102 case kRoundToMinusInf:
3103 result = lower;
3104 break;
3105 }
3106 SetFPUDoubleResult(fd_reg(), result);
3107 if (result != fs) {
3108 set_fcsr_bit(kFCSRInexactFlagBit, true);
3109 }
3110 break;
3111 }
3112 case SEL:
3113 DCHECK_EQ(kArchVariant, kMips64r6);
3114 SetFPUDoubleResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3115 break;
3116 case SELEQZ_C:
3117 DCHECK_EQ(kArchVariant, kMips64r6);
3118 SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
3119 break;
3120 case SELNEZ_C:
3121 DCHECK_EQ(kArchVariant, kMips64r6);
3122 SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
3123 break;
3124 case MOVZ_C: {
3125 DCHECK_EQ(kArchVariant, kMips64r2);
3126 if (rt() == 0) {
3127 SetFPUDoubleResult(fd_reg(), fs);
3128 }
3129 break;
3130 }
3131 case MOVN_C: {
3132 DCHECK_EQ(kArchVariant, kMips64r2);
3133 if (rt() != 0) {
3134 SetFPUDoubleResult(fd_reg(), fs);
3135 }
3136 break;
3137 }
3138 case MOVF: {
3139 // Same function field for MOVT.D and MOVF.D
3140 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3141 ft_cc = get_fcsr_condition_bit(ft_cc);
3142 if (instr_.Bit(16)) { // Read Tf bit.
3143 // MOVT.D
3144 if (test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
3145 } else {
3146 // MOVF.D
3147 if (!test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
3148 }
3149 break;
3150 }
3151 case MINA:
3152 DCHECK_EQ(kArchVariant, kMips64r6);
3153 SetFPUDoubleResult(fd_reg(), FPUMinA(ft, fs));
3154 break;
3155 case MAXA:
3156 DCHECK_EQ(kArchVariant, kMips64r6);
3157 SetFPUDoubleResult(fd_reg(), FPUMaxA(ft, fs));
3158 break;
3159 case MIN:
3160 DCHECK_EQ(kArchVariant, kMips64r6);
3161 SetFPUDoubleResult(fd_reg(), FPUMin(ft, fs));
3162 break;
3163 case MAX:
3164 DCHECK_EQ(kArchVariant, kMips64r6);
3165 SetFPUDoubleResult(fd_reg(), FPUMax(ft, fs));
3166 break;
3167 case ADD_D:
3168 SetFPUDoubleResult(
3169 fd_reg(),
3170 FPUCanonalizeOperation(
3171 [](double lhs, double rhs) { return lhs + rhs; }, fs, ft));
3172 break;
3173 case SUB_D:
3174 SetFPUDoubleResult(
3175 fd_reg(),
3176 FPUCanonalizeOperation(
3177 [](double lhs, double rhs) { return lhs - rhs; }, fs, ft));
3178 break;
3179 case MADDF_D:
3180 DCHECK_EQ(kArchVariant, kMips64r6);
3181 SetFPUDoubleResult(fd_reg(), std::fma(fs, ft, fd));
3182 break;
3183 case MSUBF_D:
3184 DCHECK_EQ(kArchVariant, kMips64r6);
3185 SetFPUDoubleResult(fd_reg(), std::fma(-fs, ft, fd));
3186 break;
3187 case MUL_D:
3188 SetFPUDoubleResult(
3189 fd_reg(),
3190 FPUCanonalizeOperation(
3191 [](double lhs, double rhs) { return lhs * rhs; }, fs, ft));
3192 break;
3193 case DIV_D:
3194 SetFPUDoubleResult(
3195 fd_reg(),
3196 FPUCanonalizeOperation(
3197 [](double lhs, double rhs) { return lhs / rhs; }, fs, ft));
3198 break;
3199 case ABS_D:
3200 SetFPUDoubleResult(
3201 fd_reg(),
3202 FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs));
3203 break;
3204 case MOV_D:
3205 SetFPUDoubleResult(fd_reg(), fs);
3206 break;
3207 case NEG_D:
3208 SetFPUDoubleResult(fd_reg(),
3209 FPUCanonalizeOperation([](double src) { return -src; },
3210 KeepSign::yes, fs));
3211 break;
3212 case SQRT_D:
3213 SetFPUDoubleResult(
3214 fd_reg(),
3215 FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs));
3216 break;
3217 case RSQRT_D:
3218 SetFPUDoubleResult(
3219 fd_reg(), FPUCanonalizeOperation(
3220 [](double fs) { return 1.0 / std::sqrt(fs); }, fs));
3221 break;
3222 case RECIP_D:
3223 SetFPUDoubleResult(fd_reg(), FPUCanonalizeOperation(
3224 [](double fs) { return 1.0 / fs; }, fs));
3225 break;
3226 case C_UN_D:
3227 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
3228 TraceRegWr(test_fcsr_bit(fcsr_cc));
3229 break;
3230 case C_EQ_D:
3231 set_fcsr_bit(fcsr_cc, (fs == ft));
3232 TraceRegWr(test_fcsr_bit(fcsr_cc));
3233 break;
3234 case C_UEQ_D:
3235 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
3236 TraceRegWr(test_fcsr_bit(fcsr_cc));
3237 break;
3238 case C_OLT_D:
3239 set_fcsr_bit(fcsr_cc, (fs < ft));
3240 TraceRegWr(test_fcsr_bit(fcsr_cc));
3241 break;
3242 case C_ULT_D:
3243 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3244 TraceRegWr(test_fcsr_bit(fcsr_cc));
3245 break;
3246 case C_OLE_D:
3247 set_fcsr_bit(fcsr_cc, (fs <= ft));
3248 TraceRegWr(test_fcsr_bit(fcsr_cc));
3249 break;
3250 case C_ULE_D:
3251 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3252 TraceRegWr(test_fcsr_bit(fcsr_cc));
3253 break;
3254 case CVT_W_D: { // Convert double to word.
3255 double rounded;
3256 int32_t result;
3257 round_according_to_fcsr(fs, &rounded, &result, fs);
3258 SetFPUWordResult(fd_reg(), result);
3259 if (set_fcsr_round_error(fs, rounded)) {
3260 set_fpu_register_word_invalid_result(fs, rounded);
3261 }
3262 break;
3263 }
3264 case ROUND_W_D: // Round double to word (round half to even).
3265 {
3266 double rounded = std::floor(fs + 0.5);
3267 int32_t result = static_cast<int32_t>(rounded);
3268 if ((result & 1) != 0 && result - fs == 0.5) {
3269 // If the number is halfway between two integers,
3270 // round to the even one.
3271 result--;
3272 }
3273 SetFPUWordResult(fd_reg(), result);
3274 if (set_fcsr_round_error(fs, rounded)) {
3275 set_fpu_register_invalid_result(fs, rounded);
3276 }
3277 } break;
3278 case TRUNC_W_D: // Truncate double to word (round towards 0).
3279 {
3280 double rounded = trunc(fs);
3281 int32_t result = static_cast<int32_t>(rounded);
3282 SetFPUWordResult(fd_reg(), result);
3283 if (set_fcsr_round_error(fs, rounded)) {
3284 set_fpu_register_invalid_result(fs, rounded);
3285 }
3286 } break;
3287 case FLOOR_W_D: // Round double to word towards negative infinity.
3288 {
3289 double rounded = std::floor(fs);
3290 int32_t result = static_cast<int32_t>(rounded);
3291 SetFPUWordResult(fd_reg(), result);
3292 if (set_fcsr_round_error(fs, rounded)) {
3293 set_fpu_register_invalid_result(fs, rounded);
3294 }
3295 } break;
3296 case CEIL_W_D: // Round double to word towards positive infinity.
3297 {
3298 double rounded = std::ceil(fs);
3299 int32_t result = static_cast<int32_t>(rounded);
3300 SetFPUWordResult2(fd_reg(), result);
3301 if (set_fcsr_round_error(fs, rounded)) {
3302 set_fpu_register_invalid_result(fs, rounded);
3303 }
3304 } break;
3305 case CVT_S_D: // Convert double to float (single).
3306 SetFPUFloatResult(fd_reg(), static_cast<float>(fs));
3307 break;
3308 case CVT_L_D: { // Mips64r2: Truncate double to 64-bit long-word.
3309 double rounded;
3310 int64_t result;
3311 round64_according_to_fcsr(fs, &rounded, &result, fs);
3312 SetFPUResult(fd_reg(), result);
3313 if (set_fcsr_round64_error(fs, rounded)) {
3314 set_fpu_register_invalid_result64(fs, rounded);
3315 }
3316 break;
3317 }
3318 case ROUND_L_D: { // Mips64r2 instruction.
3319 double rounded = std::floor(fs + 0.5);
3320 int64_t result = static_cast<int64_t>(rounded);
3321 if ((result & 1) != 0 && result - fs == 0.5) {
3322 // If the number is halfway between two integers,
3323 // round to the even one.
3324 result--;
3325 }
3326 int64_t i64 = static_cast<int64_t>(result);
3327 SetFPUResult(fd_reg(), i64);
3328 if (set_fcsr_round64_error(fs, rounded)) {
3329 set_fpu_register_invalid_result64(fs, rounded);
3330 }
3331 break;
3332 }
3333 case TRUNC_L_D: { // Mips64r2 instruction.
3334 double rounded = trunc(fs);
3335 int64_t result = static_cast<int64_t>(rounded);
3336 SetFPUResult(fd_reg(), result);
3337 if (set_fcsr_round64_error(fs, rounded)) {
3338 set_fpu_register_invalid_result64(fs, rounded);
3339 }
3340 break;
3341 }
3342 case FLOOR_L_D: { // Mips64r2 instruction.
3343 double rounded = floor(fs);
3344 int64_t result = static_cast<int64_t>(rounded);
3345 SetFPUResult(fd_reg(), result);
3346 if (set_fcsr_round64_error(fs, rounded)) {
3347 set_fpu_register_invalid_result64(fs, rounded);
3348 }
3349 break;
3350 }
3351 case CEIL_L_D: { // Mips64r2 instruction.
3352 double rounded = ceil(fs);
3353 int64_t result = static_cast<int64_t>(rounded);
3354 SetFPUResult(fd_reg(), result);
3355 if (set_fcsr_round64_error(fs, rounded)) {
3356 set_fpu_register_invalid_result64(fs, rounded);
3357 }
3358 break;
3359 }
3360 case CLASS_D: { // Mips64r6 instruction
3361 // Convert double input to uint64_t for easier bit manipulation
3362 uint64_t classed = bit_cast<uint64_t>(fs);
3363
3364 // Extracting sign, exponent and mantissa from the input double
3365 uint32_t sign = (classed >> 63) & 1;
3366 uint32_t exponent = (classed >> 52) & 0x00000000000007FF;
3367 uint64_t mantissa = classed & 0x000FFFFFFFFFFFFF;
3368 uint64_t result;
3369 double dResult;
3370
3371 // Setting flags if input double is negative infinity,
3372 // positive infinity, negative zero or positive zero
3373 bool negInf = (classed == 0xFFF0000000000000);
3374 bool posInf = (classed == 0x7FF0000000000000);
3375 bool negZero = (classed == 0x8000000000000000);
3376 bool posZero = (classed == 0x0000000000000000);
3377
3378 bool signalingNan;
3379 bool quietNan;
3380 bool negSubnorm;
3381 bool posSubnorm;
3382 bool negNorm;
3383 bool posNorm;
3384
3385 // Setting flags if double is NaN
3386 signalingNan = false;
3387 quietNan = false;
3388 if (!negInf && !posInf && exponent == 0x7FF) {
3389 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
3390 ((mantissa & (0x0008000000000000 - 1)) == 0);
3391 signalingNan = !quietNan;
3392 }
3393
3394 // Setting flags if double is subnormal number
3395 posSubnorm = false;
3396 negSubnorm = false;
3397 if ((exponent == 0) && (mantissa != 0)) {
3398 DCHECK(sign == 0 || sign == 1);
3399 posSubnorm = (sign == 0);
3400 negSubnorm = (sign == 1);
3401 }
3402
3403 // Setting flags if double is normal number
3404 posNorm = false;
3405 negNorm = false;
3406 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3407 !quietNan && !negZero && !posZero) {
3408 DCHECK(sign == 0 || sign == 1);
3409 posNorm = (sign == 0);
3410 negNorm = (sign == 1);
3411 }
3412
3413 // Calculating result according to description of CLASS.D instruction
3414 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3415 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3416 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3417
3418 DCHECK_NE(result, 0);
3419
3420 dResult = bit_cast<double>(result);
3421 SetFPUDoubleResult(fd_reg(), dResult);
3422 break;
3423 }
3424 case C_F_D: {
3425 set_fcsr_bit(fcsr_cc, false);
3426 TraceRegWr(test_fcsr_bit(fcsr_cc));
3427 break;
3428 }
3429 default:
3430 UNREACHABLE();
3431 }
3432 }
3433
DecodeTypeRegisterWRsType()3434 void Simulator::DecodeTypeRegisterWRsType() {
3435 float fs = get_fpu_register_float(fs_reg());
3436 float ft = get_fpu_register_float(ft_reg());
3437 int64_t alu_out = 0x12345678;
3438 switch (instr_.FunctionFieldRaw()) {
3439 case CVT_S_W: // Convert word to float (single).
3440 alu_out = get_fpu_register_signed_word(fs_reg());
3441 SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
3442 break;
3443 case CVT_D_W: // Convert word to double.
3444 alu_out = get_fpu_register_signed_word(fs_reg());
3445 SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
3446 break;
3447 case CMP_AF:
3448 SetFPUWordResult2(fd_reg(), 0);
3449 break;
3450 case CMP_UN:
3451 if (std::isnan(fs) || std::isnan(ft)) {
3452 SetFPUWordResult2(fd_reg(), -1);
3453 } else {
3454 SetFPUWordResult2(fd_reg(), 0);
3455 }
3456 break;
3457 case CMP_EQ:
3458 if (fs == ft) {
3459 SetFPUWordResult2(fd_reg(), -1);
3460 } else {
3461 SetFPUWordResult2(fd_reg(), 0);
3462 }
3463 break;
3464 case CMP_UEQ:
3465 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3466 SetFPUWordResult2(fd_reg(), -1);
3467 } else {
3468 SetFPUWordResult2(fd_reg(), 0);
3469 }
3470 break;
3471 case CMP_LT:
3472 if (fs < ft) {
3473 SetFPUWordResult2(fd_reg(), -1);
3474 } else {
3475 SetFPUWordResult2(fd_reg(), 0);
3476 }
3477 break;
3478 case CMP_ULT:
3479 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3480 SetFPUWordResult2(fd_reg(), -1);
3481 } else {
3482 SetFPUWordResult2(fd_reg(), 0);
3483 }
3484 break;
3485 case CMP_LE:
3486 if (fs <= ft) {
3487 SetFPUWordResult2(fd_reg(), -1);
3488 } else {
3489 SetFPUWordResult2(fd_reg(), 0);
3490 }
3491 break;
3492 case CMP_ULE:
3493 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3494 SetFPUWordResult2(fd_reg(), -1);
3495 } else {
3496 SetFPUWordResult2(fd_reg(), 0);
3497 }
3498 break;
3499 case CMP_OR:
3500 if (!std::isnan(fs) && !std::isnan(ft)) {
3501 SetFPUWordResult2(fd_reg(), -1);
3502 } else {
3503 SetFPUWordResult2(fd_reg(), 0);
3504 }
3505 break;
3506 case CMP_UNE:
3507 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3508 SetFPUWordResult2(fd_reg(), -1);
3509 } else {
3510 SetFPUWordResult2(fd_reg(), 0);
3511 }
3512 break;
3513 case CMP_NE:
3514 if (fs != ft) {
3515 SetFPUWordResult2(fd_reg(), -1);
3516 } else {
3517 SetFPUWordResult2(fd_reg(), 0);
3518 }
3519 break;
3520 default:
3521 UNREACHABLE();
3522 }
3523 }
3524
DecodeTypeRegisterLRsType()3525 void Simulator::DecodeTypeRegisterLRsType() {
3526 double fs = get_fpu_register_double(fs_reg());
3527 double ft = get_fpu_register_double(ft_reg());
3528 int64_t i64;
3529 switch (instr_.FunctionFieldRaw()) {
3530 case CVT_D_L: // Mips32r2 instruction.
3531 i64 = get_fpu_register(fs_reg());
3532 SetFPUDoubleResult(fd_reg(), static_cast<double>(i64));
3533 break;
3534 case CVT_S_L:
3535 i64 = get_fpu_register(fs_reg());
3536 SetFPUFloatResult(fd_reg(), static_cast<float>(i64));
3537 break;
3538 case CMP_AF:
3539 SetFPUResult(fd_reg(), 0);
3540 break;
3541 case CMP_UN:
3542 if (std::isnan(fs) || std::isnan(ft)) {
3543 SetFPUResult(fd_reg(), -1);
3544 } else {
3545 SetFPUResult(fd_reg(), 0);
3546 }
3547 break;
3548 case CMP_EQ:
3549 if (fs == ft) {
3550 SetFPUResult(fd_reg(), -1);
3551 } else {
3552 SetFPUResult(fd_reg(), 0);
3553 }
3554 break;
3555 case CMP_UEQ:
3556 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3557 SetFPUResult(fd_reg(), -1);
3558 } else {
3559 SetFPUResult(fd_reg(), 0);
3560 }
3561 break;
3562 case CMP_LT:
3563 if (fs < ft) {
3564 SetFPUResult(fd_reg(), -1);
3565 } else {
3566 SetFPUResult(fd_reg(), 0);
3567 }
3568 break;
3569 case CMP_ULT:
3570 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3571 SetFPUResult(fd_reg(), -1);
3572 } else {
3573 SetFPUResult(fd_reg(), 0);
3574 }
3575 break;
3576 case CMP_LE:
3577 if (fs <= ft) {
3578 SetFPUResult(fd_reg(), -1);
3579 } else {
3580 SetFPUResult(fd_reg(), 0);
3581 }
3582 break;
3583 case CMP_ULE:
3584 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3585 SetFPUResult(fd_reg(), -1);
3586 } else {
3587 SetFPUResult(fd_reg(), 0);
3588 }
3589 break;
3590 case CMP_OR:
3591 if (!std::isnan(fs) && !std::isnan(ft)) {
3592 SetFPUResult(fd_reg(), -1);
3593 } else {
3594 SetFPUResult(fd_reg(), 0);
3595 }
3596 break;
3597 case CMP_UNE:
3598 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3599 SetFPUResult(fd_reg(), -1);
3600 } else {
3601 SetFPUResult(fd_reg(), 0);
3602 }
3603 break;
3604 case CMP_NE:
3605 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3606 SetFPUResult(fd_reg(), -1);
3607 } else {
3608 SetFPUResult(fd_reg(), 0);
3609 }
3610 break;
3611 default:
3612 UNREACHABLE();
3613 }
3614 }
3615
DecodeTypeRegisterCOP1()3616 void Simulator::DecodeTypeRegisterCOP1() {
3617 switch (instr_.RsFieldRaw()) {
3618 case BC1: // Branch on coprocessor condition.
3619 case BC1EQZ:
3620 case BC1NEZ:
3621 UNREACHABLE();
3622 case CFC1:
3623 // At the moment only FCSR is supported.
3624 DCHECK_EQ(fs_reg(), kFCSRRegister);
3625 SetResult(rt_reg(), FCSR_);
3626 break;
3627 case MFC1:
3628 set_register(rt_reg(),
3629 static_cast<int64_t>(get_fpu_register_word(fs_reg())));
3630 TraceRegWr(get_register(rt_reg()), WORD_DWORD);
3631 break;
3632 case DMFC1:
3633 SetResult(rt_reg(), get_fpu_register(fs_reg()));
3634 break;
3635 case MFHC1:
3636 SetResult(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3637 break;
3638 case CTC1: {
3639 // At the moment only FCSR is supported.
3640 DCHECK_EQ(fs_reg(), kFCSRRegister);
3641 uint32_t reg = static_cast<uint32_t>(rt());
3642 if (kArchVariant == kMips64r6) {
3643 FCSR_ = reg | kFCSRNaN2008FlagMask;
3644 } else {
3645 DCHECK_EQ(kArchVariant, kMips64r2);
3646 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3647 }
3648 TraceRegWr(FCSR_);
3649 break;
3650 }
3651 case MTC1:
3652 // Hardware writes upper 32-bits to zero on mtc1.
3653 set_fpu_register_hi_word(fs_reg(), 0);
3654 set_fpu_register_word(fs_reg(), static_cast<int32_t>(rt()));
3655 TraceRegWr(get_fpu_register(fs_reg()), FLOAT_DOUBLE);
3656 break;
3657 case DMTC1:
3658 SetFPUResult2(fs_reg(), rt());
3659 break;
3660 case MTHC1:
3661 set_fpu_register_hi_word(fs_reg(), static_cast<int32_t>(rt()));
3662 TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3663 break;
3664 case S:
3665 DecodeTypeRegisterSRsType();
3666 break;
3667 case D:
3668 DecodeTypeRegisterDRsType();
3669 break;
3670 case W:
3671 DecodeTypeRegisterWRsType();
3672 break;
3673 case L:
3674 DecodeTypeRegisterLRsType();
3675 break;
3676 default:
3677 UNREACHABLE();
3678 }
3679 }
3680
DecodeTypeRegisterCOP1X()3681 void Simulator::DecodeTypeRegisterCOP1X() {
3682 switch (instr_.FunctionFieldRaw()) {
3683 case MADD_S: {
3684 DCHECK_EQ(kArchVariant, kMips64r2);
3685 float fr, ft, fs;
3686 fr = get_fpu_register_float(fr_reg());
3687 fs = get_fpu_register_float(fs_reg());
3688 ft = get_fpu_register_float(ft_reg());
3689 SetFPUFloatResult(fd_reg(), fs * ft + fr);
3690 break;
3691 }
3692 case MSUB_S: {
3693 DCHECK_EQ(kArchVariant, kMips64r2);
3694 float fr, ft, fs;
3695 fr = get_fpu_register_float(fr_reg());
3696 fs = get_fpu_register_float(fs_reg());
3697 ft = get_fpu_register_float(ft_reg());
3698 SetFPUFloatResult(fd_reg(), fs * ft - fr);
3699 break;
3700 }
3701 case MADD_D: {
3702 DCHECK_EQ(kArchVariant, kMips64r2);
3703 double fr, ft, fs;
3704 fr = get_fpu_register_double(fr_reg());
3705 fs = get_fpu_register_double(fs_reg());
3706 ft = get_fpu_register_double(ft_reg());
3707 SetFPUDoubleResult(fd_reg(), fs * ft + fr);
3708 break;
3709 }
3710 case MSUB_D: {
3711 DCHECK_EQ(kArchVariant, kMips64r2);
3712 double fr, ft, fs;
3713 fr = get_fpu_register_double(fr_reg());
3714 fs = get_fpu_register_double(fs_reg());
3715 ft = get_fpu_register_double(ft_reg());
3716 SetFPUDoubleResult(fd_reg(), fs * ft - fr);
3717 break;
3718 }
3719 default:
3720 UNREACHABLE();
3721 }
3722 }
3723
DecodeTypeRegisterSPECIAL()3724 void Simulator::DecodeTypeRegisterSPECIAL() {
3725 int64_t i64hilo;
3726 uint64_t u64hilo;
3727 int64_t alu_out;
3728 bool do_interrupt = false;
3729
3730 switch (instr_.FunctionFieldRaw()) {
3731 case SELEQZ_S:
3732 DCHECK_EQ(kArchVariant, kMips64r6);
3733 SetResult(rd_reg(), rt() == 0 ? rs() : 0);
3734 break;
3735 case SELNEZ_S:
3736 DCHECK_EQ(kArchVariant, kMips64r6);
3737 SetResult(rd_reg(), rt() != 0 ? rs() : 0);
3738 break;
3739 case JR: {
3740 int64_t next_pc = rs();
3741 int64_t current_pc = get_pc();
3742 Instruction* branch_delay_instr =
3743 reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3744 BranchDelayInstructionDecode(branch_delay_instr);
3745 set_pc(next_pc);
3746 pc_modified_ = true;
3747 break;
3748 }
3749 case JALR: {
3750 int64_t next_pc = rs();
3751 int64_t current_pc = get_pc();
3752 int32_t return_addr_reg = rd_reg();
3753 Instruction* branch_delay_instr =
3754 reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3755 BranchDelayInstructionDecode(branch_delay_instr);
3756 set_register(return_addr_reg, current_pc + 2 * kInstrSize);
3757 set_pc(next_pc);
3758 pc_modified_ = true;
3759 break;
3760 }
3761 case SLL:
3762 SetResult(rd_reg(), static_cast<int32_t>(rt()) << sa());
3763 break;
3764 case DSLL:
3765 SetResult(rd_reg(), rt() << sa());
3766 break;
3767 case DSLL32:
3768 SetResult(rd_reg(), rt() << sa() << 32);
3769 break;
3770 case SRL:
3771 if (rs_reg() == 0) {
3772 // Regular logical right shift of a word by a fixed number of
3773 // bits instruction. RS field is always equal to 0.
3774 // Sign-extend the 32-bit result.
3775 alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u()) >> sa());
3776 } else if (rs_reg() == 1) {
3777 // Logical right-rotate of a word by a fixed number of bits. This
3778 // is special case of SRL instruction, added in MIPS32 Release 2.
3779 // RS field is equal to 00001.
3780 alu_out = static_cast<int32_t>(
3781 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3782 static_cast<const uint32_t>(sa())));
3783 } else {
3784 UNREACHABLE();
3785 }
3786 SetResult(rd_reg(), alu_out);
3787 break;
3788 case DSRL:
3789 if (rs_reg() == 0) {
3790 // Regular logical right shift of a word by a fixed number of
3791 // bits instruction. RS field is always equal to 0.
3792 // Sign-extend the 64-bit result.
3793 alu_out = static_cast<int64_t>(rt_u() >> sa());
3794 } else if (rs_reg() == 1) {
3795 // Logical right-rotate of a word by a fixed number of bits. This
3796 // is special case of SRL instruction, added in MIPS32 Release 2.
3797 // RS field is equal to 00001.
3798 alu_out = static_cast<int64_t>(base::bits::RotateRight64(rt_u(), sa()));
3799 } else {
3800 UNREACHABLE();
3801 }
3802 SetResult(rd_reg(), alu_out);
3803 break;
3804 case DSRL32:
3805 if (rs_reg() == 0) {
3806 // Regular logical right shift of a word by a fixed number of
3807 // bits instruction. RS field is always equal to 0.
3808 // Sign-extend the 64-bit result.
3809 alu_out = static_cast<int64_t>(rt_u() >> sa() >> 32);
3810 } else if (rs_reg() == 1) {
3811 // Logical right-rotate of a word by a fixed number of bits. This
3812 // is special case of SRL instruction, added in MIPS32 Release 2.
3813 // RS field is equal to 00001.
3814 alu_out =
3815 static_cast<int64_t>(base::bits::RotateRight64(rt_u(), sa() + 32));
3816 } else {
3817 UNREACHABLE();
3818 }
3819 SetResult(rd_reg(), alu_out);
3820 break;
3821 case SRA:
3822 SetResult(rd_reg(), (int32_t)rt() >> sa());
3823 break;
3824 case DSRA:
3825 SetResult(rd_reg(), rt() >> sa());
3826 break;
3827 case DSRA32:
3828 SetResult(rd_reg(), rt() >> sa() >> 32);
3829 break;
3830 case SLLV:
3831 SetResult(rd_reg(), (int32_t)rt() << rs());
3832 break;
3833 case DSLLV:
3834 SetResult(rd_reg(), rt() << rs());
3835 break;
3836 case SRLV:
3837 if (sa() == 0) {
3838 // Regular logical right-shift of a word by a variable number of
3839 // bits instruction. SA field is always equal to 0.
3840 alu_out = static_cast<int32_t>((uint32_t)rt_u() >> rs());
3841 } else {
3842 // Logical right-rotate of a word by a variable number of bits.
3843 // This is special case od SRLV instruction, added in MIPS32
3844 // Release 2. SA field is equal to 00001.
3845 alu_out = static_cast<int32_t>(
3846 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3847 static_cast<const uint32_t>(rs_u())));
3848 }
3849 SetResult(rd_reg(), alu_out);
3850 break;
3851 case DSRLV:
3852 if (sa() == 0) {
3853 // Regular logical right-shift of a word by a variable number of
3854 // bits instruction. SA field is always equal to 0.
3855 alu_out = static_cast<int64_t>(rt_u() >> rs());
3856 } else {
3857 // Logical right-rotate of a word by a variable number of bits.
3858 // This is special case od SRLV instruction, added in MIPS32
3859 // Release 2. SA field is equal to 00001.
3860 alu_out =
3861 static_cast<int64_t>(base::bits::RotateRight64(rt_u(), rs_u()));
3862 }
3863 SetResult(rd_reg(), alu_out);
3864 break;
3865 case SRAV:
3866 SetResult(rd_reg(), (int32_t)rt() >> rs());
3867 break;
3868 case DSRAV:
3869 SetResult(rd_reg(), rt() >> rs());
3870 break;
3871 case LSA: {
3872 DCHECK_EQ(kArchVariant, kMips64r6);
3873 int8_t sa = lsa_sa() + 1;
3874 int32_t _rt = static_cast<int32_t>(rt());
3875 int32_t _rs = static_cast<int32_t>(rs());
3876 int32_t res = _rs << sa;
3877 res += _rt;
3878 SetResult(rd_reg(), static_cast<int64_t>(res));
3879 break;
3880 }
3881 case DLSA:
3882 DCHECK_EQ(kArchVariant, kMips64r6);
3883 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3884 break;
3885 case MFHI: // MFHI == CLZ on R6.
3886 if (kArchVariant != kMips64r6) {
3887 DCHECK_EQ(sa(), 0);
3888 alu_out = get_register(HI);
3889 } else {
3890 // MIPS spec: If no bits were set in GPR rs(), the result written to
3891 // GPR rd() is 32.
3892 DCHECK_EQ(sa(), 1);
3893 alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u()));
3894 }
3895 SetResult(rd_reg(), alu_out);
3896 break;
3897 case MFLO: // MFLO == DCLZ on R6.
3898 if (kArchVariant != kMips64r6) {
3899 DCHECK_EQ(sa(), 0);
3900 alu_out = get_register(LO);
3901 } else {
3902 // MIPS spec: If no bits were set in GPR rs(), the result written to
3903 // GPR rd() is 64.
3904 DCHECK_EQ(sa(), 1);
3905 alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rs_u()));
3906 }
3907 SetResult(rd_reg(), alu_out);
3908 break;
3909 // Instructions using HI and LO registers.
3910 case MULT: { // MULT == D_MUL_MUH.
3911 int32_t rs_lo = static_cast<int32_t>(rs());
3912 int32_t rt_lo = static_cast<int32_t>(rt());
3913 i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
3914 if (kArchVariant != kMips64r6) {
3915 set_register(LO, static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3916 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3917 } else {
3918 switch (sa()) {
3919 case MUL_OP:
3920 SetResult(rd_reg(), static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3921 break;
3922 case MUH_OP:
3923 SetResult(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3924 break;
3925 default:
3926 UNIMPLEMENTED_MIPS();
3927 break;
3928 }
3929 }
3930 break;
3931 }
3932 case MULTU:
3933 u64hilo = static_cast<uint64_t>(rs_u() & 0xFFFFFFFF) *
3934 static_cast<uint64_t>(rt_u() & 0xFFFFFFFF);
3935 if (kArchVariant != kMips64r6) {
3936 set_register(LO, static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3937 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3938 } else {
3939 switch (sa()) {
3940 case MUL_OP:
3941 SetResult(rd_reg(), static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3942 break;
3943 case MUH_OP:
3944 SetResult(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3945 break;
3946 default:
3947 UNIMPLEMENTED_MIPS();
3948 break;
3949 }
3950 }
3951 break;
3952 case DMULT: // DMULT == D_MUL_MUH.
3953 if (kArchVariant != kMips64r6) {
3954 set_register(LO, rs() * rt());
3955 set_register(HI, MultiplyHighSigned(rs(), rt()));
3956 } else {
3957 switch (sa()) {
3958 case MUL_OP:
3959 SetResult(rd_reg(), rs() * rt());
3960 break;
3961 case MUH_OP:
3962 SetResult(rd_reg(), MultiplyHighSigned(rs(), rt()));
3963 break;
3964 default:
3965 UNIMPLEMENTED_MIPS();
3966 break;
3967 }
3968 }
3969 break;
3970 case DMULTU:
3971 UNIMPLEMENTED_MIPS();
3972 break;
3973 case DIV:
3974 case DDIV: {
3975 const int64_t int_min_value =
3976 instr_.FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
3977 switch (kArchVariant) {
3978 case kMips64r2:
3979 // Divide by zero and overflow was not checked in the
3980 // configuration step - div and divu do not raise exceptions. On
3981 // division by 0 the result will be UNPREDICTABLE. On overflow
3982 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3983 if (rs() == int_min_value && rt() == -1) {
3984 set_register(LO, int_min_value);
3985 set_register(HI, 0);
3986 } else if (rt() != 0) {
3987 set_register(LO, rs() / rt());
3988 set_register(HI, rs() % rt());
3989 }
3990 break;
3991 case kMips64r6:
3992 switch (sa()) {
3993 case DIV_OP:
3994 if (rs() == int_min_value && rt() == -1) {
3995 SetResult(rd_reg(), int_min_value);
3996 } else if (rt() != 0) {
3997 SetResult(rd_reg(), rs() / rt());
3998 }
3999 break;
4000 case MOD_OP:
4001 if (rs() == int_min_value && rt() == -1) {
4002 SetResult(rd_reg(), 0);
4003 } else if (rt() != 0) {
4004 SetResult(rd_reg(), rs() % rt());
4005 }
4006 break;
4007 default:
4008 UNIMPLEMENTED_MIPS();
4009 break;
4010 }
4011 break;
4012 default:
4013 break;
4014 }
4015 break;
4016 }
4017 case DIVU:
4018 switch (kArchVariant) {
4019 case kMips64r6: {
4020 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
4021 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
4022 switch (sa()) {
4023 case DIV_OP:
4024 if (rt_u_32 != 0) {
4025 SetResult(rd_reg(), rs_u_32 / rt_u_32);
4026 }
4027 break;
4028 case MOD_OP:
4029 if (rt_u() != 0) {
4030 SetResult(rd_reg(), rs_u_32 % rt_u_32);
4031 }
4032 break;
4033 default:
4034 UNIMPLEMENTED_MIPS();
4035 break;
4036 }
4037 } break;
4038 default: {
4039 if (rt_u() != 0) {
4040 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
4041 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
4042 set_register(LO, rs_u_32 / rt_u_32);
4043 set_register(HI, rs_u_32 % rt_u_32);
4044 }
4045 }
4046 }
4047 break;
4048 case DDIVU:
4049 switch (kArchVariant) {
4050 case kMips64r6: {
4051 switch (instr_.SaValue()) {
4052 case DIV_OP:
4053 if (rt_u() != 0) {
4054 SetResult(rd_reg(), rs_u() / rt_u());
4055 }
4056 break;
4057 case MOD_OP:
4058 if (rt_u() != 0) {
4059 SetResult(rd_reg(), rs_u() % rt_u());
4060 }
4061 break;
4062 default:
4063 UNIMPLEMENTED_MIPS();
4064 break;
4065 }
4066 } break;
4067 default: {
4068 if (rt_u() != 0) {
4069 set_register(LO, rs_u() / rt_u());
4070 set_register(HI, rs_u() % rt_u());
4071 }
4072 }
4073 }
4074 break;
4075 case ADD:
4076 case DADD:
4077 if (HaveSameSign(rs(), rt())) {
4078 if (rs() > 0) {
4079 if (rs() > (Registers::kMaxValue - rt())) {
4080 SignalException(kIntegerOverflow);
4081 }
4082 } else if (rs() < 0) {
4083 if (rs() < (Registers::kMinValue - rt())) {
4084 SignalException(kIntegerUnderflow);
4085 }
4086 }
4087 }
4088 SetResult(rd_reg(), rs() + rt());
4089 break;
4090 case ADDU: {
4091 int32_t alu32_out = static_cast<int32_t>(rs() + rt());
4092 // Sign-extend result of 32bit operation into 64bit register.
4093 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
4094 break;
4095 }
4096 case DADDU:
4097 SetResult(rd_reg(), rs() + rt());
4098 break;
4099 case SUB:
4100 case DSUB:
4101 if (!HaveSameSign(rs(), rt())) {
4102 if (rs() > 0) {
4103 if (rs() > (Registers::kMaxValue + rt())) {
4104 SignalException(kIntegerOverflow);
4105 }
4106 } else if (rs() < 0) {
4107 if (rs() < (Registers::kMinValue + rt())) {
4108 SignalException(kIntegerUnderflow);
4109 }
4110 }
4111 }
4112 SetResult(rd_reg(), rs() - rt());
4113 break;
4114 case SUBU: {
4115 int32_t alu32_out = static_cast<int32_t>(rs() - rt());
4116 // Sign-extend result of 32bit operation into 64bit register.
4117 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
4118 break;
4119 }
4120 case DSUBU:
4121 SetResult(rd_reg(), rs() - rt());
4122 break;
4123 case AND:
4124 SetResult(rd_reg(), rs() & rt());
4125 break;
4126 case OR:
4127 SetResult(rd_reg(), rs() | rt());
4128 break;
4129 case XOR:
4130 SetResult(rd_reg(), rs() ^ rt());
4131 break;
4132 case NOR:
4133 SetResult(rd_reg(), ~(rs() | rt()));
4134 break;
4135 case SLT:
4136 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
4137 break;
4138 case SLTU:
4139 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
4140 break;
4141 // Break and trap instructions.
4142 case BREAK:
4143 do_interrupt = true;
4144 break;
4145 case TGE:
4146 do_interrupt = rs() >= rt();
4147 break;
4148 case TGEU:
4149 do_interrupt = rs_u() >= rt_u();
4150 break;
4151 case TLT:
4152 do_interrupt = rs() < rt();
4153 break;
4154 case TLTU:
4155 do_interrupt = rs_u() < rt_u();
4156 break;
4157 case TEQ:
4158 do_interrupt = rs() == rt();
4159 break;
4160 case TNE:
4161 do_interrupt = rs() != rt();
4162 break;
4163 case SYNC:
4164 // TODO(palfia): Ignore sync instruction for now.
4165 break;
4166 // Conditional moves.
4167 case MOVN:
4168 if (rt()) {
4169 SetResult(rd_reg(), rs());
4170 }
4171 break;
4172 case MOVCI: {
4173 uint32_t cc = instr_.FBccValue();
4174 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4175 if (instr_.Bit(16)) { // Read Tf bit.
4176 if (test_fcsr_bit(fcsr_cc)) SetResult(rd_reg(), rs());
4177 } else {
4178 if (!test_fcsr_bit(fcsr_cc)) SetResult(rd_reg(), rs());
4179 }
4180 break;
4181 }
4182 case MOVZ:
4183 if (!rt()) {
4184 SetResult(rd_reg(), rs());
4185 }
4186 break;
4187 default:
4188 UNREACHABLE();
4189 }
4190 if (do_interrupt) {
4191 SoftwareInterrupt();
4192 }
4193 }
4194
DecodeTypeRegisterSPECIAL2()4195 void Simulator::DecodeTypeRegisterSPECIAL2() {
4196 int64_t alu_out;
4197 switch (instr_.FunctionFieldRaw()) {
4198 case MUL:
4199 alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u());
4200 SetResult(rd_reg(), alu_out);
4201 // HI and LO are UNPREDICTABLE after the operation.
4202 set_register(LO, Unpredictable);
4203 set_register(HI, Unpredictable);
4204 break;
4205 case CLZ:
4206 // MIPS32 spec: If no bits were set in GPR rs(), the result written to
4207 // GPR rd is 32.
4208 alu_out = base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u()));
4209 SetResult(rd_reg(), alu_out);
4210 break;
4211 case DCLZ:
4212 // MIPS64 spec: If no bits were set in GPR rs(), the result written to
4213 // GPR rd is 64.
4214 alu_out = base::bits::CountLeadingZeros64(static_cast<uint64_t>(rs_u()));
4215 SetResult(rd_reg(), alu_out);
4216 break;
4217 default:
4218 alu_out = 0x12345678;
4219 UNREACHABLE();
4220 }
4221 }
4222
DecodeTypeRegisterSPECIAL3()4223 void Simulator::DecodeTypeRegisterSPECIAL3() {
4224 int64_t alu_out;
4225 switch (instr_.FunctionFieldRaw()) {
4226 case EXT: { // Mips32r2 instruction.
4227 // Interpret rd field as 5-bit msbd of extract.
4228 uint16_t msbd = rd_reg();
4229 // Interpret sa field as 5-bit lsb of extract.
4230 uint16_t lsb = sa();
4231 uint16_t size = msbd + 1;
4232 uint64_t mask = (1ULL << size) - 1;
4233 alu_out = static_cast<int32_t>((rs_u() & (mask << lsb)) >> lsb);
4234 SetResult(rt_reg(), alu_out);
4235 break;
4236 }
4237 case DEXT: { // Mips64r2 instruction.
4238 // Interpret rd field as 5-bit msbd of extract.
4239 uint16_t msbd = rd_reg();
4240 // Interpret sa field as 5-bit lsb of extract.
4241 uint16_t lsb = sa();
4242 uint16_t size = msbd + 1;
4243 uint64_t mask = (size == 64) ? UINT64_MAX : (1ULL << size) - 1;
4244 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
4245 SetResult(rt_reg(), alu_out);
4246 break;
4247 }
4248 case DEXTM: {
4249 // Interpret rd field as 5-bit msbdminus32 of extract.
4250 uint16_t msbdminus32 = rd_reg();
4251 // Interpret sa field as 5-bit lsb of extract.
4252 uint16_t lsb = sa();
4253 uint16_t size = msbdminus32 + 1 + 32;
4254 uint64_t mask = (size == 64) ? UINT64_MAX : (1ULL << size) - 1;
4255 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
4256 SetResult(rt_reg(), alu_out);
4257 break;
4258 }
4259 case DEXTU: {
4260 // Interpret rd field as 5-bit msbd of extract.
4261 uint16_t msbd = rd_reg();
4262 // Interpret sa field as 5-bit lsbminus32 of extract and add 32 to get
4263 // lsb.
4264 uint16_t lsb = sa() + 32;
4265 uint16_t size = msbd + 1;
4266 uint64_t mask = (size == 64) ? UINT64_MAX : (1ULL << size) - 1;
4267 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
4268 SetResult(rt_reg(), alu_out);
4269 break;
4270 }
4271 case INS: { // Mips32r2 instruction.
4272 // Interpret rd field as 5-bit msb of insert.
4273 uint16_t msb = rd_reg();
4274 // Interpret sa field as 5-bit lsb of insert.
4275 uint16_t lsb = sa();
4276 uint16_t size = msb - lsb + 1;
4277 uint64_t mask = (1ULL << size) - 1;
4278 alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) |
4279 ((rs_u() & mask) << lsb));
4280 SetResult(rt_reg(), alu_out);
4281 break;
4282 }
4283 case DINS: { // Mips64r2 instruction.
4284 // Interpret rd field as 5-bit msb of insert.
4285 uint16_t msb = rd_reg();
4286 // Interpret sa field as 5-bit lsb of insert.
4287 uint16_t lsb = sa();
4288 uint16_t size = msb - lsb + 1;
4289 uint64_t mask = (1ULL << size) - 1;
4290 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4291 SetResult(rt_reg(), alu_out);
4292 break;
4293 }
4294 case DINSM: { // Mips64r2 instruction.
4295 // Interpret rd field as 5-bit msbminus32 of insert.
4296 uint16_t msbminus32 = rd_reg();
4297 // Interpret sa field as 5-bit lsb of insert.
4298 uint16_t lsb = sa();
4299 uint16_t size = msbminus32 + 32 - lsb + 1;
4300 uint64_t mask;
4301 if (size < 64)
4302 mask = (1ULL << size) - 1;
4303 else
4304 mask = std::numeric_limits<uint64_t>::max();
4305 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4306 SetResult(rt_reg(), alu_out);
4307 break;
4308 }
4309 case DINSU: { // Mips64r2 instruction.
4310 // Interpret rd field as 5-bit msbminus32 of insert.
4311 uint16_t msbminus32 = rd_reg();
4312 // Interpret rd field as 5-bit lsbminus32 of insert.
4313 uint16_t lsbminus32 = sa();
4314 uint16_t lsb = lsbminus32 + 32;
4315 uint16_t size = msbminus32 + 32 - lsb + 1;
4316 uint64_t mask = (1ULL << size) - 1;
4317 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4318 SetResult(rt_reg(), alu_out);
4319 break;
4320 }
4321 case BSHFL: {
4322 int32_t sa = instr_.SaFieldRaw() >> kSaShift;
4323 switch (sa) {
4324 case BITSWAP: {
4325 uint32_t input = static_cast<uint32_t>(rt());
4326 uint32_t output = 0;
4327 uint8_t i_byte, o_byte;
4328
4329 // Reverse the bit in byte for each individual byte
4330 for (int i = 0; i < 4; i++) {
4331 output = output >> 8;
4332 i_byte = input & 0xFF;
4333
4334 // Fast way to reverse bits in byte
4335 // Devised by Sean Anderson, July 13, 2001
4336 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4337 (i_byte * 0x8020LU & 0x88440LU)) *
4338 0x10101LU >>
4339 16);
4340
4341 output = output | (static_cast<uint32_t>(o_byte << 24));
4342 input = input >> 8;
4343 }
4344
4345 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4346 break;
4347 }
4348 case SEB: {
4349 uint8_t input = static_cast<uint8_t>(rt());
4350 uint32_t output = input;
4351 uint32_t mask = 0x00000080;
4352
4353 // Extending sign
4354 if (mask & input) {
4355 output |= 0xFFFFFF00;
4356 }
4357
4358 alu_out = static_cast<int32_t>(output);
4359 break;
4360 }
4361 case SEH: {
4362 uint16_t input = static_cast<uint16_t>(rt());
4363 uint32_t output = input;
4364 uint32_t mask = 0x00008000;
4365
4366 // Extending sign
4367 if (mask & input) {
4368 output |= 0xFFFF0000;
4369 }
4370
4371 alu_out = static_cast<int32_t>(output);
4372 break;
4373 }
4374 case WSBH: {
4375 uint32_t input = static_cast<uint32_t>(rt());
4376 uint64_t output = 0;
4377
4378 uint32_t mask = 0xFF000000;
4379 for (int i = 0; i < 4; i++) {
4380 uint32_t tmp = mask & input;
4381 if (i % 2 == 0) {
4382 tmp = tmp >> 8;
4383 } else {
4384 tmp = tmp << 8;
4385 }
4386 output = output | tmp;
4387 mask = mask >> 8;
4388 }
4389 mask = 0x80000000;
4390
4391 // Extending sign
4392 if (mask & output) {
4393 output |= 0xFFFFFFFF00000000;
4394 }
4395
4396 alu_out = static_cast<int64_t>(output);
4397 break;
4398 }
4399 default: {
4400 const uint8_t bp2 = instr_.Bp2Value();
4401 sa >>= kBp2Bits;
4402 switch (sa) {
4403 case ALIGN: {
4404 if (bp2 == 0) {
4405 alu_out = static_cast<int32_t>(rt());
4406 } else {
4407 uint64_t rt_hi = rt() << (8 * bp2);
4408 uint64_t rs_lo = rs() >> (8 * (4 - bp2));
4409 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
4410 }
4411 break;
4412 }
4413 default:
4414 alu_out = 0x12345678;
4415 UNREACHABLE();
4416 }
4417 break;
4418 }
4419 }
4420 SetResult(rd_reg(), alu_out);
4421 break;
4422 }
4423 case DBSHFL: {
4424 int32_t sa = instr_.SaFieldRaw() >> kSaShift;
4425 switch (sa) {
4426 case DBITSWAP: {
4427 switch (sa) {
4428 case DBITSWAP_SA: { // Mips64r6
4429 uint64_t input = static_cast<uint64_t>(rt());
4430 uint64_t output = 0;
4431 uint8_t i_byte, o_byte;
4432
4433 // Reverse the bit in byte for each individual byte
4434 for (int i = 0; i < 8; i++) {
4435 output = output >> 8;
4436 i_byte = input & 0xFF;
4437
4438 // Fast way to reverse bits in byte
4439 // Devised by Sean Anderson, July 13, 2001
4440 o_byte =
4441 static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4442 (i_byte * 0x8020LU & 0x88440LU)) *
4443 0x10101LU >>
4444 16);
4445
4446 output = output | ((static_cast<uint64_t>(o_byte) << 56));
4447 input = input >> 8;
4448 }
4449
4450 alu_out = static_cast<int64_t>(output);
4451 break;
4452 }
4453 }
4454 break;
4455 }
4456 case DSBH: {
4457 uint64_t input = static_cast<uint64_t>(rt());
4458 uint64_t output = 0;
4459
4460 uint64_t mask = 0xFF00000000000000;
4461 for (int i = 0; i < 8; i++) {
4462 uint64_t tmp = mask & input;
4463 if (i % 2 == 0)
4464 tmp = tmp >> 8;
4465 else
4466 tmp = tmp << 8;
4467
4468 output = output | tmp;
4469 mask = mask >> 8;
4470 }
4471
4472 alu_out = static_cast<int64_t>(output);
4473 break;
4474 }
4475 case DSHD: {
4476 uint64_t input = static_cast<uint64_t>(rt());
4477 uint64_t output = 0;
4478
4479 uint64_t mask = 0xFFFF000000000000;
4480 for (int i = 0; i < 4; i++) {
4481 uint64_t tmp = mask & input;
4482 if (i == 0)
4483 tmp = tmp >> 48;
4484 else if (i == 1)
4485 tmp = tmp >> 16;
4486 else if (i == 2)
4487 tmp = tmp << 16;
4488 else
4489 tmp = tmp << 48;
4490 output = output | tmp;
4491 mask = mask >> 16;
4492 }
4493
4494 alu_out = static_cast<int64_t>(output);
4495 break;
4496 }
4497 default: {
4498 const uint8_t bp3 = instr_.Bp3Value();
4499 sa >>= kBp3Bits;
4500 switch (sa) {
4501 case DALIGN: {
4502 if (bp3 == 0) {
4503 alu_out = static_cast<int64_t>(rt());
4504 } else {
4505 uint64_t rt_hi = rt() << (8 * bp3);
4506 uint64_t rs_lo = rs() >> (8 * (8 - bp3));
4507 alu_out = static_cast<int64_t>(rt_hi | rs_lo);
4508 }
4509 break;
4510 }
4511 default:
4512 alu_out = 0x12345678;
4513 UNREACHABLE();
4514 }
4515 break;
4516 }
4517 }
4518 SetResult(rd_reg(), alu_out);
4519 break;
4520 }
4521 default:
4522 UNREACHABLE();
4523 }
4524 }
4525
DecodeMsaDataFormat()4526 int Simulator::DecodeMsaDataFormat() {
4527 int df = -1;
4528 if (instr_.IsMSABranchInstr()) {
4529 switch (instr_.RsFieldRaw()) {
4530 case BZ_V:
4531 case BNZ_V:
4532 df = MSA_VECT;
4533 break;
4534 case BZ_B:
4535 case BNZ_B:
4536 df = MSA_BYTE;
4537 break;
4538 case BZ_H:
4539 case BNZ_H:
4540 df = MSA_HALF;
4541 break;
4542 case BZ_W:
4543 case BNZ_W:
4544 df = MSA_WORD;
4545 break;
4546 case BZ_D:
4547 case BNZ_D:
4548 df = MSA_DWORD;
4549 break;
4550 default:
4551 UNREACHABLE();
4552 }
4553 } else {
4554 int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
4555 switch (instr_.MSAMinorOpcodeField()) {
4556 case kMsaMinorI5:
4557 case kMsaMinorI10:
4558 case kMsaMinor3R:
4559 df = DF[instr_.Bits(22, 21)];
4560 break;
4561 case kMsaMinorMI10:
4562 df = DF[instr_.Bits(1, 0)];
4563 break;
4564 case kMsaMinorBIT:
4565 df = DF[instr_.MsaBitDf()];
4566 break;
4567 case kMsaMinorELM:
4568 df = DF[instr_.MsaElmDf()];
4569 break;
4570 case kMsaMinor3RF: {
4571 uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
4572 switch (opcode) {
4573 case FEXDO:
4574 case FTQ:
4575 case MUL_Q:
4576 case MADD_Q:
4577 case MSUB_Q:
4578 case MULR_Q:
4579 case MADDR_Q:
4580 case MSUBR_Q:
4581 df = DF[1 + instr_.Bit(21)];
4582 break;
4583 default:
4584 df = DF[2 + instr_.Bit(21)];
4585 break;
4586 }
4587 } break;
4588 case kMsaMinor2R:
4589 df = DF[instr_.Bits(17, 16)];
4590 break;
4591 case kMsaMinor2RF:
4592 df = DF[2 + instr_.Bit(16)];
4593 break;
4594 default:
4595 UNREACHABLE();
4596 }
4597 }
4598 return df;
4599 }
4600
DecodeTypeMsaI8()4601 void Simulator::DecodeTypeMsaI8() {
4602 DCHECK_EQ(kArchVariant, kMips64r6);
4603 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4604 uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
4605 int8_t i8 = instr_.MsaImm8Value();
4606 msa_reg_t ws, wd;
4607
4608 switch (opcode) {
4609 case ANDI_B:
4610 get_msa_register(instr_.WsValue(), ws.b);
4611 for (int i = 0; i < kMSALanesByte; i++) {
4612 wd.b[i] = ws.b[i] & i8;
4613 }
4614 set_msa_register(instr_.WdValue(), wd.b);
4615 TraceMSARegWr(wd.b);
4616 break;
4617 case ORI_B:
4618 get_msa_register(instr_.WsValue(), ws.b);
4619 for (int i = 0; i < kMSALanesByte; i++) {
4620 wd.b[i] = ws.b[i] | i8;
4621 }
4622 set_msa_register(instr_.WdValue(), wd.b);
4623 TraceMSARegWr(wd.b);
4624 break;
4625 case NORI_B:
4626 get_msa_register(instr_.WsValue(), ws.b);
4627 for (int i = 0; i < kMSALanesByte; i++) {
4628 wd.b[i] = ~(ws.b[i] | i8);
4629 }
4630 set_msa_register(instr_.WdValue(), wd.b);
4631 TraceMSARegWr(wd.b);
4632 break;
4633 case XORI_B:
4634 get_msa_register(instr_.WsValue(), ws.b);
4635 for (int i = 0; i < kMSALanesByte; i++) {
4636 wd.b[i] = ws.b[i] ^ i8;
4637 }
4638 set_msa_register(instr_.WdValue(), wd.b);
4639 TraceMSARegWr(wd.b);
4640 break;
4641 case BMNZI_B:
4642 get_msa_register(instr_.WsValue(), ws.b);
4643 get_msa_register(instr_.WdValue(), wd.b);
4644 for (int i = 0; i < kMSALanesByte; i++) {
4645 wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
4646 }
4647 set_msa_register(instr_.WdValue(), wd.b);
4648 TraceMSARegWr(wd.b);
4649 break;
4650 case BMZI_B:
4651 get_msa_register(instr_.WsValue(), ws.b);
4652 get_msa_register(instr_.WdValue(), wd.b);
4653 for (int i = 0; i < kMSALanesByte; i++) {
4654 wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
4655 }
4656 set_msa_register(instr_.WdValue(), wd.b);
4657 TraceMSARegWr(wd.b);
4658 break;
4659 case BSELI_B:
4660 get_msa_register(instr_.WsValue(), ws.b);
4661 get_msa_register(instr_.WdValue(), wd.b);
4662 for (int i = 0; i < kMSALanesByte; i++) {
4663 wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
4664 }
4665 set_msa_register(instr_.WdValue(), wd.b);
4666 TraceMSARegWr(wd.b);
4667 break;
4668 case SHF_B:
4669 get_msa_register(instr_.WsValue(), ws.b);
4670 for (int i = 0; i < kMSALanesByte; i++) {
4671 int j = i % 4;
4672 int k = (i8 >> (2 * j)) & 0x3;
4673 wd.b[i] = ws.b[i - j + k];
4674 }
4675 set_msa_register(instr_.WdValue(), wd.b);
4676 TraceMSARegWr(wd.b);
4677 break;
4678 case SHF_H:
4679 get_msa_register(instr_.WsValue(), ws.h);
4680 for (int i = 0; i < kMSALanesHalf; i++) {
4681 int j = i % 4;
4682 int k = (i8 >> (2 * j)) & 0x3;
4683 wd.h[i] = ws.h[i - j + k];
4684 }
4685 set_msa_register(instr_.WdValue(), wd.h);
4686 TraceMSARegWr(wd.h);
4687 break;
4688 case SHF_W:
4689 get_msa_register(instr_.WsValue(), ws.w);
4690 for (int i = 0; i < kMSALanesWord; i++) {
4691 int j = (i8 >> (2 * i)) & 0x3;
4692 wd.w[i] = ws.w[j];
4693 }
4694 set_msa_register(instr_.WdValue(), wd.w);
4695 TraceMSARegWr(wd.w);
4696 break;
4697 default:
4698 UNREACHABLE();
4699 }
4700 }
4701
4702 template <typename T>
MsaI5InstrHelper(uint32_t opcode,T ws,int32_t i5)4703 T Simulator::MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5) {
4704 T res;
4705 uint32_t ui5 = i5 & 0x1Fu;
4706 uint64_t ws_u64 = static_cast<uint64_t>(ws);
4707 uint64_t ui5_u64 = static_cast<uint64_t>(ui5);
4708
4709 switch (opcode) {
4710 case ADDVI:
4711 res = static_cast<T>(ws + ui5);
4712 break;
4713 case SUBVI:
4714 res = static_cast<T>(ws - ui5);
4715 break;
4716 case MAXI_S:
4717 res = static_cast<T>(std::max(ws, static_cast<T>(i5)));
4718 break;
4719 case MINI_S:
4720 res = static_cast<T>(std::min(ws, static_cast<T>(i5)));
4721 break;
4722 case MAXI_U:
4723 res = static_cast<T>(std::max(ws_u64, ui5_u64));
4724 break;
4725 case MINI_U:
4726 res = static_cast<T>(std::min(ws_u64, ui5_u64));
4727 break;
4728 case CEQI:
4729 res = static_cast<T>(!Compare(ws, static_cast<T>(i5)) ? -1ull : 0ull);
4730 break;
4731 case CLTI_S:
4732 res = static_cast<T>((Compare(ws, static_cast<T>(i5)) == -1) ? -1ull
4733 : 0ull);
4734 break;
4735 case CLTI_U:
4736 res = static_cast<T>((Compare(ws_u64, ui5_u64) == -1) ? -1ull : 0ull);
4737 break;
4738 case CLEI_S:
4739 res =
4740 static_cast<T>((Compare(ws, static_cast<T>(i5)) != 1) ? -1ull : 0ull);
4741 break;
4742 case CLEI_U:
4743 res = static_cast<T>((Compare(ws_u64, ui5_u64) != 1) ? -1ull : 0ull);
4744 break;
4745 default:
4746 UNREACHABLE();
4747 }
4748 return res;
4749 }
4750
DecodeTypeMsaI5()4751 void Simulator::DecodeTypeMsaI5() {
4752 DCHECK_EQ(kArchVariant, kMips64r6);
4753 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4754 uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4755 msa_reg_t ws, wd;
4756
4757 // sign extend 5bit value to int32_t
4758 int32_t i5 = static_cast<int32_t>(instr_.MsaImm5Value() << 27) >> 27;
4759
4760 #define MSA_I5_DF(elem, num_of_lanes) \
4761 get_msa_register(instr_.WsValue(), ws.elem); \
4762 for (int i = 0; i < num_of_lanes; i++) { \
4763 wd.elem[i] = MsaI5InstrHelper(opcode, ws.elem[i], i5); \
4764 } \
4765 set_msa_register(instr_.WdValue(), wd.elem); \
4766 TraceMSARegWr(wd.elem)
4767
4768 switch (DecodeMsaDataFormat()) {
4769 case MSA_BYTE:
4770 MSA_I5_DF(b, kMSALanesByte);
4771 break;
4772 case MSA_HALF:
4773 MSA_I5_DF(h, kMSALanesHalf);
4774 break;
4775 case MSA_WORD:
4776 MSA_I5_DF(w, kMSALanesWord);
4777 break;
4778 case MSA_DWORD:
4779 MSA_I5_DF(d, kMSALanesDword);
4780 break;
4781 default:
4782 UNREACHABLE();
4783 }
4784 #undef MSA_I5_DF
4785 }
4786
DecodeTypeMsaI10()4787 void Simulator::DecodeTypeMsaI10() {
4788 DCHECK_EQ(kArchVariant, kMips64r6);
4789 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4790 uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4791 int64_t s10 = (static_cast<int64_t>(instr_.MsaImm10Value()) << 54) >> 54;
4792 msa_reg_t wd;
4793
4794 #define MSA_I10_DF(elem, num_of_lanes, T) \
4795 for (int i = 0; i < num_of_lanes; ++i) { \
4796 wd.elem[i] = static_cast<T>(s10); \
4797 } \
4798 set_msa_register(instr_.WdValue(), wd.elem); \
4799 TraceMSARegWr(wd.elem)
4800
4801 if (opcode == LDI) {
4802 switch (DecodeMsaDataFormat()) {
4803 case MSA_BYTE:
4804 MSA_I10_DF(b, kMSALanesByte, int8_t);
4805 break;
4806 case MSA_HALF:
4807 MSA_I10_DF(h, kMSALanesHalf, int16_t);
4808 break;
4809 case MSA_WORD:
4810 MSA_I10_DF(w, kMSALanesWord, int32_t);
4811 break;
4812 case MSA_DWORD:
4813 MSA_I10_DF(d, kMSALanesDword, int64_t);
4814 break;
4815 default:
4816 UNREACHABLE();
4817 }
4818 } else {
4819 UNREACHABLE();
4820 }
4821 #undef MSA_I10_DF
4822 }
4823
DecodeTypeMsaELM()4824 void Simulator::DecodeTypeMsaELM() {
4825 DCHECK_EQ(kArchVariant, kMips64r6);
4826 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4827 uint32_t opcode = instr_.InstructionBits() & kMsaLongerELMMask;
4828 int32_t n = instr_.MsaElmNValue();
4829 int64_t alu_out;
4830 switch (opcode) {
4831 case CTCMSA:
4832 DCHECK_EQ(sa(), kMSACSRRegister);
4833 MSACSR_ = bit_cast<uint32_t>(
4834 static_cast<int32_t>(registers_[rd_reg()] & kMaxUInt32));
4835 TraceRegWr(static_cast<int32_t>(MSACSR_));
4836 break;
4837 case CFCMSA:
4838 DCHECK_EQ(rd_reg(), kMSACSRRegister);
4839 SetResult(sa(), static_cast<int64_t>(bit_cast<int32_t>(MSACSR_)));
4840 break;
4841 case MOVE_V: {
4842 msa_reg_t ws;
4843 get_msa_register(ws_reg(), &ws);
4844 set_msa_register(wd_reg(), &ws);
4845 TraceMSARegWr(&ws);
4846 } break;
4847 default:
4848 opcode &= kMsaELMMask;
4849 switch (opcode) {
4850 case COPY_S:
4851 case COPY_U: {
4852 msa_reg_t ws;
4853 switch (DecodeMsaDataFormat()) {
4854 case MSA_BYTE:
4855 DCHECK_LT(n, kMSALanesByte);
4856 get_msa_register(instr_.WsValue(), ws.b);
4857 alu_out = static_cast<int32_t>(ws.b[n]);
4858 SetResult(wd_reg(),
4859 (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
4860 break;
4861 case MSA_HALF:
4862 DCHECK_LT(n, kMSALanesHalf);
4863 get_msa_register(instr_.WsValue(), ws.h);
4864 alu_out = static_cast<int32_t>(ws.h[n]);
4865 SetResult(wd_reg(),
4866 (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
4867 break;
4868 case MSA_WORD:
4869 DCHECK_LT(n, kMSALanesWord);
4870 get_msa_register(instr_.WsValue(), ws.w);
4871 alu_out = static_cast<int32_t>(ws.w[n]);
4872 SetResult(wd_reg(),
4873 (opcode == COPY_U) ? alu_out & 0xFFFFFFFFu : alu_out);
4874 break;
4875 case MSA_DWORD:
4876 DCHECK_LT(n, kMSALanesDword);
4877 get_msa_register(instr_.WsValue(), ws.d);
4878 alu_out = static_cast<int64_t>(ws.d[n]);
4879 SetResult(wd_reg(), alu_out);
4880 break;
4881 default:
4882 UNREACHABLE();
4883 }
4884 } break;
4885 case INSERT: {
4886 msa_reg_t wd;
4887 switch (DecodeMsaDataFormat()) {
4888 case MSA_BYTE: {
4889 DCHECK_LT(n, kMSALanesByte);
4890 int64_t rs = get_register(instr_.WsValue());
4891 get_msa_register(instr_.WdValue(), wd.b);
4892 wd.b[n] = rs & 0xFFu;
4893 set_msa_register(instr_.WdValue(), wd.b);
4894 TraceMSARegWr(wd.b);
4895 break;
4896 }
4897 case MSA_HALF: {
4898 DCHECK_LT(n, kMSALanesHalf);
4899 int64_t rs = get_register(instr_.WsValue());
4900 get_msa_register(instr_.WdValue(), wd.h);
4901 wd.h[n] = rs & 0xFFFFu;
4902 set_msa_register(instr_.WdValue(), wd.h);
4903 TraceMSARegWr(wd.h);
4904 break;
4905 }
4906 case MSA_WORD: {
4907 DCHECK_LT(n, kMSALanesWord);
4908 int64_t rs = get_register(instr_.WsValue());
4909 get_msa_register(instr_.WdValue(), wd.w);
4910 wd.w[n] = rs & 0xFFFFFFFFu;
4911 set_msa_register(instr_.WdValue(), wd.w);
4912 TraceMSARegWr(wd.w);
4913 break;
4914 }
4915 case MSA_DWORD: {
4916 DCHECK_LT(n, kMSALanesDword);
4917 int64_t rs = get_register(instr_.WsValue());
4918 get_msa_register(instr_.WdValue(), wd.d);
4919 wd.d[n] = rs;
4920 set_msa_register(instr_.WdValue(), wd.d);
4921 TraceMSARegWr(wd.d);
4922 break;
4923 }
4924 default:
4925 UNREACHABLE();
4926 }
4927 } break;
4928 case SLDI: {
4929 uint8_t v[32];
4930 msa_reg_t ws;
4931 msa_reg_t wd;
4932 get_msa_register(ws_reg(), &ws);
4933 get_msa_register(wd_reg(), &wd);
4934 #define SLDI_DF(s, k) \
4935 for (unsigned i = 0; i < s; i++) { \
4936 v[i] = ws.b[s * k + i]; \
4937 v[i + s] = wd.b[s * k + i]; \
4938 } \
4939 for (unsigned i = 0; i < s; i++) { \
4940 wd.b[s * k + i] = v[i + n]; \
4941 }
4942 switch (DecodeMsaDataFormat()) {
4943 case MSA_BYTE:
4944 DCHECK(n < kMSALanesByte);
4945 SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
4946 break;
4947 case MSA_HALF:
4948 DCHECK(n < kMSALanesHalf);
4949 for (int k = 0; k < 2; ++k) {
4950 SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
4951 }
4952 break;
4953 case MSA_WORD:
4954 DCHECK(n < kMSALanesWord);
4955 for (int k = 0; k < 4; ++k) {
4956 SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
4957 }
4958 break;
4959 case MSA_DWORD:
4960 DCHECK(n < kMSALanesDword);
4961 for (int k = 0; k < 8; ++k) {
4962 SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
4963 }
4964 break;
4965 default:
4966 UNREACHABLE();
4967 }
4968 set_msa_register(wd_reg(), &wd);
4969 TraceMSARegWr(&wd);
4970 } break;
4971 #undef SLDI_DF
4972 case SPLATI:
4973 case INSVE:
4974 UNIMPLEMENTED();
4975 default:
4976 UNREACHABLE();
4977 }
4978 break;
4979 }
4980 }
4981
4982 template <typename T>
MsaBitInstrHelper(uint32_t opcode,T wd,T ws,int32_t m)4983 T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
4984 using uT = typename std::make_unsigned<T>::type;
4985 T res;
4986 switch (opcode) {
4987 case SLLI:
4988 res = static_cast<T>(ws << m);
4989 break;
4990 case SRAI:
4991 res = static_cast<T>(ArithmeticShiftRight(ws, m));
4992 break;
4993 case SRLI:
4994 res = static_cast<T>(static_cast<uT>(ws) >> m);
4995 break;
4996 case BCLRI:
4997 res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
4998 break;
4999 case BSETI:
5000 res = static_cast<T>(static_cast<T>(1ull << m) | ws);
5001 break;
5002 case BNEGI:
5003 res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
5004 break;
5005 case BINSLI: {
5006 int elem_size = 8 * sizeof(T);
5007 int bits = m + 1;
5008 if (bits == elem_size) {
5009 res = static_cast<T>(ws);
5010 } else {
5011 uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
5012 res = static_cast<T>((static_cast<T>(mask) & ws) |
5013 (static_cast<T>(~mask) & wd));
5014 }
5015 } break;
5016 case BINSRI: {
5017 int elem_size = 8 * sizeof(T);
5018 int bits = m + 1;
5019 if (bits == elem_size) {
5020 res = static_cast<T>(ws);
5021 } else {
5022 uint64_t mask = (1ull << bits) - 1;
5023 res = static_cast<T>((static_cast<T>(mask) & ws) |
5024 (static_cast<T>(~mask) & wd));
5025 }
5026 } break;
5027 case SAT_S: {
5028 #define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
5029 #define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
5030 int shift = 64 - 8 * sizeof(T);
5031 int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
5032 res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
5033 ? M_MIN_INT(m + 1)
5034 : ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
5035 : ws_i64);
5036 #undef M_MAX_INT
5037 #undef M_MIN_INT
5038 } break;
5039 case SAT_U: {
5040 #define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
5041 uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
5042 uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
5043 res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
5044 : M_MAX_UINT(m + 1));
5045 #undef M_MAX_UINT
5046 } break;
5047 case SRARI:
5048 if (!m) {
5049 res = static_cast<T>(ws);
5050 } else {
5051 res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
5052 static_cast<T>((ws >> (m - 1)) & 0x1);
5053 }
5054 break;
5055 case SRLRI:
5056 if (!m) {
5057 res = static_cast<T>(ws);
5058 } else {
5059 res = static_cast<T>(static_cast<uT>(ws) >> m) +
5060 static_cast<T>((ws >> (m - 1)) & 0x1);
5061 }
5062 break;
5063 default:
5064 UNREACHABLE();
5065 }
5066 return res;
5067 }
5068
DecodeTypeMsaBIT()5069 void Simulator::DecodeTypeMsaBIT() {
5070 DCHECK_EQ(kArchVariant, kMips64r6);
5071 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5072 uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
5073 int32_t m = instr_.MsaBitMValue();
5074 msa_reg_t wd, ws;
5075
5076 #define MSA_BIT_DF(elem, num_of_lanes) \
5077 get_msa_register(instr_.WsValue(), ws.elem); \
5078 if (opcode == BINSLI || opcode == BINSRI) { \
5079 get_msa_register(instr_.WdValue(), wd.elem); \
5080 } \
5081 for (int i = 0; i < num_of_lanes; i++) { \
5082 wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
5083 } \
5084 set_msa_register(instr_.WdValue(), wd.elem); \
5085 TraceMSARegWr(wd.elem)
5086
5087 switch (DecodeMsaDataFormat()) {
5088 case MSA_BYTE:
5089 DCHECK(m < kMSARegSize / kMSALanesByte);
5090 MSA_BIT_DF(b, kMSALanesByte);
5091 break;
5092 case MSA_HALF:
5093 DCHECK(m < kMSARegSize / kMSALanesHalf);
5094 MSA_BIT_DF(h, kMSALanesHalf);
5095 break;
5096 case MSA_WORD:
5097 DCHECK(m < kMSARegSize / kMSALanesWord);
5098 MSA_BIT_DF(w, kMSALanesWord);
5099 break;
5100 case MSA_DWORD:
5101 DCHECK(m < kMSARegSize / kMSALanesDword);
5102 MSA_BIT_DF(d, kMSALanesDword);
5103 break;
5104 default:
5105 UNREACHABLE();
5106 }
5107 #undef MSA_BIT_DF
5108 }
5109
DecodeTypeMsaMI10()5110 void Simulator::DecodeTypeMsaMI10() {
5111 DCHECK_EQ(kArchVariant, kMips64r6);
5112 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5113 uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
5114 int64_t s10 = (static_cast<int64_t>(instr_.MsaImmMI10Value()) << 54) >> 54;
5115 int64_t rs = get_register(instr_.WsValue());
5116 int64_t addr;
5117 msa_reg_t wd;
5118
5119 #define MSA_MI10_LOAD(elem, num_of_lanes, T) \
5120 for (int i = 0; i < num_of_lanes; ++i) { \
5121 addr = rs + (s10 + i) * sizeof(T); \
5122 wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
5123 } \
5124 set_msa_register(instr_.WdValue(), wd.elem);
5125
5126 #define MSA_MI10_STORE(elem, num_of_lanes, T) \
5127 get_msa_register(instr_.WdValue(), wd.elem); \
5128 for (int i = 0; i < num_of_lanes; ++i) { \
5129 addr = rs + (s10 + i) * sizeof(T); \
5130 WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
5131 }
5132
5133 if (opcode == MSA_LD) {
5134 switch (DecodeMsaDataFormat()) {
5135 case MSA_BYTE:
5136 MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
5137 break;
5138 case MSA_HALF:
5139 MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
5140 break;
5141 case MSA_WORD:
5142 MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
5143 break;
5144 case MSA_DWORD:
5145 MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
5146 break;
5147 default:
5148 UNREACHABLE();
5149 }
5150 } else if (opcode == MSA_ST) {
5151 switch (DecodeMsaDataFormat()) {
5152 case MSA_BYTE:
5153 MSA_MI10_STORE(b, kMSALanesByte, int8_t);
5154 break;
5155 case MSA_HALF:
5156 MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
5157 break;
5158 case MSA_WORD:
5159 MSA_MI10_STORE(w, kMSALanesWord, int32_t);
5160 break;
5161 case MSA_DWORD:
5162 MSA_MI10_STORE(d, kMSALanesDword, int64_t);
5163 break;
5164 default:
5165 UNREACHABLE();
5166 }
5167 } else {
5168 UNREACHABLE();
5169 }
5170
5171 #undef MSA_MI10_LOAD
5172 #undef MSA_MI10_STORE
5173 }
5174
5175 template <typename T>
Msa3RInstrHelper(uint32_t opcode,T wd,T ws,T wt)5176 T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
5177 using uT = typename std::make_unsigned<T>::type;
5178 T res;
5179 int wt_modulo = wt % (sizeof(T) * 8);
5180 switch (opcode) {
5181 case SLL_MSA:
5182 res = static_cast<T>(ws << wt_modulo);
5183 break;
5184 case SRA_MSA:
5185 res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo));
5186 break;
5187 case SRL_MSA:
5188 res = static_cast<T>(static_cast<uT>(ws) >> wt_modulo);
5189 break;
5190 case BCLR:
5191 res = static_cast<T>(static_cast<T>(~(1ull << wt_modulo)) & ws);
5192 break;
5193 case BSET:
5194 res = static_cast<T>(static_cast<T>(1ull << wt_modulo) | ws);
5195 break;
5196 case BNEG:
5197 res = static_cast<T>(static_cast<T>(1ull << wt_modulo) ^ ws);
5198 break;
5199 case BINSL: {
5200 int elem_size = 8 * sizeof(T);
5201 int bits = wt_modulo + 1;
5202 if (bits == elem_size) {
5203 res = static_cast<T>(ws);
5204 } else {
5205 uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
5206 res = static_cast<T>((static_cast<T>(mask) & ws) |
5207 (static_cast<T>(~mask) & wd));
5208 }
5209 } break;
5210 case BINSR: {
5211 int elem_size = 8 * sizeof(T);
5212 int bits = wt_modulo + 1;
5213 if (bits == elem_size) {
5214 res = static_cast<T>(ws);
5215 } else {
5216 uint64_t mask = (1ull << bits) - 1;
5217 res = static_cast<T>((static_cast<T>(mask) & ws) |
5218 (static_cast<T>(~mask) & wd));
5219 }
5220 } break;
5221 case ADDV:
5222 res = ws + wt;
5223 break;
5224 case SUBV:
5225 res = ws - wt;
5226 break;
5227 case MAX_S:
5228 res = std::max(ws, wt);
5229 break;
5230 case MAX_U:
5231 res = static_cast<T>(std::max(static_cast<uT>(ws), static_cast<uT>(wt)));
5232 break;
5233 case MIN_S:
5234 res = std::min(ws, wt);
5235 break;
5236 case MIN_U:
5237 res = static_cast<T>(std::min(static_cast<uT>(ws), static_cast<uT>(wt)));
5238 break;
5239 case MAX_A:
5240 // We use negative abs in order to avoid problems
5241 // with corner case for MIN_INT
5242 res = Nabs(ws) < Nabs(wt) ? ws : wt;
5243 break;
5244 case MIN_A:
5245 // We use negative abs in order to avoid problems
5246 // with corner case for MIN_INT
5247 res = Nabs(ws) > Nabs(wt) ? ws : wt;
5248 break;
5249 case CEQ:
5250 res = static_cast<T>(!Compare(ws, wt) ? -1ull : 0ull);
5251 break;
5252 case CLT_S:
5253 res = static_cast<T>((Compare(ws, wt) == -1) ? -1ull : 0ull);
5254 break;
5255 case CLT_U:
5256 res = static_cast<T>(
5257 (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) == -1) ? -1ull
5258 : 0ull);
5259 break;
5260 case CLE_S:
5261 res = static_cast<T>((Compare(ws, wt) != 1) ? -1ull : 0ull);
5262 break;
5263 case CLE_U:
5264 res = static_cast<T>(
5265 (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) != 1) ? -1ull
5266 : 0ull);
5267 break;
5268 case ADD_A:
5269 res = static_cast<T>(Abs(ws) + Abs(wt));
5270 break;
5271 case ADDS_A: {
5272 T ws_nabs = Nabs(ws);
5273 T wt_nabs = Nabs(wt);
5274 if (ws_nabs < -std::numeric_limits<T>::max() - wt_nabs) {
5275 res = std::numeric_limits<T>::max();
5276 } else {
5277 res = -(ws_nabs + wt_nabs);
5278 }
5279 } break;
5280 case ADDS_S:
5281 res = SaturateAdd(ws, wt);
5282 break;
5283 case ADDS_U: {
5284 uT ws_u = static_cast<uT>(ws);
5285 uT wt_u = static_cast<uT>(wt);
5286 res = static_cast<T>(SaturateAdd(ws_u, wt_u));
5287 } break;
5288 case AVE_S:
5289 res = static_cast<T>((wt & ws) + ((wt ^ ws) >> 1));
5290 break;
5291 case AVE_U: {
5292 uT ws_u = static_cast<uT>(ws);
5293 uT wt_u = static_cast<uT>(wt);
5294 res = static_cast<T>((wt_u & ws_u) + ((wt_u ^ ws_u) >> 1));
5295 } break;
5296 case AVER_S:
5297 res = static_cast<T>((wt | ws) - ((wt ^ ws) >> 1));
5298 break;
5299 case AVER_U: {
5300 uT ws_u = static_cast<uT>(ws);
5301 uT wt_u = static_cast<uT>(wt);
5302 res = static_cast<T>((wt_u | ws_u) - ((wt_u ^ ws_u) >> 1));
5303 } break;
5304 case SUBS_S:
5305 res = SaturateSub(ws, wt);
5306 break;
5307 case SUBS_U: {
5308 uT ws_u = static_cast<uT>(ws);
5309 uT wt_u = static_cast<uT>(wt);
5310 res = static_cast<T>(SaturateSub(ws_u, wt_u));
5311 } break;
5312 case SUBSUS_U: {
5313 uT wsu = static_cast<uT>(ws);
5314 if (wt > 0) {
5315 uT wtu = static_cast<uT>(wt);
5316 if (wtu > wsu) {
5317 res = 0;
5318 } else {
5319 res = static_cast<T>(wsu - wtu);
5320 }
5321 } else {
5322 if (wsu > std::numeric_limits<uT>::max() + wt) {
5323 res = static_cast<T>(std::numeric_limits<uT>::max());
5324 } else {
5325 res = static_cast<T>(wsu - wt);
5326 }
5327 }
5328 } break;
5329 case SUBSUU_S: {
5330 uT wsu = static_cast<uT>(ws);
5331 uT wtu = static_cast<uT>(wt);
5332 uT wdu;
5333 if (wsu > wtu) {
5334 wdu = wsu - wtu;
5335 if (wdu > std::numeric_limits<T>::max()) {
5336 res = std::numeric_limits<T>::max();
5337 } else {
5338 res = static_cast<T>(wdu);
5339 }
5340 } else {
5341 wdu = wtu - wsu;
5342 CHECK(-std::numeric_limits<T>::max() ==
5343 std::numeric_limits<T>::min() + 1);
5344 if (wdu <= std::numeric_limits<T>::max()) {
5345 res = -static_cast<T>(wdu);
5346 } else {
5347 res = std::numeric_limits<T>::min();
5348 }
5349 }
5350 } break;
5351 case ASUB_S:
5352 res = static_cast<T>(Abs(ws - wt));
5353 break;
5354 case ASUB_U: {
5355 uT wsu = static_cast<uT>(ws);
5356 uT wtu = static_cast<uT>(wt);
5357 res = static_cast<T>(wsu > wtu ? wsu - wtu : wtu - wsu);
5358 } break;
5359 case MULV:
5360 res = ws * wt;
5361 break;
5362 case MADDV:
5363 res = wd + ws * wt;
5364 break;
5365 case MSUBV:
5366 res = wd - ws * wt;
5367 break;
5368 case DIV_S_MSA:
5369 res = wt != 0 ? ws / wt : static_cast<T>(Unpredictable);
5370 break;
5371 case DIV_U:
5372 res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) / static_cast<uT>(wt))
5373 : static_cast<T>(Unpredictable);
5374 break;
5375 case MOD_S:
5376 res = wt != 0 ? ws % wt : static_cast<T>(Unpredictable);
5377 break;
5378 case MOD_U:
5379 res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) % static_cast<uT>(wt))
5380 : static_cast<T>(Unpredictable);
5381 break;
5382 case DOTP_S:
5383 case DOTP_U:
5384 case DPADD_S:
5385 case DPADD_U:
5386 case DPSUB_S:
5387 case DPSUB_U:
5388 case SLD:
5389 case SPLAT:
5390 UNIMPLEMENTED();
5391 break;
5392 case SRAR: {
5393 int bit = wt_modulo == 0 ? 0 : (ws >> (wt_modulo - 1)) & 1;
5394 res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo) + bit);
5395 } break;
5396 case SRLR: {
5397 uT wsu = static_cast<uT>(ws);
5398 int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
5399 res = static_cast<T>((wsu >> wt_modulo) + bit);
5400 } break;
5401 default:
5402 UNREACHABLE();
5403 }
5404 return res;
5405 }
5406 template <typename T_int, typename T_reg>
Msa3RInstrHelper_shuffle(const uint32_t opcode,T_reg ws,T_reg wt,T_reg wd,const int i,const int num_of_lanes)5407 void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
5408 T_reg wd, const int i, const int num_of_lanes) {
5409 T_int *ws_p, *wt_p, *wd_p;
5410 ws_p = reinterpret_cast<T_int*>(ws);
5411 wt_p = reinterpret_cast<T_int*>(wt);
5412 wd_p = reinterpret_cast<T_int*>(wd);
5413 switch (opcode) {
5414 case PCKEV:
5415 wd_p[i] = wt_p[2 * i];
5416 wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
5417 break;
5418 case PCKOD:
5419 wd_p[i] = wt_p[2 * i + 1];
5420 wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
5421 break;
5422 case ILVL:
5423 wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
5424 wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
5425 break;
5426 case ILVR:
5427 wd_p[2 * i] = wt_p[i];
5428 wd_p[2 * i + 1] = ws_p[i];
5429 break;
5430 case ILVEV:
5431 wd_p[2 * i] = wt_p[2 * i];
5432 wd_p[2 * i + 1] = ws_p[2 * i];
5433 break;
5434 case ILVOD:
5435 wd_p[2 * i] = wt_p[2 * i + 1];
5436 wd_p[2 * i + 1] = ws_p[2 * i + 1];
5437 break;
5438 case VSHF: {
5439 const int mask_not_valid = 0xC0;
5440 const int mask_6_bits = 0x3F;
5441 if ((wd_p[i] & mask_not_valid)) {
5442 wd_p[i] = 0;
5443 } else {
5444 int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
5445 wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
5446 }
5447 } break;
5448 default:
5449 UNREACHABLE();
5450 }
5451 }
5452
5453 template <typename T_int, typename T_smaller_int, typename T_reg>
Msa3RInstrHelper_horizontal(const uint32_t opcode,T_reg ws,T_reg wt,T_reg wd,const int i,const int num_of_lanes)5454 void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
5455 T_reg wd, const int i,
5456 const int num_of_lanes) {
5457 using T_uint = typename std::make_unsigned<T_int>::type;
5458 using T_smaller_uint = typename std::make_unsigned<T_smaller_int>::type;
5459 T_int* wd_p;
5460 T_smaller_int *ws_p, *wt_p;
5461 ws_p = reinterpret_cast<T_smaller_int*>(ws);
5462 wt_p = reinterpret_cast<T_smaller_int*>(wt);
5463 wd_p = reinterpret_cast<T_int*>(wd);
5464 T_uint* wd_pu;
5465 T_smaller_uint *ws_pu, *wt_pu;
5466 ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
5467 wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
5468 wd_pu = reinterpret_cast<T_uint*>(wd);
5469 switch (opcode) {
5470 case HADD_S:
5471 wd_p[i] =
5472 static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
5473 break;
5474 case HADD_U:
5475 wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
5476 static_cast<T_uint>(wt_pu[2 * i]);
5477 break;
5478 case HSUB_S:
5479 wd_p[i] =
5480 static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
5481 break;
5482 case HSUB_U:
5483 wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
5484 static_cast<T_uint>(wt_pu[2 * i]);
5485 break;
5486 default:
5487 UNREACHABLE();
5488 }
5489 }
5490
DecodeTypeMsa3R()5491 void Simulator::DecodeTypeMsa3R() {
5492 DCHECK_EQ(kArchVariant, kMips64r6);
5493 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5494 uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
5495 msa_reg_t ws, wd, wt;
5496 get_msa_register(ws_reg(), &ws);
5497 get_msa_register(wt_reg(), &wt);
5498 get_msa_register(wd_reg(), &wd);
5499 switch (opcode) {
5500 case HADD_S:
5501 case HADD_U:
5502 case HSUB_S:
5503 case HSUB_U:
5504 #define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
5505 for (int i = 0; i < num_of_lanes; ++i) { \
5506 Msa3RInstrHelper_horizontal<int_type, lesser_int_type>( \
5507 opcode, &ws, &wt, &wd, i, num_of_lanes); \
5508 }
5509 switch (DecodeMsaDataFormat()) {
5510 case MSA_HALF:
5511 HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
5512 break;
5513 case MSA_WORD:
5514 HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
5515 break;
5516 case MSA_DWORD:
5517 HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
5518 break;
5519 default:
5520 UNREACHABLE();
5521 }
5522 break;
5523 #undef HORIZONTAL_ARITHMETIC_DF
5524 case VSHF:
5525 #define VSHF_DF(num_of_lanes, int_type) \
5526 for (int i = 0; i < num_of_lanes; ++i) { \
5527 Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5528 num_of_lanes); \
5529 }
5530 switch (DecodeMsaDataFormat()) {
5531 case MSA_BYTE:
5532 VSHF_DF(kMSALanesByte, int8_t);
5533 break;
5534 case MSA_HALF:
5535 VSHF_DF(kMSALanesHalf, int16_t);
5536 break;
5537 case MSA_WORD:
5538 VSHF_DF(kMSALanesWord, int32_t);
5539 break;
5540 case MSA_DWORD:
5541 VSHF_DF(kMSALanesDword, int64_t);
5542 break;
5543 default:
5544 UNREACHABLE();
5545 }
5546 #undef VSHF_DF
5547 break;
5548 case PCKEV:
5549 case PCKOD:
5550 case ILVL:
5551 case ILVR:
5552 case ILVEV:
5553 case ILVOD:
5554 #define INTERLEAVE_PACK_DF(num_of_lanes, int_type) \
5555 for (int i = 0; i < num_of_lanes / 2; ++i) { \
5556 Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5557 num_of_lanes); \
5558 }
5559 switch (DecodeMsaDataFormat()) {
5560 case MSA_BYTE:
5561 INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
5562 break;
5563 case MSA_HALF:
5564 INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
5565 break;
5566 case MSA_WORD:
5567 INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
5568 break;
5569 case MSA_DWORD:
5570 INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
5571 break;
5572 default:
5573 UNREACHABLE();
5574 }
5575 break;
5576 #undef INTERLEAVE_PACK_DF
5577 default:
5578 #define MSA_3R_DF(elem, num_of_lanes) \
5579 for (int i = 0; i < num_of_lanes; i++) { \
5580 wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
5581 }
5582
5583 switch (DecodeMsaDataFormat()) {
5584 case MSA_BYTE:
5585 MSA_3R_DF(b, kMSALanesByte);
5586 break;
5587 case MSA_HALF:
5588 MSA_3R_DF(h, kMSALanesHalf);
5589 break;
5590 case MSA_WORD:
5591 MSA_3R_DF(w, kMSALanesWord);
5592 break;
5593 case MSA_DWORD:
5594 MSA_3R_DF(d, kMSALanesDword);
5595 break;
5596 default:
5597 UNREACHABLE();
5598 }
5599 #undef MSA_3R_DF
5600 break;
5601 }
5602 set_msa_register(wd_reg(), &wd);
5603 TraceMSARegWr(&wd);
5604 }
5605
5606 template <typename T_int, typename T_fp, typename T_reg>
Msa3RFInstrHelper(uint32_t opcode,T_reg ws,T_reg wt,T_reg * wd)5607 void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg* wd) {
5608 const T_int all_ones = static_cast<T_int>(-1);
5609 const T_fp s_element = *reinterpret_cast<T_fp*>(&ws);
5610 const T_fp t_element = *reinterpret_cast<T_fp*>(&wt);
5611 switch (opcode) {
5612 case FCUN: {
5613 if (std::isnan(s_element) || std::isnan(t_element)) {
5614 *wd = all_ones;
5615 } else {
5616 *wd = 0;
5617 }
5618 } break;
5619 case FCEQ: {
5620 if (s_element != t_element || std::isnan(s_element) ||
5621 std::isnan(t_element)) {
5622 *wd = 0;
5623 } else {
5624 *wd = all_ones;
5625 }
5626 } break;
5627 case FCUEQ: {
5628 if (s_element == t_element || std::isnan(s_element) ||
5629 std::isnan(t_element)) {
5630 *wd = all_ones;
5631 } else {
5632 *wd = 0;
5633 }
5634 } break;
5635 case FCLT: {
5636 if (s_element >= t_element || std::isnan(s_element) ||
5637 std::isnan(t_element)) {
5638 *wd = 0;
5639 } else {
5640 *wd = all_ones;
5641 }
5642 } break;
5643 case FCULT: {
5644 if (s_element < t_element || std::isnan(s_element) ||
5645 std::isnan(t_element)) {
5646 *wd = all_ones;
5647 } else {
5648 *wd = 0;
5649 }
5650 } break;
5651 case FCLE: {
5652 if (s_element > t_element || std::isnan(s_element) ||
5653 std::isnan(t_element)) {
5654 *wd = 0;
5655 } else {
5656 *wd = all_ones;
5657 }
5658 } break;
5659 case FCULE: {
5660 if (s_element <= t_element || std::isnan(s_element) ||
5661 std::isnan(t_element)) {
5662 *wd = all_ones;
5663 } else {
5664 *wd = 0;
5665 }
5666 } break;
5667 case FCOR: {
5668 if (std::isnan(s_element) || std::isnan(t_element)) {
5669 *wd = 0;
5670 } else {
5671 *wd = all_ones;
5672 }
5673 } break;
5674 case FCUNE: {
5675 if (s_element != t_element || std::isnan(s_element) ||
5676 std::isnan(t_element)) {
5677 *wd = all_ones;
5678 } else {
5679 *wd = 0;
5680 }
5681 } break;
5682 case FCNE: {
5683 if (s_element == t_element || std::isnan(s_element) ||
5684 std::isnan(t_element)) {
5685 *wd = 0;
5686 } else {
5687 *wd = all_ones;
5688 }
5689 } break;
5690 case FADD:
5691 *wd = bit_cast<T_int>(s_element + t_element);
5692 break;
5693 case FSUB:
5694 *wd = bit_cast<T_int>(s_element - t_element);
5695 break;
5696 case FMUL:
5697 *wd = bit_cast<T_int>(s_element * t_element);
5698 break;
5699 case FDIV: {
5700 if (t_element == 0) {
5701 *wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
5702 } else {
5703 *wd = bit_cast<T_int>(s_element / t_element);
5704 }
5705 } break;
5706 case FMADD:
5707 *wd = bit_cast<T_int>(
5708 std::fma(s_element, t_element, *reinterpret_cast<T_fp*>(wd)));
5709 break;
5710 case FMSUB:
5711 *wd = bit_cast<T_int>(
5712 std::fma(-s_element, t_element, *reinterpret_cast<T_fp*>(wd)));
5713 break;
5714 case FEXP2:
5715 *wd = bit_cast<T_int>(std::ldexp(s_element, static_cast<int>(wt)));
5716 break;
5717 case FMIN:
5718 *wd = bit_cast<T_int>(std::min(s_element, t_element));
5719 break;
5720 case FMAX:
5721 *wd = bit_cast<T_int>(std::max(s_element, t_element));
5722 break;
5723 case FMIN_A: {
5724 *wd = bit_cast<T_int>(
5725 std::fabs(s_element) < std::fabs(t_element) ? s_element : t_element);
5726 } break;
5727 case FMAX_A: {
5728 *wd = bit_cast<T_int>(
5729 std::fabs(s_element) > std::fabs(t_element) ? s_element : t_element);
5730 } break;
5731 case FSOR:
5732 case FSUNE:
5733 case FSNE:
5734 case FSAF:
5735 case FSUN:
5736 case FSEQ:
5737 case FSUEQ:
5738 case FSLT:
5739 case FSULT:
5740 case FSLE:
5741 case FSULE:
5742 UNIMPLEMENTED();
5743 break;
5744 default:
5745 UNREACHABLE();
5746 }
5747 }
5748
5749 template <typename T_int, typename T_int_dbl, typename T_reg>
Msa3RFInstrHelper2(uint32_t opcode,T_reg ws,T_reg wt,T_reg * wd)5750 void Msa3RFInstrHelper2(uint32_t opcode, T_reg ws, T_reg wt, T_reg* wd) {
5751 // using T_uint = typename std::make_unsigned<T_int>::type;
5752 using T_uint_dbl = typename std::make_unsigned<T_int_dbl>::type;
5753 const T_int max_int = std::numeric_limits<T_int>::max();
5754 const T_int min_int = std::numeric_limits<T_int>::min();
5755 const int shift = kBitsPerByte * sizeof(T_int) - 1;
5756 const T_int_dbl reg_s = ws;
5757 const T_int_dbl reg_t = wt;
5758 T_int_dbl product, result;
5759 product = reg_s * reg_t;
5760 switch (opcode) {
5761 case MUL_Q: {
5762 const T_int_dbl min_fix_dbl =
5763 bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5764 const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5765 if (product == min_fix_dbl) {
5766 product = max_fix_dbl;
5767 }
5768 *wd = static_cast<T_int>(product >> shift);
5769 } break;
5770 case MADD_Q: {
5771 result = (product + (static_cast<T_int_dbl>(*wd) << shift)) >> shift;
5772 *wd = static_cast<T_int>(
5773 result > max_int ? max_int : result < min_int ? min_int : result);
5774 } break;
5775 case MSUB_Q: {
5776 result = (-product + (static_cast<T_int_dbl>(*wd) << shift)) >> shift;
5777 *wd = static_cast<T_int>(
5778 result > max_int ? max_int : result < min_int ? min_int : result);
5779 } break;
5780 case MULR_Q: {
5781 const T_int_dbl min_fix_dbl =
5782 bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5783 const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5784 if (product == min_fix_dbl) {
5785 *wd = static_cast<T_int>(max_fix_dbl >> shift);
5786 break;
5787 }
5788 *wd = static_cast<T_int>((product + (1 << (shift - 1))) >> shift);
5789 } break;
5790 case MADDR_Q: {
5791 result = (product + (static_cast<T_int_dbl>(*wd) << shift) +
5792 (1 << (shift - 1))) >>
5793 shift;
5794 *wd = static_cast<T_int>(
5795 result > max_int ? max_int : result < min_int ? min_int : result);
5796 } break;
5797 case MSUBR_Q: {
5798 result = (-product + (static_cast<T_int_dbl>(*wd) << shift) +
5799 (1 << (shift - 1))) >>
5800 shift;
5801 *wd = static_cast<T_int>(
5802 result > max_int ? max_int : result < min_int ? min_int : result);
5803 } break;
5804 default:
5805 UNREACHABLE();
5806 }
5807 }
5808
DecodeTypeMsa3RF()5809 void Simulator::DecodeTypeMsa3RF() {
5810 DCHECK_EQ(kArchVariant, kMips64r6);
5811 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5812 uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
5813 msa_reg_t wd, ws, wt;
5814 if (opcode != FCAF) {
5815 get_msa_register(ws_reg(), &ws);
5816 get_msa_register(wt_reg(), &wt);
5817 }
5818 switch (opcode) {
5819 case FCAF:
5820 wd.d[0] = 0;
5821 wd.d[1] = 0;
5822 break;
5823 case FEXDO:
5824 #define PACK_FLOAT16(sign, exp, frac) \
5825 static_cast<uint16_t>(((sign) << 15) + ((exp) << 10) + (frac))
5826 #define FEXDO_DF(source, dst) \
5827 do { \
5828 element = source; \
5829 aSign = element >> 31; \
5830 aExp = element >> 23 & 0xFF; \
5831 aFrac = element & 0x007FFFFF; \
5832 if (aExp == 0xFF) { \
5833 if (aFrac) { \
5834 /* Input is a NaN */ \
5835 dst = 0x7DFFU; \
5836 break; \
5837 } \
5838 /* Infinity */ \
5839 dst = PACK_FLOAT16(aSign, 0x1F, 0); \
5840 break; \
5841 } else if (aExp == 0 && aFrac == 0) { \
5842 dst = PACK_FLOAT16(aSign, 0, 0); \
5843 break; \
5844 } else { \
5845 int maxexp = 29; \
5846 uint32_t mask; \
5847 uint32_t increment; \
5848 bool rounding_bumps_exp; \
5849 aFrac |= 0x00800000; \
5850 aExp -= 0x71; \
5851 if (aExp < 1) { \
5852 /* Will be denormal in halfprec */ \
5853 mask = 0x00FFFFFF; \
5854 if (aExp >= -11) { \
5855 mask >>= 11 + aExp; \
5856 } \
5857 } else { \
5858 /* Normal number in halfprec */ \
5859 mask = 0x00001FFF; \
5860 } \
5861 switch (MSACSR_ & 3) { \
5862 case kRoundToNearest: \
5863 increment = (mask + 1) >> 1; \
5864 if ((aFrac & mask) == increment) { \
5865 increment = aFrac & (increment << 1); \
5866 } \
5867 break; \
5868 case kRoundToPlusInf: \
5869 increment = aSign ? 0 : mask; \
5870 break; \
5871 case kRoundToMinusInf: \
5872 increment = aSign ? mask : 0; \
5873 break; \
5874 case kRoundToZero: \
5875 increment = 0; \
5876 break; \
5877 } \
5878 rounding_bumps_exp = (aFrac + increment >= 0x01000000); \
5879 if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { \
5880 dst = PACK_FLOAT16(aSign, 0x1F, 0); \
5881 break; \
5882 } \
5883 aFrac += increment; \
5884 if (rounding_bumps_exp) { \
5885 aFrac >>= 1; \
5886 aExp++; \
5887 } \
5888 if (aExp < -10) { \
5889 dst = PACK_FLOAT16(aSign, 0, 0); \
5890 break; \
5891 } \
5892 if (aExp < 0) { \
5893 aFrac >>= -aExp; \
5894 aExp = 0; \
5895 } \
5896 dst = PACK_FLOAT16(aSign, aExp, aFrac >> 13); \
5897 } \
5898 } while (0);
5899 switch (DecodeMsaDataFormat()) {
5900 case MSA_HALF:
5901 for (int i = 0; i < kMSALanesWord; i++) {
5902 uint_fast32_t element;
5903 uint_fast32_t aSign, aFrac;
5904 int_fast32_t aExp;
5905 FEXDO_DF(ws.uw[i], wd.uh[i + kMSALanesHalf / 2])
5906 FEXDO_DF(wt.uw[i], wd.uh[i])
5907 }
5908 break;
5909 case MSA_WORD:
5910 for (int i = 0; i < kMSALanesDword; i++) {
5911 wd.w[i + kMSALanesWord / 2] = bit_cast<int32_t>(
5912 static_cast<float>(bit_cast<double>(ws.d[i])));
5913 wd.w[i] = bit_cast<int32_t>(
5914 static_cast<float>(bit_cast<double>(wt.d[i])));
5915 }
5916 break;
5917 default:
5918 UNREACHABLE();
5919 }
5920 break;
5921 #undef PACK_FLOAT16
5922 #undef FEXDO_DF
5923 case FTQ:
5924 #define FTQ_DF(source, dst, fp_type, int_type) \
5925 element = bit_cast<fp_type>(source) * \
5926 (1U << (sizeof(int_type) * kBitsPerByte - 1)); \
5927 if (element > std::numeric_limits<int_type>::max()) { \
5928 dst = std::numeric_limits<int_type>::max(); \
5929 } else if (element < std::numeric_limits<int_type>::min()) { \
5930 dst = std::numeric_limits<int_type>::min(); \
5931 } else if (std::isnan(element)) { \
5932 dst = 0; \
5933 } else { \
5934 int_type fixed_point; \
5935 round_according_to_msacsr(element, &element, &fixed_point); \
5936 dst = fixed_point; \
5937 }
5938
5939 switch (DecodeMsaDataFormat()) {
5940 case MSA_HALF:
5941 for (int i = 0; i < kMSALanesWord; i++) {
5942 float element;
5943 FTQ_DF(ws.w[i], wd.h[i + kMSALanesHalf / 2], float, int16_t)
5944 FTQ_DF(wt.w[i], wd.h[i], float, int16_t)
5945 }
5946 break;
5947 case MSA_WORD:
5948 double element;
5949 for (int i = 0; i < kMSALanesDword; i++) {
5950 FTQ_DF(ws.d[i], wd.w[i + kMSALanesWord / 2], double, int32_t)
5951 FTQ_DF(wt.d[i], wd.w[i], double, int32_t)
5952 }
5953 break;
5954 default:
5955 UNREACHABLE();
5956 }
5957 break;
5958 #undef FTQ_DF
5959 #define MSA_3RF_DF(T1, T2, Lanes, ws, wt, wd) \
5960 for (int i = 0; i < Lanes; i++) { \
5961 Msa3RFInstrHelper<T1, T2>(opcode, ws, wt, &(wd)); \
5962 }
5963 #define MSA_3RF_DF2(T1, T2, Lanes, ws, wt, wd) \
5964 for (int i = 0; i < Lanes; i++) { \
5965 Msa3RFInstrHelper2<T1, T2>(opcode, ws, wt, &(wd)); \
5966 }
5967 case MADD_Q:
5968 case MSUB_Q:
5969 case MADDR_Q:
5970 case MSUBR_Q:
5971 get_msa_register(wd_reg(), &wd);
5972 V8_FALLTHROUGH;
5973 case MUL_Q:
5974 case MULR_Q:
5975 switch (DecodeMsaDataFormat()) {
5976 case MSA_HALF:
5977 MSA_3RF_DF2(int16_t, int32_t, kMSALanesHalf, ws.h[i], wt.h[i],
5978 wd.h[i])
5979 break;
5980 case MSA_WORD:
5981 MSA_3RF_DF2(int32_t, int64_t, kMSALanesWord, ws.w[i], wt.w[i],
5982 wd.w[i])
5983 break;
5984 default:
5985 UNREACHABLE();
5986 }
5987 break;
5988 default:
5989 if (opcode == FMADD || opcode == FMSUB) {
5990 get_msa_register(wd_reg(), &wd);
5991 }
5992 switch (DecodeMsaDataFormat()) {
5993 case MSA_WORD:
5994 MSA_3RF_DF(int32_t, float, kMSALanesWord, ws.w[i], wt.w[i], wd.w[i])
5995 break;
5996 case MSA_DWORD:
5997 MSA_3RF_DF(int64_t, double, kMSALanesDword, ws.d[i], wt.d[i], wd.d[i])
5998 break;
5999 default:
6000 UNREACHABLE();
6001 }
6002 break;
6003 #undef MSA_3RF_DF
6004 #undef MSA_3RF_DF2
6005 }
6006 set_msa_register(wd_reg(), &wd);
6007 TraceMSARegWr(&wd);
6008 }
6009
DecodeTypeMsaVec()6010 void Simulator::DecodeTypeMsaVec() {
6011 DCHECK_EQ(kArchVariant, kMips64r6);
6012 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
6013 uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
6014 msa_reg_t wd, ws, wt;
6015
6016 get_msa_register(instr_.WsValue(), ws.d);
6017 get_msa_register(instr_.WtValue(), wt.d);
6018 if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) {
6019 get_msa_register(instr_.WdValue(), wd.d);
6020 }
6021
6022 for (int i = 0; i < kMSALanesDword; i++) {
6023 switch (opcode) {
6024 case AND_V:
6025 wd.d[i] = ws.d[i] & wt.d[i];
6026 break;
6027 case OR_V:
6028 wd.d[i] = ws.d[i] | wt.d[i];
6029 break;
6030 case NOR_V:
6031 wd.d[i] = ~(ws.d[i] | wt.d[i]);
6032 break;
6033 case XOR_V:
6034 wd.d[i] = ws.d[i] ^ wt.d[i];
6035 break;
6036 case BMNZ_V:
6037 wd.d[i] = (wt.d[i] & ws.d[i]) | (~wt.d[i] & wd.d[i]);
6038 break;
6039 case BMZ_V:
6040 wd.d[i] = (~wt.d[i] & ws.d[i]) | (wt.d[i] & wd.d[i]);
6041 break;
6042 case BSEL_V:
6043 wd.d[i] = (~wd.d[i] & ws.d[i]) | (wd.d[i] & wt.d[i]);
6044 break;
6045 default:
6046 UNREACHABLE();
6047 }
6048 }
6049 set_msa_register(instr_.WdValue(), wd.d);
6050 TraceMSARegWr(wd.d);
6051 }
6052
DecodeTypeMsa2R()6053 void Simulator::DecodeTypeMsa2R() {
6054 DCHECK_EQ(kArchVariant, kMips64r6);
6055 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
6056 uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
6057 msa_reg_t wd, ws;
6058 switch (opcode) {
6059 case FILL:
6060 switch (DecodeMsaDataFormat()) {
6061 case MSA_BYTE: {
6062 int64_t rs = get_register(instr_.WsValue());
6063 for (int i = 0; i < kMSALanesByte; i++) {
6064 wd.b[i] = rs & 0xFFu;
6065 }
6066 set_msa_register(instr_.WdValue(), wd.b);
6067 TraceMSARegWr(wd.b);
6068 break;
6069 }
6070 case MSA_HALF: {
6071 int64_t rs = get_register(instr_.WsValue());
6072 for (int i = 0; i < kMSALanesHalf; i++) {
6073 wd.h[i] = rs & 0xFFFFu;
6074 }
6075 set_msa_register(instr_.WdValue(), wd.h);
6076 TraceMSARegWr(wd.h);
6077 break;
6078 }
6079 case MSA_WORD: {
6080 int64_t rs = get_register(instr_.WsValue());
6081 for (int i = 0; i < kMSALanesWord; i++) {
6082 wd.w[i] = rs & 0xFFFFFFFFu;
6083 }
6084 set_msa_register(instr_.WdValue(), wd.w);
6085 TraceMSARegWr(wd.w);
6086 break;
6087 }
6088 case MSA_DWORD: {
6089 int64_t rs = get_register(instr_.WsValue());
6090 wd.d[0] = wd.d[1] = rs;
6091 set_msa_register(instr_.WdValue(), wd.d);
6092 TraceMSARegWr(wd.d);
6093 break;
6094 }
6095 default:
6096 UNREACHABLE();
6097 }
6098 break;
6099 case PCNT:
6100 #define PCNT_DF(elem, num_of_lanes) \
6101 get_msa_register(instr_.WsValue(), ws.elem); \
6102 for (int i = 0; i < num_of_lanes; i++) { \
6103 uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
6104 wd.elem[i] = base::bits::CountPopulation(u64elem); \
6105 } \
6106 set_msa_register(instr_.WdValue(), wd.elem); \
6107 TraceMSARegWr(wd.elem)
6108
6109 switch (DecodeMsaDataFormat()) {
6110 case MSA_BYTE:
6111 PCNT_DF(ub, kMSALanesByte);
6112 break;
6113 case MSA_HALF:
6114 PCNT_DF(uh, kMSALanesHalf);
6115 break;
6116 case MSA_WORD:
6117 PCNT_DF(uw, kMSALanesWord);
6118 break;
6119 case MSA_DWORD:
6120 PCNT_DF(ud, kMSALanesDword);
6121 break;
6122 default:
6123 UNREACHABLE();
6124 }
6125 #undef PCNT_DF
6126 break;
6127 case NLOC:
6128 #define NLOC_DF(elem, num_of_lanes) \
6129 get_msa_register(instr_.WsValue(), ws.elem); \
6130 for (int i = 0; i < num_of_lanes; i++) { \
6131 const uint64_t mask = (num_of_lanes == kMSALanesDword) \
6132 ? UINT64_MAX \
6133 : (1ULL << (kMSARegSize / num_of_lanes)) - 1; \
6134 uint64_t u64elem = static_cast<uint64_t>(~ws.elem[i]) & mask; \
6135 wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
6136 (64 - kMSARegSize / num_of_lanes); \
6137 } \
6138 set_msa_register(instr_.WdValue(), wd.elem); \
6139 TraceMSARegWr(wd.elem)
6140
6141 switch (DecodeMsaDataFormat()) {
6142 case MSA_BYTE:
6143 NLOC_DF(ub, kMSALanesByte);
6144 break;
6145 case MSA_HALF:
6146 NLOC_DF(uh, kMSALanesHalf);
6147 break;
6148 case MSA_WORD:
6149 NLOC_DF(uw, kMSALanesWord);
6150 break;
6151 case MSA_DWORD:
6152 NLOC_DF(ud, kMSALanesDword);
6153 break;
6154 default:
6155 UNREACHABLE();
6156 }
6157 #undef NLOC_DF
6158 break;
6159 case NLZC:
6160 #define NLZC_DF(elem, num_of_lanes) \
6161 get_msa_register(instr_.WsValue(), ws.elem); \
6162 for (int i = 0; i < num_of_lanes; i++) { \
6163 uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
6164 wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
6165 (64 - kMSARegSize / num_of_lanes); \
6166 } \
6167 set_msa_register(instr_.WdValue(), wd.elem); \
6168 TraceMSARegWr(wd.elem)
6169
6170 switch (DecodeMsaDataFormat()) {
6171 case MSA_BYTE:
6172 NLZC_DF(ub, kMSALanesByte);
6173 break;
6174 case MSA_HALF:
6175 NLZC_DF(uh, kMSALanesHalf);
6176 break;
6177 case MSA_WORD:
6178 NLZC_DF(uw, kMSALanesWord);
6179 break;
6180 case MSA_DWORD:
6181 NLZC_DF(ud, kMSALanesDword);
6182 break;
6183 default:
6184 UNREACHABLE();
6185 }
6186 #undef NLZC_DF
6187 break;
6188 default:
6189 UNREACHABLE();
6190 }
6191 }
6192
6193 #define BIT(n) (0x1LL << n)
6194 #define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
6195 #define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
isSnan(float fp)6196 static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
isSnan(double fp)6197 static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
6198 #undef QUIET_BIT_S
6199 #undef QUIET_BIT_D
6200
6201 template <typename T_int, typename T_fp, typename T_src, typename T_dst>
Msa2RFInstrHelper(uint32_t opcode,T_src src,T_dst * dst,Simulator * sim)6202 T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst* dst,
6203 Simulator* sim) {
6204 using T_uint = typename std::make_unsigned<T_int>::type;
6205 switch (opcode) {
6206 case FCLASS: {
6207 #define SNAN_BIT BIT(0)
6208 #define QNAN_BIT BIT(1)
6209 #define NEG_INFINITY_BIT BIT(2)
6210 #define NEG_NORMAL_BIT BIT(3)
6211 #define NEG_SUBNORMAL_BIT BIT(4)
6212 #define NEG_ZERO_BIT BIT(5)
6213 #define POS_INFINITY_BIT BIT(6)
6214 #define POS_NORMAL_BIT BIT(7)
6215 #define POS_SUBNORMAL_BIT BIT(8)
6216 #define POS_ZERO_BIT BIT(9)
6217 T_fp element = *reinterpret_cast<T_fp*>(&src);
6218 switch (std::fpclassify(element)) {
6219 case FP_INFINITE:
6220 if (std::signbit(element)) {
6221 *dst = NEG_INFINITY_BIT;
6222 } else {
6223 *dst = POS_INFINITY_BIT;
6224 }
6225 break;
6226 case FP_NAN:
6227 if (isSnan(element)) {
6228 *dst = SNAN_BIT;
6229 } else {
6230 *dst = QNAN_BIT;
6231 }
6232 break;
6233 case FP_NORMAL:
6234 if (std::signbit(element)) {
6235 *dst = NEG_NORMAL_BIT;
6236 } else {
6237 *dst = POS_NORMAL_BIT;
6238 }
6239 break;
6240 case FP_SUBNORMAL:
6241 if (std::signbit(element)) {
6242 *dst = NEG_SUBNORMAL_BIT;
6243 } else {
6244 *dst = POS_SUBNORMAL_BIT;
6245 }
6246 break;
6247 case FP_ZERO:
6248 if (std::signbit(element)) {
6249 *dst = NEG_ZERO_BIT;
6250 } else {
6251 *dst = POS_ZERO_BIT;
6252 }
6253 break;
6254 default:
6255 UNREACHABLE();
6256 }
6257 break;
6258 }
6259 #undef BIT
6260 #undef SNAN_BIT
6261 #undef QNAN_BIT
6262 #undef NEG_INFINITY_BIT
6263 #undef NEG_NORMAL_BIT
6264 #undef NEG_SUBNORMAL_BIT
6265 #undef NEG_ZERO_BIT
6266 #undef POS_INFINITY_BIT
6267 #undef POS_NORMAL_BIT
6268 #undef POS_SUBNORMAL_BIT
6269 #undef POS_ZERO_BIT
6270 case FTRUNC_S: {
6271 T_fp element = bit_cast<T_fp>(src);
6272 const T_int max_int = std::numeric_limits<T_int>::max();
6273 const T_int min_int = std::numeric_limits<T_int>::min();
6274 if (std::isnan(element)) {
6275 *dst = 0;
6276 } else if (element >= static_cast<T_fp>(max_int) || element <= min_int) {
6277 *dst = element >= static_cast<T_fp>(max_int) ? max_int : min_int;
6278 } else {
6279 *dst = static_cast<T_int>(std::trunc(element));
6280 }
6281 break;
6282 }
6283 case FTRUNC_U: {
6284 T_fp element = bit_cast<T_fp>(src);
6285 const T_uint max_int = std::numeric_limits<T_uint>::max();
6286 if (std::isnan(element)) {
6287 *dst = 0;
6288 } else if (element >= static_cast<T_fp>(max_int) || element <= 0) {
6289 *dst = element >= static_cast<T_fp>(max_int) ? max_int : 0;
6290 } else {
6291 *dst = static_cast<T_uint>(std::trunc(element));
6292 }
6293 break;
6294 }
6295 case FSQRT: {
6296 T_fp element = bit_cast<T_fp>(src);
6297 if (element < 0 || std::isnan(element)) {
6298 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6299 } else {
6300 *dst = bit_cast<T_int>(std::sqrt(element));
6301 }
6302 break;
6303 }
6304 case FRSQRT: {
6305 T_fp element = bit_cast<T_fp>(src);
6306 if (element < 0 || std::isnan(element)) {
6307 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6308 } else {
6309 *dst = bit_cast<T_int>(1 / std::sqrt(element));
6310 }
6311 break;
6312 }
6313 case FRCP: {
6314 T_fp element = bit_cast<T_fp>(src);
6315 if (std::isnan(element)) {
6316 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6317 } else {
6318 *dst = bit_cast<T_int>(1 / element);
6319 }
6320 break;
6321 }
6322 case FRINT: {
6323 T_fp element = bit_cast<T_fp>(src);
6324 if (std::isnan(element)) {
6325 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6326 } else {
6327 T_int dummy;
6328 sim->round_according_to_msacsr<T_fp, T_int>(element, &element, &dummy);
6329 *dst = bit_cast<T_int>(element);
6330 }
6331 break;
6332 }
6333 case FLOG2: {
6334 T_fp element = bit_cast<T_fp>(src);
6335 switch (std::fpclassify(element)) {
6336 case FP_NORMAL:
6337 case FP_SUBNORMAL:
6338 *dst = bit_cast<T_int>(std::logb(element));
6339 break;
6340 case FP_ZERO:
6341 *dst = bit_cast<T_int>(-std::numeric_limits<T_fp>::infinity());
6342 break;
6343 case FP_NAN:
6344 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6345 break;
6346 case FP_INFINITE:
6347 if (element < 0) {
6348 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6349 } else {
6350 *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::infinity());
6351 }
6352 break;
6353 default:
6354 UNREACHABLE();
6355 }
6356 break;
6357 }
6358 case FTINT_S: {
6359 T_fp element = bit_cast<T_fp>(src);
6360 const T_int max_int = std::numeric_limits<T_int>::max();
6361 const T_int min_int = std::numeric_limits<T_int>::min();
6362 if (std::isnan(element)) {
6363 *dst = 0;
6364 } else if (element < min_int || element > static_cast<T_fp>(max_int)) {
6365 *dst = element > static_cast<T_fp>(max_int) ? max_int : min_int;
6366 } else {
6367 sim->round_according_to_msacsr<T_fp, T_int>(element, &element, dst);
6368 }
6369 break;
6370 }
6371 case FTINT_U: {
6372 T_fp element = bit_cast<T_fp>(src);
6373 const T_uint max_uint = std::numeric_limits<T_uint>::max();
6374 if (std::isnan(element)) {
6375 *dst = 0;
6376 } else if (element < 0 || element > static_cast<T_fp>(max_uint)) {
6377 *dst = element > static_cast<T_fp>(max_uint) ? max_uint : 0;
6378 } else {
6379 T_uint res;
6380 sim->round_according_to_msacsr<T_fp, T_uint>(element, &element, &res);
6381 *dst = *reinterpret_cast<T_int*>(&res);
6382 }
6383 break;
6384 }
6385 case FFINT_S:
6386 *dst = bit_cast<T_int>(static_cast<T_fp>(src));
6387 break;
6388 case FFINT_U:
6389 using uT_src = typename std::make_unsigned<T_src>::type;
6390 *dst = bit_cast<T_int>(static_cast<T_fp>(bit_cast<uT_src>(src)));
6391 break;
6392 default:
6393 UNREACHABLE();
6394 }
6395 return 0;
6396 }
6397
6398 template <typename T_int, typename T_fp, typename T_reg>
Msa2RFInstrHelper2(uint32_t opcode,T_reg ws,int i)6399 T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
6400 switch (opcode) {
6401 #define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
6402 #define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1F)
6403 #define EXTRACT_FLOAT16_FRAC(fp16) (fp16 & 0x3FF)
6404 #define PACK_FLOAT32(sign, exp, frac) \
6405 static_cast<uint32_t>(((sign) << 31) + ((exp) << 23) + (frac))
6406 #define FEXUP_DF(src_index) \
6407 uint_fast16_t element = ws.uh[src_index]; \
6408 uint_fast32_t aSign, aFrac; \
6409 int_fast32_t aExp; \
6410 aSign = EXTRACT_FLOAT16_SIGN(element); \
6411 aExp = EXTRACT_FLOAT16_EXP(element); \
6412 aFrac = EXTRACT_FLOAT16_FRAC(element); \
6413 if (V8_LIKELY(aExp && aExp != 0x1F)) { \
6414 return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13); \
6415 } else if (aExp == 0x1F) { \
6416 if (aFrac) { \
6417 return bit_cast<int32_t>(std::numeric_limits<float>::quiet_NaN()); \
6418 } else { \
6419 return bit_cast<uint32_t>(std::numeric_limits<float>::infinity()) | \
6420 static_cast<uint32_t>(aSign) << 31; \
6421 } \
6422 } else { \
6423 if (aFrac == 0) { \
6424 return PACK_FLOAT32(aSign, 0, 0); \
6425 } else { \
6426 int_fast16_t shiftCount = \
6427 base::bits::CountLeadingZeros32(static_cast<uint32_t>(aFrac)) - 21; \
6428 aFrac <<= shiftCount; \
6429 aExp = -shiftCount; \
6430 return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13); \
6431 } \
6432 }
6433 case FEXUPL:
6434 if (std::is_same<int32_t, T_int>::value) {
6435 FEXUP_DF(i + kMSALanesWord)
6436 } else {
6437 return bit_cast<int64_t>(
6438 static_cast<double>(bit_cast<float>(ws.w[i + kMSALanesDword])));
6439 }
6440 case FEXUPR:
6441 if (std::is_same<int32_t, T_int>::value) {
6442 FEXUP_DF(i)
6443 } else {
6444 return bit_cast<int64_t>(static_cast<double>(bit_cast<float>(ws.w[i])));
6445 }
6446 case FFQL: {
6447 if (std::is_same<int32_t, T_int>::value) {
6448 return bit_cast<int32_t>(static_cast<float>(ws.h[i + kMSALanesWord]) /
6449 (1U << 15));
6450 } else {
6451 return bit_cast<int64_t>(static_cast<double>(ws.w[i + kMSALanesDword]) /
6452 (1U << 31));
6453 }
6454 break;
6455 }
6456 case FFQR: {
6457 if (std::is_same<int32_t, T_int>::value) {
6458 return bit_cast<int32_t>(static_cast<float>(ws.h[i]) / (1U << 15));
6459 } else {
6460 return bit_cast<int64_t>(static_cast<double>(ws.w[i]) / (1U << 31));
6461 }
6462 break;
6463 default:
6464 UNREACHABLE();
6465 }
6466 }
6467 #undef EXTRACT_FLOAT16_SIGN
6468 #undef EXTRACT_FLOAT16_EXP
6469 #undef EXTRACT_FLOAT16_FRAC
6470 #undef PACK_FLOAT32
6471 #undef FEXUP_DF
6472 }
6473
DecodeTypeMsa2RF()6474 void Simulator::DecodeTypeMsa2RF() {
6475 DCHECK_EQ(kArchVariant, kMips64r6);
6476 DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
6477 uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
6478 msa_reg_t wd, ws;
6479 get_msa_register(ws_reg(), &ws);
6480 if (opcode == FEXUPL || opcode == FEXUPR || opcode == FFQL ||
6481 opcode == FFQR) {
6482 switch (DecodeMsaDataFormat()) {
6483 case MSA_WORD:
6484 for (int i = 0; i < kMSALanesWord; i++) {
6485 wd.w[i] = Msa2RFInstrHelper2<int32_t, float>(opcode, ws, i);
6486 }
6487 break;
6488 case MSA_DWORD:
6489 for (int i = 0; i < kMSALanesDword; i++) {
6490 wd.d[i] = Msa2RFInstrHelper2<int64_t, double>(opcode, ws, i);
6491 }
6492 break;
6493 default:
6494 UNREACHABLE();
6495 }
6496 } else {
6497 switch (DecodeMsaDataFormat()) {
6498 case MSA_WORD:
6499 for (int i = 0; i < kMSALanesWord; i++) {
6500 Msa2RFInstrHelper<int32_t, float>(opcode, ws.w[i], &wd.w[i], this);
6501 }
6502 break;
6503 case MSA_DWORD:
6504 for (int i = 0; i < kMSALanesDword; i++) {
6505 Msa2RFInstrHelper<int64_t, double>(opcode, ws.d[i], &wd.d[i], this);
6506 }
6507 break;
6508 default:
6509 UNREACHABLE();
6510 }
6511 }
6512 set_msa_register(wd_reg(), &wd);
6513 TraceMSARegWr(&wd);
6514 }
6515
DecodeTypeRegister()6516 void Simulator::DecodeTypeRegister() {
6517 // ---------- Execution.
6518 switch (instr_.OpcodeFieldRaw()) {
6519 case COP1:
6520 DecodeTypeRegisterCOP1();
6521 break;
6522 case COP1X:
6523 DecodeTypeRegisterCOP1X();
6524 break;
6525 case SPECIAL:
6526 DecodeTypeRegisterSPECIAL();
6527 break;
6528 case SPECIAL2:
6529 DecodeTypeRegisterSPECIAL2();
6530 break;
6531 case SPECIAL3:
6532 DecodeTypeRegisterSPECIAL3();
6533 break;
6534 case MSA:
6535 switch (instr_.MSAMinorOpcodeField()) {
6536 case kMsaMinor3R:
6537 DecodeTypeMsa3R();
6538 break;
6539 case kMsaMinor3RF:
6540 DecodeTypeMsa3RF();
6541 break;
6542 case kMsaMinorVEC:
6543 DecodeTypeMsaVec();
6544 break;
6545 case kMsaMinor2R:
6546 DecodeTypeMsa2R();
6547 break;
6548 case kMsaMinor2RF:
6549 DecodeTypeMsa2RF();
6550 break;
6551 case kMsaMinorELM:
6552 DecodeTypeMsaELM();
6553 break;
6554 default:
6555 UNREACHABLE();
6556 }
6557 break;
6558 // Unimplemented opcodes raised an error in the configuration step before,
6559 // so we can use the default here to set the destination register in common
6560 // cases.
6561 default:
6562 UNREACHABLE();
6563 }
6564 }
6565
6566 // Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
DecodeTypeImmediate()6567 void Simulator::DecodeTypeImmediate() {
6568 // Instruction fields.
6569 Opcode op = instr_.OpcodeFieldRaw();
6570 int32_t rs_reg = instr_.RsValue();
6571 int64_t rs = get_register(instr_.RsValue());
6572 uint64_t rs_u = static_cast<uint64_t>(rs);
6573 int32_t rt_reg = instr_.RtValue(); // Destination register.
6574 int64_t rt = get_register(rt_reg);
6575 int16_t imm16 = instr_.Imm16Value();
6576 int32_t imm18 = instr_.Imm18Value();
6577
6578 int32_t ft_reg = instr_.FtValue(); // Destination register.
6579
6580 // Zero extended immediate.
6581 uint64_t oe_imm16 = 0xFFFF & imm16;
6582 // Sign extended immediate.
6583 int64_t se_imm16 = imm16;
6584 int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xFFFFFFFFFFFC0000 : 0);
6585
6586 // Next pc.
6587 int64_t next_pc = bad_ra;
6588
6589 // Used for conditional branch instructions.
6590 bool execute_branch_delay_instruction = false;
6591
6592 // Used for arithmetic instructions.
6593 int64_t alu_out = 0;
6594
6595 // Used for memory instructions.
6596 int64_t addr = 0x0;
6597 // Alignment for 32-bit integers used in LWL, LWR, etc.
6598 const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
6599 // Alignment for 64-bit integers used in LDL, LDR, etc.
6600 const int kInt64AlignmentMask = sizeof(uint64_t) - 1;
6601
6602 // Branch instructions common part.
6603 auto BranchAndLinkHelper =
6604 [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
6605 execute_branch_delay_instruction = true;
6606 int64_t current_pc = get_pc();
6607 set_register(31, current_pc + 2 * kInstrSize);
6608 if (do_branch) {
6609 int16_t imm16 = instr_.Imm16Value();
6610 next_pc = current_pc + (imm16 << 2) + kInstrSize;
6611 } else {
6612 next_pc = current_pc + 2 * kInstrSize;
6613 }
6614 };
6615
6616 auto BranchHelper = [this, &next_pc,
6617 &execute_branch_delay_instruction](bool do_branch) {
6618 execute_branch_delay_instruction = true;
6619 int64_t current_pc = get_pc();
6620 if (do_branch) {
6621 int16_t imm16 = instr_.Imm16Value();
6622 next_pc = current_pc + (imm16 << 2) + kInstrSize;
6623 } else {
6624 next_pc = current_pc + 2 * kInstrSize;
6625 }
6626 };
6627
6628 auto BranchHelper_MSA = [this, &next_pc, imm16,
6629 &execute_branch_delay_instruction](bool do_branch) {
6630 execute_branch_delay_instruction = true;
6631 int64_t current_pc = get_pc();
6632 const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
6633 if (do_branch) {
6634 if (FLAG_debug_code) {
6635 int16_t bits = imm16 & 0xFC;
6636 if (imm16 >= 0) {
6637 CHECK_EQ(bits, 0);
6638 } else {
6639 CHECK_EQ(bits ^ 0xFC, 0);
6640 }
6641 }
6642 // jump range :[pc + kInstrSize - 512 * kInstrSize,
6643 // pc + kInstrSize + 511 * kInstrSize]
6644 int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
6645 (bitsIn16Int - 12);
6646 next_pc = current_pc + offset + kInstrSize;
6647 } else {
6648 next_pc = current_pc + 2 * kInstrSize;
6649 }
6650 };
6651
6652 auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6653 int64_t current_pc = get_pc();
6654 CheckForbiddenSlot(current_pc);
6655 if (do_branch) {
6656 int32_t imm = instr_.ImmValue(bits);
6657 imm <<= 32 - bits;
6658 imm >>= 32 - bits;
6659 next_pc = current_pc + (imm << 2) + kInstrSize;
6660 set_register(31, current_pc + kInstrSize);
6661 }
6662 };
6663
6664 auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6665 int64_t current_pc = get_pc();
6666 CheckForbiddenSlot(current_pc);
6667 if (do_branch) {
6668 int32_t imm = instr_.ImmValue(bits);
6669 imm <<= 32 - bits;
6670 imm >>= 32 - bits;
6671 next_pc = get_pc() + (imm << 2) + kInstrSize;
6672 }
6673 };
6674
6675 switch (op) {
6676 // ------------- COP1. Coprocessor instructions.
6677 case COP1:
6678 switch (instr_.RsFieldRaw()) {
6679 case BC1: { // Branch on coprocessor condition.
6680 uint32_t cc = instr_.FBccValue();
6681 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
6682 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
6683 bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
6684 BranchHelper(do_branch);
6685 break;
6686 }
6687 case BC1EQZ:
6688 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
6689 break;
6690 case BC1NEZ:
6691 BranchHelper(get_fpu_register(ft_reg) & 0x1);
6692 break;
6693 case BZ_V: {
6694 msa_reg_t wt;
6695 get_msa_register(wt_reg(), &wt);
6696 BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
6697 } break;
6698 #define BZ_DF(witdh, lanes) \
6699 { \
6700 msa_reg_t wt; \
6701 get_msa_register(wt_reg(), &wt); \
6702 int i; \
6703 for (i = 0; i < lanes; ++i) { \
6704 if (wt.witdh[i] == 0) { \
6705 break; \
6706 } \
6707 } \
6708 BranchHelper_MSA(i != lanes); \
6709 }
6710 case BZ_B:
6711 BZ_DF(b, kMSALanesByte)
6712 break;
6713 case BZ_H:
6714 BZ_DF(h, kMSALanesHalf)
6715 break;
6716 case BZ_W:
6717 BZ_DF(w, kMSALanesWord)
6718 break;
6719 case BZ_D:
6720 BZ_DF(d, kMSALanesDword)
6721 break;
6722 #undef BZ_DF
6723 case BNZ_V: {
6724 msa_reg_t wt;
6725 get_msa_register(wt_reg(), &wt);
6726 BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
6727 } break;
6728 #define BNZ_DF(witdh, lanes) \
6729 { \
6730 msa_reg_t wt; \
6731 get_msa_register(wt_reg(), &wt); \
6732 int i; \
6733 for (i = 0; i < lanes; ++i) { \
6734 if (wt.witdh[i] == 0) { \
6735 break; \
6736 } \
6737 } \
6738 BranchHelper_MSA(i == lanes); \
6739 }
6740 case BNZ_B:
6741 BNZ_DF(b, kMSALanesByte)
6742 break;
6743 case BNZ_H:
6744 BNZ_DF(h, kMSALanesHalf)
6745 break;
6746 case BNZ_W:
6747 BNZ_DF(w, kMSALanesWord)
6748 break;
6749 case BNZ_D:
6750 BNZ_DF(d, kMSALanesDword)
6751 break;
6752 #undef BNZ_DF
6753 default:
6754 UNREACHABLE();
6755 }
6756 break;
6757 // ------------- REGIMM class.
6758 case REGIMM:
6759 switch (instr_.RtFieldRaw()) {
6760 case BLTZ:
6761 BranchHelper(rs < 0);
6762 break;
6763 case BGEZ:
6764 BranchHelper(rs >= 0);
6765 break;
6766 case BLTZAL:
6767 BranchAndLinkHelper(rs < 0);
6768 break;
6769 case BGEZAL:
6770 BranchAndLinkHelper(rs >= 0);
6771 break;
6772 case DAHI:
6773 SetResult(rs_reg, rs + (se_imm16 << 32));
6774 break;
6775 case DATI:
6776 SetResult(rs_reg, rs + (se_imm16 << 48));
6777 break;
6778 default:
6779 UNREACHABLE();
6780 }
6781 break; // case REGIMM.
6782 // ------------- Branch instructions.
6783 // When comparing to zero, the encoding of rt field is always 0, so we don't
6784 // need to replace rt with zero.
6785 case BEQ:
6786 BranchHelper(rs == rt);
6787 break;
6788 case BNE:
6789 BranchHelper(rs != rt);
6790 break;
6791 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
6792 if (kArchVariant == kMips64r6) {
6793 if (rt_reg != 0) {
6794 if (rs_reg == 0) { // BLEZALC
6795 BranchAndLinkCompactHelper(rt <= 0, 16);
6796 } else {
6797 if (rs_reg == rt_reg) { // BGEZALC
6798 BranchAndLinkCompactHelper(rt >= 0, 16);
6799 } else { // BGEUC
6800 BranchCompactHelper(
6801 static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16);
6802 }
6803 }
6804 } else { // BLEZ
6805 BranchHelper(rs <= 0);
6806 }
6807 } else { // BLEZ
6808 BranchHelper(rs <= 0);
6809 }
6810 break;
6811 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
6812 if (kArchVariant == kMips64r6) {
6813 if (rt_reg != 0) {
6814 if (rs_reg == 0) { // BGTZALC
6815 BranchAndLinkCompactHelper(rt > 0, 16);
6816 } else {
6817 if (rt_reg == rs_reg) { // BLTZALC
6818 BranchAndLinkCompactHelper(rt < 0, 16);
6819 } else { // BLTUC
6820 BranchCompactHelper(
6821 static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16);
6822 }
6823 }
6824 } else { // BGTZ
6825 BranchHelper(rs > 0);
6826 }
6827 } else { // BGTZ
6828 BranchHelper(rs > 0);
6829 }
6830 break;
6831 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
6832 if (kArchVariant == kMips64r6) {
6833 if (rt_reg != 0) {
6834 if (rs_reg == 0) { // BLEZC
6835 BranchCompactHelper(rt <= 0, 16);
6836 } else {
6837 if (rs_reg == rt_reg) { // BGEZC
6838 BranchCompactHelper(rt >= 0, 16);
6839 } else { // BGEC/BLEC
6840 BranchCompactHelper(rs >= rt, 16);
6841 }
6842 }
6843 }
6844 } else { // BLEZL
6845 BranchAndLinkHelper(rs <= 0);
6846 }
6847 break;
6848 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
6849 if (kArchVariant == kMips64r6) {
6850 if (rt_reg != 0) {
6851 if (rs_reg == 0) { // BGTZC
6852 BranchCompactHelper(rt > 0, 16);
6853 } else {
6854 if (rs_reg == rt_reg) { // BLTZC
6855 BranchCompactHelper(rt < 0, 16);
6856 } else { // BLTC/BGTC
6857 BranchCompactHelper(rs < rt, 16);
6858 }
6859 }
6860 }
6861 } else { // BGTZL
6862 BranchAndLinkHelper(rs > 0);
6863 }
6864 break;
6865 case POP66: // BEQZC, JIC
6866 if (rs_reg != 0) { // BEQZC
6867 BranchCompactHelper(rs == 0, 21);
6868 } else { // JIC
6869 next_pc = rt + imm16;
6870 }
6871 break;
6872 case POP76: // BNEZC, JIALC
6873 if (rs_reg != 0) { // BNEZC
6874 BranchCompactHelper(rs != 0, 21);
6875 } else { // JIALC
6876 int64_t current_pc = get_pc();
6877 set_register(31, current_pc + kInstrSize);
6878 next_pc = rt + imm16;
6879 }
6880 break;
6881 case BC:
6882 BranchCompactHelper(true, 26);
6883 break;
6884 case BALC:
6885 BranchAndLinkCompactHelper(true, 26);
6886 break;
6887 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
6888 if (kArchVariant == kMips64r6) {
6889 if (rs_reg >= rt_reg) { // BOVC
6890 bool condition = !is_int32(rs) || !is_int32(rt) || !is_int32(rs + rt);
6891 BranchCompactHelper(condition, 16);
6892 } else {
6893 if (rs_reg == 0) { // BEQZALC
6894 BranchAndLinkCompactHelper(rt == 0, 16);
6895 } else { // BEQC
6896 BranchCompactHelper(rt == rs, 16);
6897 }
6898 }
6899 } else { // ADDI
6900 if (HaveSameSign(rs, se_imm16)) {
6901 if (rs > 0) {
6902 if (rs <= Registers::kMaxValue - se_imm16) {
6903 SignalException(kIntegerOverflow);
6904 }
6905 } else if (rs < 0) {
6906 if (rs >= Registers::kMinValue - se_imm16) {
6907 SignalException(kIntegerUnderflow);
6908 }
6909 }
6910 }
6911 SetResult(rt_reg, rs + se_imm16);
6912 }
6913 break;
6914 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
6915 if (kArchVariant == kMips64r6) {
6916 if (rs_reg >= rt_reg) { // BNVC
6917 bool condition = is_int32(rs) && is_int32(rt) && is_int32(rs + rt);
6918 BranchCompactHelper(condition, 16);
6919 } else {
6920 if (rs_reg == 0) { // BNEZALC
6921 BranchAndLinkCompactHelper(rt != 0, 16);
6922 } else { // BNEC
6923 BranchCompactHelper(rt != rs, 16);
6924 }
6925 }
6926 }
6927 break;
6928 // ------------- Arithmetic instructions.
6929 case ADDIU: {
6930 int32_t alu32_out = static_cast<int32_t>(rs + se_imm16);
6931 // Sign-extend result of 32bit operation into 64bit register.
6932 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
6933 break;
6934 }
6935 case DADDIU:
6936 SetResult(rt_reg, rs + se_imm16);
6937 break;
6938 case SLTI:
6939 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
6940 break;
6941 case SLTIU:
6942 SetResult(rt_reg, rs_u < static_cast<uint64_t>(se_imm16) ? 1 : 0);
6943 break;
6944 case ANDI:
6945 SetResult(rt_reg, rs & oe_imm16);
6946 break;
6947 case ORI:
6948 SetResult(rt_reg, rs | oe_imm16);
6949 break;
6950 case XORI:
6951 SetResult(rt_reg, rs ^ oe_imm16);
6952 break;
6953 case LUI:
6954 if (rs_reg != 0) {
6955 // AUI instruction.
6956 DCHECK_EQ(kArchVariant, kMips64r6);
6957 int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16));
6958 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
6959 } else {
6960 // LUI instruction.
6961 int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
6962 // Sign-extend result of 32bit operation into 64bit register.
6963 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
6964 }
6965 break;
6966 case DAUI:
6967 DCHECK_EQ(kArchVariant, kMips64r6);
6968 DCHECK_NE(rs_reg, 0);
6969 SetResult(rt_reg, rs + (se_imm16 << 16));
6970 break;
6971 // ------------- Memory instructions.
6972 case LB:
6973 set_register(rt_reg, ReadB(rs + se_imm16));
6974 break;
6975 case LH:
6976 set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
6977 break;
6978 case LWL: {
6979 local_monitor_.NotifyLoad();
6980 // al_offset is offset of the effective address within an aligned word.
6981 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
6982 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
6983 uint32_t mask = (1 << byte_shift * 8) - 1;
6984 addr = rs + se_imm16 - al_offset;
6985 int32_t val = ReadW(addr, instr_.instr());
6986 val <<= byte_shift * 8;
6987 val |= rt & mask;
6988 set_register(rt_reg, static_cast<int64_t>(val));
6989 break;
6990 }
6991 case LW:
6992 set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
6993 break;
6994 case LWU:
6995 set_register(rt_reg, ReadWU(rs + se_imm16, instr_.instr()));
6996 break;
6997 case LD:
6998 set_register(rt_reg, Read2W(rs + se_imm16, instr_.instr()));
6999 break;
7000 case LBU:
7001 set_register(rt_reg, ReadBU(rs + se_imm16));
7002 break;
7003 case LHU:
7004 set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
7005 break;
7006 case LWR: {
7007 // al_offset is offset of the effective address within an aligned word.
7008 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
7009 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
7010 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
7011 addr = rs + se_imm16 - al_offset;
7012 alu_out = ReadW(addr, instr_.instr());
7013 alu_out = static_cast<uint32_t>(alu_out) >> al_offset * 8;
7014 alu_out |= rt & mask;
7015 set_register(rt_reg, alu_out);
7016 break;
7017 }
7018 case LDL: {
7019 // al_offset is offset of the effective address within an aligned word.
7020 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
7021 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
7022 uint64_t mask = (1UL << byte_shift * 8) - 1;
7023 addr = rs + se_imm16 - al_offset;
7024 alu_out = Read2W(addr, instr_.instr());
7025 alu_out <<= byte_shift * 8;
7026 alu_out |= rt & mask;
7027 set_register(rt_reg, alu_out);
7028 break;
7029 }
7030 case LDR: {
7031 // al_offset is offset of the effective address within an aligned word.
7032 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
7033 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
7034 uint64_t mask = al_offset ? (~0UL << (byte_shift + 1) * 8) : 0UL;
7035 addr = rs + se_imm16 - al_offset;
7036 alu_out = Read2W(addr, instr_.instr());
7037 alu_out = alu_out >> al_offset * 8;
7038 alu_out |= rt & mask;
7039 set_register(rt_reg, alu_out);
7040 break;
7041 }
7042 case SB:
7043 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
7044 break;
7045 case SH:
7046 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
7047 break;
7048 case SWL: {
7049 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
7050 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
7051 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
7052 addr = rs + se_imm16 - al_offset;
7053 uint64_t mem_value = ReadW(addr, instr_.instr()) & mask;
7054 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
7055 WriteW(addr, static_cast<int32_t>(mem_value), instr_.instr());
7056 break;
7057 }
7058 case SW:
7059 WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr_.instr());
7060 break;
7061 case SD:
7062 Write2W(rs + se_imm16, rt, instr_.instr());
7063 break;
7064 case SWR: {
7065 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
7066 uint32_t mask = (1 << al_offset * 8) - 1;
7067 addr = rs + se_imm16 - al_offset;
7068 uint64_t mem_value = ReadW(addr, instr_.instr());
7069 mem_value = (rt << al_offset * 8) | (mem_value & mask);
7070 WriteW(addr, static_cast<int32_t>(mem_value), instr_.instr());
7071 break;
7072 }
7073 case SDL: {
7074 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
7075 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
7076 uint64_t mask = byte_shift ? (~0UL << (al_offset + 1) * 8) : 0;
7077 addr = rs + se_imm16 - al_offset;
7078 uint64_t mem_value = Read2W(addr, instr_.instr()) & mask;
7079 mem_value |= static_cast<uint64_t>(rt) >> byte_shift * 8;
7080 Write2W(addr, mem_value, instr_.instr());
7081 break;
7082 }
7083 case SDR: {
7084 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
7085 uint64_t mask = (1UL << al_offset * 8) - 1;
7086 addr = rs + se_imm16 - al_offset;
7087 uint64_t mem_value = Read2W(addr, instr_.instr());
7088 mem_value = (rt << al_offset * 8) | (mem_value & mask);
7089 Write2W(addr, mem_value, instr_.instr());
7090 break;
7091 }
7092 case LL: {
7093 DCHECK(kArchVariant != kMips64r6);
7094 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
7095 addr = rs + se_imm16;
7096 set_register(rt_reg, ReadW(addr, instr_.instr()));
7097 local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
7098 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
7099 &global_monitor_thread_);
7100 break;
7101 }
7102 case SC: {
7103 DCHECK(kArchVariant != kMips64r6);
7104 addr = rs + se_imm16;
7105 WriteConditionalW(addr, static_cast<int32_t>(rt), instr_.instr(), rt_reg);
7106 break;
7107 }
7108 case LLD: {
7109 DCHECK(kArchVariant != kMips64r6);
7110 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
7111 addr = rs + se_imm16;
7112 set_register(rt_reg, Read2W(addr, instr_.instr()));
7113 local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord);
7114 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
7115 &global_monitor_thread_);
7116 break;
7117 }
7118 case SCD: {
7119 DCHECK(kArchVariant != kMips64r6);
7120 addr = rs + se_imm16;
7121 WriteConditional2W(addr, rt, instr_.instr(), rt_reg);
7122 break;
7123 }
7124 case LWC1:
7125 set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
7126 set_fpu_register_word(ft_reg,
7127 ReadW(rs + se_imm16, instr_.instr(), FLOAT_DOUBLE));
7128 break;
7129 case LDC1:
7130 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
7131 TraceMemRd(addr, get_fpu_register(ft_reg), DOUBLE);
7132 break;
7133 case SWC1: {
7134 int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg));
7135 WriteW(rs + se_imm16, alu_out_32, instr_.instr());
7136 break;
7137 }
7138 case SDC1:
7139 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
7140 TraceMemWr(rs + se_imm16, get_fpu_register(ft_reg), DWORD);
7141 break;
7142 // ------------- PC-Relative instructions.
7143 case PCREL: {
7144 // rt field: checking 5-bits.
7145 int32_t imm21 = instr_.Imm21Value();
7146 int64_t current_pc = get_pc();
7147 uint8_t rt = (imm21 >> kImm16Bits);
7148 switch (rt) {
7149 case ALUIPC:
7150 addr = current_pc + (se_imm16 << 16);
7151 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
7152 break;
7153 case AUIPC:
7154 alu_out = current_pc + (se_imm16 << 16);
7155 break;
7156 default: {
7157 int32_t imm19 = instr_.Imm19Value();
7158 // rt field: checking the most significant 3-bits.
7159 rt = (imm21 >> kImm18Bits);
7160 switch (rt) {
7161 case LDPC:
7162 addr =
7163 (current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
7164 alu_out = Read2W(addr, instr_.instr());
7165 break;
7166 default: {
7167 // rt field: checking the most significant 2-bits.
7168 rt = (imm21 >> kImm19Bits);
7169 switch (rt) {
7170 case LWUPC: {
7171 // Set sign.
7172 imm19 <<= (kOpcodeBits + kRsBits + 2);
7173 imm19 >>= (kOpcodeBits + kRsBits + 2);
7174 addr = current_pc + (imm19 << 2);
7175 alu_out = ReadWU(addr, instr_.instr());
7176 break;
7177 }
7178 case LWPC: {
7179 // Set sign.
7180 imm19 <<= (kOpcodeBits + kRsBits + 2);
7181 imm19 >>= (kOpcodeBits + kRsBits + 2);
7182 addr = current_pc + (imm19 << 2);
7183 alu_out = ReadW(addr, instr_.instr());
7184 break;
7185 }
7186 case ADDIUPC: {
7187 int64_t se_imm19 =
7188 imm19 | ((imm19 & 0x40000) ? 0xFFFFFFFFFFF80000 : 0);
7189 alu_out = current_pc + (se_imm19 << 2);
7190 break;
7191 }
7192 default:
7193 UNREACHABLE();
7194 }
7195 break;
7196 }
7197 }
7198 break;
7199 }
7200 }
7201 SetResult(rs_reg, alu_out);
7202 break;
7203 }
7204 case SPECIAL3: {
7205 switch (instr_.FunctionFieldRaw()) {
7206 case LL_R6: {
7207 DCHECK_EQ(kArchVariant, kMips64r6);
7208 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
7209 int64_t base = get_register(instr_.BaseValue());
7210 int32_t offset9 = instr_.Imm9Value();
7211 addr = base + offset9;
7212 DCHECK_EQ(addr & 0x3, 0);
7213 set_register(rt_reg, ReadW(addr, instr_.instr()));
7214 local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
7215 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
7216 addr, &global_monitor_thread_);
7217 break;
7218 }
7219 case LLD_R6: {
7220 DCHECK_EQ(kArchVariant, kMips64r6);
7221 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
7222 int64_t base = get_register(instr_.BaseValue());
7223 int32_t offset9 = instr_.Imm9Value();
7224 addr = base + offset9;
7225 DCHECK_EQ(addr & kPointerAlignmentMask, 0);
7226 set_register(rt_reg, Read2W(addr, instr_.instr()));
7227 local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord);
7228 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
7229 addr, &global_monitor_thread_);
7230 break;
7231 }
7232 case SC_R6: {
7233 DCHECK_EQ(kArchVariant, kMips64r6);
7234 int64_t base = get_register(instr_.BaseValue());
7235 int32_t offset9 = instr_.Imm9Value();
7236 addr = base + offset9;
7237 DCHECK_EQ(addr & 0x3, 0);
7238 WriteConditionalW(addr, static_cast<int32_t>(rt), instr_.instr(),
7239 rt_reg);
7240 break;
7241 }
7242 case SCD_R6: {
7243 DCHECK_EQ(kArchVariant, kMips64r6);
7244 int64_t base = get_register(instr_.BaseValue());
7245 int32_t offset9 = instr_.Imm9Value();
7246 addr = base + offset9;
7247 DCHECK_EQ(addr & kPointerAlignmentMask, 0);
7248 WriteConditional2W(addr, rt, instr_.instr(), rt_reg);
7249 break;
7250 }
7251 default:
7252 UNREACHABLE();
7253 }
7254 break;
7255 }
7256
7257 case MSA:
7258 switch (instr_.MSAMinorOpcodeField()) {
7259 case kMsaMinorI8:
7260 DecodeTypeMsaI8();
7261 break;
7262 case kMsaMinorI5:
7263 DecodeTypeMsaI5();
7264 break;
7265 case kMsaMinorI10:
7266 DecodeTypeMsaI10();
7267 break;
7268 case kMsaMinorELM:
7269 DecodeTypeMsaELM();
7270 break;
7271 case kMsaMinorBIT:
7272 DecodeTypeMsaBIT();
7273 break;
7274 case kMsaMinorMI10:
7275 DecodeTypeMsaMI10();
7276 break;
7277 default:
7278 UNREACHABLE();
7279 }
7280 break;
7281 default:
7282 UNREACHABLE();
7283 }
7284
7285 if (execute_branch_delay_instruction) {
7286 // Execute branch delay slot
7287 // We don't check for end_sim_pc. First it should not be met as the current
7288 // pc is valid. Secondly a jump should always execute its branch delay slot.
7289 Instruction* branch_delay_instr =
7290 reinterpret_cast<Instruction*>(get_pc() + kInstrSize);
7291 BranchDelayInstructionDecode(branch_delay_instr);
7292 }
7293
7294 // If needed update pc after the branch delay execution.
7295 if (next_pc != bad_ra) {
7296 set_pc(next_pc);
7297 }
7298 }
7299
7300 // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
DecodeTypeJump()7301 void Simulator::DecodeTypeJump() {
7302 // instr_ will be overwritten by BranchDelayInstructionDecode(), so we save
7303 // the result of IsLinkingInstruction now.
7304 bool isLinkingInstr = instr_.IsLinkingInstruction();
7305 // Get current pc.
7306 int64_t current_pc = get_pc();
7307 // Get unchanged bits of pc.
7308 int64_t pc_high_bits = current_pc & 0xFFFFFFFFF0000000;
7309 // Next pc.
7310 int64_t next_pc = pc_high_bits | (instr_.Imm26Value() << 2);
7311
7312 // Execute branch delay slot.
7313 // We don't check for end_sim_pc. First it should not be met as the current pc
7314 // is valid. Secondly a jump should always execute its branch delay slot.
7315 Instruction* branch_delay_instr =
7316 reinterpret_cast<Instruction*>(current_pc + kInstrSize);
7317 BranchDelayInstructionDecode(branch_delay_instr);
7318
7319 // Update pc and ra if necessary.
7320 // Do this after the branch delay execution.
7321 if (isLinkingInstr) {
7322 set_register(31, current_pc + 2 * kInstrSize);
7323 }
7324 set_pc(next_pc);
7325 pc_modified_ = true;
7326 }
7327
7328 // Executes the current instruction.
InstructionDecode(Instruction * instr)7329 void Simulator::InstructionDecode(Instruction* instr) {
7330 if (v8::internal::FLAG_check_icache) {
7331 CheckICache(i_cache(), instr);
7332 }
7333 pc_modified_ = false;
7334
7335 v8::base::EmbeddedVector<char, 256> buffer;
7336
7337 if (::v8::internal::FLAG_trace_sim) {
7338 base::SNPrintF(trace_buf_, " ");
7339 disasm::NameConverter converter;
7340 disasm::Disassembler dasm(converter);
7341 // Use a reasonably large buffer.
7342 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
7343 }
7344
7345 instr_ = instr;
7346 switch (instr_.InstructionType()) {
7347 case Instruction::kRegisterType:
7348 DecodeTypeRegister();
7349 break;
7350 case Instruction::kImmediateType:
7351 DecodeTypeImmediate();
7352 break;
7353 case Instruction::kJumpType:
7354 DecodeTypeJump();
7355 break;
7356 default:
7357 UNSUPPORTED();
7358 }
7359
7360 if (::v8::internal::FLAG_trace_sim) {
7361 PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
7362 reinterpret_cast<intptr_t>(instr), buffer.begin(),
7363 trace_buf_.begin());
7364 }
7365
7366 if (!pc_modified_) {
7367 set_register(pc, reinterpret_cast<int64_t>(instr) + kInstrSize);
7368 }
7369 }
7370
Execute()7371 void Simulator::Execute() {
7372 // Get the PC to simulate. Cannot use the accessor here as we need the
7373 // raw PC value and not the one used as input to arithmetic instructions.
7374 int64_t program_counter = get_pc();
7375 if (::v8::internal::FLAG_stop_sim_at == 0) {
7376 // Fast version of the dispatch loop without checking whether the simulator
7377 // should be stopping at a particular executed instruction.
7378 while (program_counter != end_sim_pc) {
7379 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
7380 icount_++;
7381 InstructionDecode(instr);
7382 program_counter = get_pc();
7383 }
7384 } else {
7385 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
7386 // we reach the particular instruction count.
7387 while (program_counter != end_sim_pc) {
7388 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
7389 icount_++;
7390 if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) {
7391 MipsDebugger dbg(this);
7392 dbg.Debug();
7393 } else {
7394 InstructionDecode(instr);
7395 }
7396 program_counter = get_pc();
7397 }
7398 }
7399 }
7400
CallInternal(Address entry)7401 void Simulator::CallInternal(Address entry) {
7402 // Adjust JS-based stack limit to C-based stack limit.
7403 isolate_->stack_guard()->AdjustStackLimitForSimulator();
7404
7405 // Prepare to execute the code at entry.
7406 set_register(pc, static_cast<int64_t>(entry));
7407 // Put down marker for end of simulation. The simulator will stop simulation
7408 // when the PC reaches this value. By saving the "end simulation" value into
7409 // the LR the simulation stops when returning to this call point.
7410 set_register(ra, end_sim_pc);
7411
7412 // Remember the values of callee-saved registers.
7413 // The code below assumes that r9 is not used as sb (static base) in
7414 // simulator code and therefore is regarded as a callee-saved register.
7415 int64_t s0_val = get_register(s0);
7416 int64_t s1_val = get_register(s1);
7417 int64_t s2_val = get_register(s2);
7418 int64_t s3_val = get_register(s3);
7419 int64_t s4_val = get_register(s4);
7420 int64_t s5_val = get_register(s5);
7421 int64_t s6_val = get_register(s6);
7422 int64_t s7_val = get_register(s7);
7423 int64_t gp_val = get_register(gp);
7424 int64_t sp_val = get_register(sp);
7425 int64_t fp_val = get_register(fp);
7426
7427 // Set up the callee-saved registers with a known value. To be able to check
7428 // that they are preserved properly across JS execution.
7429 int64_t callee_saved_value = icount_;
7430 set_register(s0, callee_saved_value);
7431 set_register(s1, callee_saved_value);
7432 set_register(s2, callee_saved_value);
7433 set_register(s3, callee_saved_value);
7434 set_register(s4, callee_saved_value);
7435 set_register(s5, callee_saved_value);
7436 set_register(s6, callee_saved_value);
7437 set_register(s7, callee_saved_value);
7438 set_register(gp, callee_saved_value);
7439 set_register(fp, callee_saved_value);
7440
7441 // Start the simulation.
7442 Execute();
7443
7444 // Check that the callee-saved registers have been preserved.
7445 CHECK_EQ(callee_saved_value, get_register(s0));
7446 CHECK_EQ(callee_saved_value, get_register(s1));
7447 CHECK_EQ(callee_saved_value, get_register(s2));
7448 CHECK_EQ(callee_saved_value, get_register(s3));
7449 CHECK_EQ(callee_saved_value, get_register(s4));
7450 CHECK_EQ(callee_saved_value, get_register(s5));
7451 CHECK_EQ(callee_saved_value, get_register(s6));
7452 CHECK_EQ(callee_saved_value, get_register(s7));
7453 CHECK_EQ(callee_saved_value, get_register(gp));
7454 CHECK_EQ(callee_saved_value, get_register(fp));
7455
7456 // Restore callee-saved registers with the original value.
7457 set_register(s0, s0_val);
7458 set_register(s1, s1_val);
7459 set_register(s2, s2_val);
7460 set_register(s3, s3_val);
7461 set_register(s4, s4_val);
7462 set_register(s5, s5_val);
7463 set_register(s6, s6_val);
7464 set_register(s7, s7_val);
7465 set_register(gp, gp_val);
7466 set_register(sp, sp_val);
7467 set_register(fp, fp_val);
7468 }
7469
CallImpl(Address entry,int argument_count,const intptr_t * arguments)7470 intptr_t Simulator::CallImpl(Address entry, int argument_count,
7471 const intptr_t* arguments) {
7472 constexpr int kRegisterPassedArguments = 8;
7473 // Set up arguments.
7474
7475 // First four arguments passed in registers in both ABI's.
7476 int reg_arg_count = std::min(kRegisterPassedArguments, argument_count);
7477 if (reg_arg_count > 0) set_register(a0, arguments[0]);
7478 if (reg_arg_count > 1) set_register(a1, arguments[1]);
7479 if (reg_arg_count > 2) set_register(a2, arguments[2]);
7480 if (reg_arg_count > 3) set_register(a3, arguments[3]);
7481
7482 // Up to eight arguments passed in registers in N64 ABI.
7483 // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this.
7484 if (reg_arg_count > 4) set_register(a4, arguments[4]);
7485 if (reg_arg_count > 5) set_register(a5, arguments[5]);
7486 if (reg_arg_count > 6) set_register(a6, arguments[6]);
7487 if (reg_arg_count > 7) set_register(a7, arguments[7]);
7488
7489 // Remaining arguments passed on stack.
7490 int64_t original_stack = get_register(sp);
7491 // Compute position of stack on entry to generated code.
7492 int stack_args_count = argument_count - reg_arg_count;
7493 int stack_args_size = stack_args_count * sizeof(*arguments) + kCArgsSlotsSize;
7494 int64_t entry_stack = original_stack - stack_args_size;
7495
7496 if (base::OS::ActivationFrameAlignment() != 0) {
7497 entry_stack &= -base::OS::ActivationFrameAlignment();
7498 }
7499 // Store remaining arguments on stack, from low to high memory.
7500 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
7501 memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count,
7502 stack_args_count * sizeof(*arguments));
7503 set_register(sp, entry_stack);
7504
7505 CallInternal(entry);
7506
7507 // Pop stack passed arguments.
7508 CHECK_EQ(entry_stack, get_register(sp));
7509 set_register(sp, original_stack);
7510
7511 return get_register(v0);
7512 }
7513
CallFP(Address entry,double d0,double d1)7514 double Simulator::CallFP(Address entry, double d0, double d1) {
7515 if (!IsMipsSoftFloatABI) {
7516 const FPURegister fparg2 = f13;
7517 set_fpu_register_double(f12, d0);
7518 set_fpu_register_double(fparg2, d1);
7519 } else {
7520 int buffer[2];
7521 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
7522 memcpy(buffer, &d0, sizeof(d0));
7523 set_dw_register(a0, buffer);
7524 memcpy(buffer, &d1, sizeof(d1));
7525 set_dw_register(a2, buffer);
7526 }
7527 CallInternal(entry);
7528 if (!IsMipsSoftFloatABI) {
7529 return get_fpu_register_double(f0);
7530 } else {
7531 return get_double_from_register_pair(v0);
7532 }
7533 }
7534
PushAddress(uintptr_t address)7535 uintptr_t Simulator::PushAddress(uintptr_t address) {
7536 int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
7537 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
7538 *stack_slot = address;
7539 set_register(sp, new_sp);
7540 return new_sp;
7541 }
7542
PopAddress()7543 uintptr_t Simulator::PopAddress() {
7544 int64_t current_sp = get_register(sp);
7545 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
7546 uintptr_t address = *stack_slot;
7547 set_register(sp, current_sp + sizeof(uintptr_t));
7548 return address;
7549 }
7550
LocalMonitor()7551 Simulator::LocalMonitor::LocalMonitor()
7552 : access_state_(MonitorAccess::Open),
7553 tagged_addr_(0),
7554 size_(TransactionSize::None) {}
7555
Clear()7556 void Simulator::LocalMonitor::Clear() {
7557 access_state_ = MonitorAccess::Open;
7558 tagged_addr_ = 0;
7559 size_ = TransactionSize::None;
7560 }
7561
NotifyLoad()7562 void Simulator::LocalMonitor::NotifyLoad() {
7563 if (access_state_ == MonitorAccess::RMW) {
7564 // A non linked load could clear the local monitor. As a result, it's
7565 // most strict to unconditionally clear the local monitor on load.
7566 Clear();
7567 }
7568 }
7569
NotifyLoadLinked(uintptr_t addr,TransactionSize size)7570 void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
7571 TransactionSize size) {
7572 access_state_ = MonitorAccess::RMW;
7573 tagged_addr_ = addr;
7574 size_ = size;
7575 }
7576
NotifyStore()7577 void Simulator::LocalMonitor::NotifyStore() {
7578 if (access_state_ == MonitorAccess::RMW) {
7579 // A non exclusive store could clear the local monitor. As a result, it's
7580 // most strict to unconditionally clear the local monitor on store.
7581 Clear();
7582 }
7583 }
7584
NotifyStoreConditional(uintptr_t addr,TransactionSize size)7585 bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
7586 TransactionSize size) {
7587 if (access_state_ == MonitorAccess::RMW) {
7588 if (addr == tagged_addr_ && size_ == size) {
7589 Clear();
7590 return true;
7591 } else {
7592 return false;
7593 }
7594 } else {
7595 DCHECK(access_state_ == MonitorAccess::Open);
7596 return false;
7597 }
7598 }
7599
LinkedAddress()7600 Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
7601 : access_state_(MonitorAccess::Open),
7602 tagged_addr_(0),
7603 next_(nullptr),
7604 prev_(nullptr),
7605 failure_counter_(0) {}
7606
Clear_Locked()7607 void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
7608 access_state_ = MonitorAccess::Open;
7609 tagged_addr_ = 0;
7610 }
7611
NotifyLoadLinked_Locked(uintptr_t addr)7612 void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
7613 uintptr_t addr) {
7614 access_state_ = MonitorAccess::RMW;
7615 tagged_addr_ = addr;
7616 }
7617
NotifyStore_Locked()7618 void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
7619 if (access_state_ == MonitorAccess::RMW) {
7620 // A non exclusive store could clear the global monitor. As a result, it's
7621 // most strict to unconditionally clear global monitors on store.
7622 Clear_Locked();
7623 }
7624 }
7625
NotifyStoreConditional_Locked(uintptr_t addr,bool is_requesting_thread)7626 bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
7627 uintptr_t addr, bool is_requesting_thread) {
7628 if (access_state_ == MonitorAccess::RMW) {
7629 if (is_requesting_thread) {
7630 if (addr == tagged_addr_) {
7631 Clear_Locked();
7632 // Introduce occasional sc/scd failures. This is to simulate the
7633 // behavior of hardware, which can randomly fail due to background
7634 // cache evictions.
7635 if (failure_counter_++ >= kMaxFailureCounter) {
7636 failure_counter_ = 0;
7637 return false;
7638 } else {
7639 return true;
7640 }
7641 }
7642 } else if ((addr & kExclusiveTaggedAddrMask) ==
7643 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
7644 // Check the masked addresses when responding to a successful lock by
7645 // another thread so the implementation is more conservative (i.e. the
7646 // granularity of locking is as large as possible.)
7647 Clear_Locked();
7648 return false;
7649 }
7650 }
7651 return false;
7652 }
7653
NotifyLoadLinked_Locked(uintptr_t addr,LinkedAddress * linked_address)7654 void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
7655 uintptr_t addr, LinkedAddress* linked_address) {
7656 linked_address->NotifyLoadLinked_Locked(addr);
7657 PrependProcessor_Locked(linked_address);
7658 }
7659
NotifyStore_Locked(LinkedAddress * linked_address)7660 void Simulator::GlobalMonitor::NotifyStore_Locked(
7661 LinkedAddress* linked_address) {
7662 // Notify each thread of the store operation.
7663 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
7664 iter->NotifyStore_Locked();
7665 }
7666 }
7667
NotifyStoreConditional_Locked(uintptr_t addr,LinkedAddress * linked_address)7668 bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
7669 uintptr_t addr, LinkedAddress* linked_address) {
7670 DCHECK(IsProcessorInLinkedList_Locked(linked_address));
7671 if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
7672 // Notify the other processors that this StoreConditional succeeded.
7673 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
7674 if (iter != linked_address) {
7675 iter->NotifyStoreConditional_Locked(addr, false);
7676 }
7677 }
7678 return true;
7679 } else {
7680 return false;
7681 }
7682 }
7683
IsProcessorInLinkedList_Locked(LinkedAddress * linked_address) const7684 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
7685 LinkedAddress* linked_address) const {
7686 return head_ == linked_address || linked_address->next_ ||
7687 linked_address->prev_;
7688 }
7689
PrependProcessor_Locked(LinkedAddress * linked_address)7690 void Simulator::GlobalMonitor::PrependProcessor_Locked(
7691 LinkedAddress* linked_address) {
7692 if (IsProcessorInLinkedList_Locked(linked_address)) {
7693 return;
7694 }
7695
7696 if (head_) {
7697 head_->prev_ = linked_address;
7698 }
7699 linked_address->prev_ = nullptr;
7700 linked_address->next_ = head_;
7701 head_ = linked_address;
7702 }
7703
RemoveLinkedAddress(LinkedAddress * linked_address)7704 void Simulator::GlobalMonitor::RemoveLinkedAddress(
7705 LinkedAddress* linked_address) {
7706 base::MutexGuard lock_guard(&mutex);
7707 if (!IsProcessorInLinkedList_Locked(linked_address)) {
7708 return;
7709 }
7710
7711 if (linked_address->prev_) {
7712 linked_address->prev_->next_ = linked_address->next_;
7713 } else {
7714 head_ = linked_address->next_;
7715 }
7716 if (linked_address->next_) {
7717 linked_address->next_->prev_ = linked_address->prev_;
7718 }
7719 linked_address->prev_ = nullptr;
7720 linked_address->next_ = nullptr;
7721 }
7722
7723 #undef SScanF
7724
7725 } // namespace internal
7726 } // namespace v8
7727
7728 #endif // USE_SIMULATOR
7729