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