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