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