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