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