blob: 9519865c8231eab71bcc54840827e82537b702fe [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#if V8_TARGET_ARCH_MIPS64
11
12#include "src/assembler.h"
13#include "src/base/bits.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/disasm.h"
16#include "src/mips64/constants-mips64.h"
17#include "src/mips64/simulator-mips64.h"
18#include "src/ostreams.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010019#include "src/runtime/runtime-utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020
21// Only build the simulator if not compiling for real MIPS hardware.
22#if defined(USE_SIMULATOR)
23
24namespace v8 {
25namespace internal {
26
Ben Murdochda12d292016-06-02 14:46:10 +010027// Util functions.
28inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029
30uint32_t get_fcsr_condition_bit(uint32_t cc) {
31 if (cc == 0) {
32 return 23;
33 } else {
34 return 24 + cc;
35 }
36}
37
38
39static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
40 uint64_t u0, v0, w0;
41 int64_t u1, v1, w1, w2, t;
42
43 u0 = u & 0xffffffffL;
44 u1 = u >> 32;
45 v0 = v & 0xffffffffL;
46 v1 = v >> 32;
47
48 w0 = u0 * v0;
49 t = u1 * v0 + (w0 >> 32);
50 w1 = t & 0xffffffffL;
51 w2 = t >> 32;
52 w1 = u0 * v1 + w1;
53
54 return u1 * v1 + w2 + (w1 >> 32);
55}
56
57
58// This macro provides a platform independent use of sscanf. The reason for
59// SScanF not being implemented in a platform independent was through
60// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
61// Library does not provide vsscanf.
62#define SScanF sscanf // NOLINT
63
64// The MipsDebugger class is used by the simulator while debugging simulated
65// code.
66class MipsDebugger {
67 public:
68 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
69 ~MipsDebugger();
70
71 void Stop(Instruction* instr);
72 void Debug();
73 // Print all registers with a nice formatting.
74 void PrintAllRegs();
75 void PrintAllRegsIncludingFPU();
76
77 private:
78 // We set the breakpoint code to 0xfffff to easily recognize it.
79 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
80 static const Instr kNopInstr = 0x0;
81
82 Simulator* sim_;
83
84 int64_t GetRegisterValue(int regnum);
85 int64_t GetFPURegisterValue(int regnum);
86 float GetFPURegisterValueFloat(int regnum);
87 double GetFPURegisterValueDouble(int regnum);
88 bool GetValue(const char* desc, int64_t* value);
89
90 // Set or delete a breakpoint. Returns true if successful.
91 bool SetBreakpoint(Instruction* breakpc);
92 bool DeleteBreakpoint(Instruction* breakpc);
93
94 // Undo and redo all breakpoints. This is needed to bracket disassembly and
95 // execution to skip past breakpoints when run from the debugger.
96 void UndoBreakpoints();
97 void RedoBreakpoints();
98};
99
100
101MipsDebugger::~MipsDebugger() {
102}
103
104
105#ifdef GENERATED_CODE_COVERAGE
106static FILE* coverage_log = NULL;
107
108
109static void InitializeCoverage() {
110 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
111 if (file_name != NULL) {
112 coverage_log = fopen(file_name, "aw+");
113 }
114}
115
116
117void MipsDebugger::Stop(Instruction* instr) {
118 // Get the stop code.
119 uint32_t code = instr->Bits(25, 6);
120 // Retrieve the encoded address, which comes just after this stop.
121 char** msg_address =
122 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
123 char* msg = *msg_address;
124 DCHECK(msg != NULL);
125
126 // Update this stop description.
127 if (!watched_stops_[code].desc) {
128 watched_stops_[code].desc = msg;
129 }
130
131 if (strlen(msg) > 0) {
132 if (coverage_log != NULL) {
133 fprintf(coverage_log, "%s\n", str);
134 fflush(coverage_log);
135 }
136 // Overwrite the instruction and address with nops.
137 instr->SetInstructionBits(kNopInstr);
138 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
139 }
140 // TODO(yuyin): 2 -> 3?
141 sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstructionSize);
142}
143
144
145#else // GENERATED_CODE_COVERAGE
146
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148
149static void InitializeCoverage() {}
150
151
152void MipsDebugger::Stop(Instruction* instr) {
153 // Get the stop code.
154 uint32_t code = instr->Bits(25, 6);
155 // Retrieve the encoded address, which comes just after this stop.
156 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
157 Instruction::kInstrSize);
158 // Update this stop description.
159 if (!sim_->watched_stops_[code].desc) {
160 sim_->watched_stops_[code].desc = msg;
161 }
162 PrintF("Simulator hit %s (%u)\n", msg, code);
163 // TODO(yuyin): 2 -> 3?
164 sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstrSize);
165 Debug();
166}
167#endif // GENERATED_CODE_COVERAGE
168
169
170int64_t MipsDebugger::GetRegisterValue(int regnum) {
171 if (regnum == kNumSimuRegisters) {
172 return sim_->get_pc();
173 } else {
174 return sim_->get_register(regnum);
175 }
176}
177
178
179int64_t MipsDebugger::GetFPURegisterValue(int regnum) {
180 if (regnum == kNumFPURegisters) {
181 return sim_->get_pc();
182 } else {
183 return sim_->get_fpu_register(regnum);
184 }
185}
186
187
188float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
189 if (regnum == kNumFPURegisters) {
190 return sim_->get_pc();
191 } else {
192 return sim_->get_fpu_register_float(regnum);
193 }
194}
195
196
197double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
198 if (regnum == kNumFPURegisters) {
199 return sim_->get_pc();
200 } else {
201 return sim_->get_fpu_register_double(regnum);
202 }
203}
204
205
206bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
207 int regnum = Registers::Number(desc);
208 int fpuregnum = FPURegisters::Number(desc);
209
210 if (regnum != kInvalidRegister) {
211 *value = GetRegisterValue(regnum);
212 return true;
213 } else if (fpuregnum != kInvalidFPURegister) {
214 *value = GetFPURegisterValue(fpuregnum);
215 return true;
216 } else if (strncmp(desc, "0x", 2) == 0) {
217 return SScanF(desc + 2, "%" SCNx64,
218 reinterpret_cast<uint64_t*>(value)) == 1;
219 } else {
220 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
221 }
222 return false;
223}
224
225
226bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
227 // Check if a breakpoint can be set. If not return without any side-effects.
228 if (sim_->break_pc_ != NULL) {
229 return false;
230 }
231
232 // Set the breakpoint.
233 sim_->break_pc_ = breakpc;
234 sim_->break_instr_ = breakpc->InstructionBits();
235 // Not setting the breakpoint instruction in the code itself. It will be set
236 // when the debugger shell continues.
237 return true;
238}
239
240
241bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
242 if (sim_->break_pc_ != NULL) {
243 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
244 }
245
246 sim_->break_pc_ = NULL;
247 sim_->break_instr_ = 0;
248 return true;
249}
250
251
252void MipsDebugger::UndoBreakpoints() {
253 if (sim_->break_pc_ != NULL) {
254 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
255 }
256}
257
258
259void MipsDebugger::RedoBreakpoints() {
260 if (sim_->break_pc_ != NULL) {
261 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
262 }
263}
264
265
266void MipsDebugger::PrintAllRegs() {
267#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
268
269 PrintF("\n");
270 // at, v0, a0.
271 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
272 REG_INFO(1), REG_INFO(2), REG_INFO(4));
273 // v1, a1.
274 PrintF("%34s\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
275 "", REG_INFO(3), REG_INFO(5));
276 // a2.
277 PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(6));
278 // a3.
279 PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(7));
280 PrintF("\n");
281 // a4-t3, s0-s7
282 for (int i = 0; i < 8; i++) {
283 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
284 REG_INFO(8+i), REG_INFO(16+i));
285 }
286 PrintF("\n");
287 // t8, k0, LO.
288 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
289 REG_INFO(24), REG_INFO(26), REG_INFO(32));
290 // t9, k1, HI.
291 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
292 REG_INFO(25), REG_INFO(27), REG_INFO(33));
293 // sp, fp, gp.
294 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
295 REG_INFO(29), REG_INFO(30), REG_INFO(28));
296 // pc.
297 PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
298 REG_INFO(31), REG_INFO(34));
299
300#undef REG_INFO
301#undef FPU_REG_INFO
302}
303
304
305void MipsDebugger::PrintAllRegsIncludingFPU() {
306#define FPU_REG_INFO(n) FPURegisters::Name(n), \
307 GetFPURegisterValue(n), \
308 GetFPURegisterValueDouble(n)
309
310 PrintAllRegs();
311
312 PrintF("\n\n");
313 // f0, f1, f2, ... f31.
314 // TODO(plind): consider printing 2 columns for space efficiency.
315 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(0) );
316 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(1) );
317 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(2) );
318 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(3) );
319 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(4) );
320 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(5) );
321 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(6) );
322 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(7) );
323 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(8) );
324 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(9) );
325 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(10));
326 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(11));
327 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(12));
328 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(13));
329 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(14));
330 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(15));
331 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(16));
332 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(17));
333 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(18));
334 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(19));
335 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(20));
336 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(21));
337 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(22));
338 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(23));
339 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(24));
340 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(25));
341 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(26));
342 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(27));
343 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(28));
344 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(29));
345 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(30));
346 PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(31));
347
348#undef REG_INFO
349#undef FPU_REG_INFO
350}
351
352
353void MipsDebugger::Debug() {
354 intptr_t last_pc = -1;
355 bool done = false;
356
357#define COMMAND_SIZE 63
358#define ARG_SIZE 255
359
360#define STR(a) #a
361#define XSTR(a) STR(a)
362
363 char cmd[COMMAND_SIZE + 1];
364 char arg1[ARG_SIZE + 1];
365 char arg2[ARG_SIZE + 1];
366 char* argv[3] = { cmd, arg1, arg2 };
367
368 // Make sure to have a proper terminating character if reaching the limit.
369 cmd[COMMAND_SIZE] = 0;
370 arg1[ARG_SIZE] = 0;
371 arg2[ARG_SIZE] = 0;
372
373 // Undo all set breakpoints while running in the debugger shell. This will
374 // make them invisible to all commands.
375 UndoBreakpoints();
376
377 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
378 if (last_pc != sim_->get_pc()) {
379 disasm::NameConverter converter;
380 disasm::Disassembler dasm(converter);
381 // Use a reasonably large buffer.
382 v8::internal::EmbeddedVector<char, 256> buffer;
383 dasm.InstructionDecode(buffer,
384 reinterpret_cast<byte*>(sim_->get_pc()));
385 PrintF(" 0x%016lx %s\n", sim_->get_pc(), buffer.start());
386 last_pc = sim_->get_pc();
387 }
388 char* line = ReadLine("sim> ");
389 if (line == NULL) {
390 break;
391 } else {
392 char* last_input = sim_->last_debugger_input();
393 if (strcmp(line, "\n") == 0 && last_input != NULL) {
394 line = last_input;
395 } else {
396 // Ownership is transferred to sim_;
397 sim_->set_last_debugger_input(line);
398 }
399 // Use sscanf to parse the individual parts of the command line. At the
400 // moment no command expects more than two parameters.
401 int argc = SScanF(line,
402 "%" XSTR(COMMAND_SIZE) "s "
403 "%" XSTR(ARG_SIZE) "s "
404 "%" XSTR(ARG_SIZE) "s",
405 cmd, arg1, arg2);
406 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
407 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
408 if (!(instr->IsTrap()) ||
409 instr->InstructionBits() == rtCallRedirInstr) {
410 sim_->InstructionDecode(
411 reinterpret_cast<Instruction*>(sim_->get_pc()));
412 } else {
413 // Allow si to jump over generated breakpoints.
414 PrintF("/!\\ Jumping over generated breakpoint.\n");
415 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
416 }
417 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
418 // Execute the one instruction we broke at with breakpoints disabled.
419 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
420 // Leave the debugger shell.
421 done = true;
422 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
423 if (argc == 2) {
424 int64_t value;
425 double dvalue;
426 if (strcmp(arg1, "all") == 0) {
427 PrintAllRegs();
428 } else if (strcmp(arg1, "allf") == 0) {
429 PrintAllRegsIncludingFPU();
430 } else {
431 int regnum = Registers::Number(arg1);
432 int fpuregnum = FPURegisters::Number(arg1);
433
434 if (regnum != kInvalidRegister) {
435 value = GetRegisterValue(regnum);
436 PrintF("%s: 0x%08lx %ld \n", arg1, value, value);
437 } else if (fpuregnum != kInvalidFPURegister) {
438 value = GetFPURegisterValue(fpuregnum);
439 dvalue = GetFPURegisterValueDouble(fpuregnum);
440 PrintF("%3s: 0x%016lx %16.4e\n",
441 FPURegisters::Name(fpuregnum), value, dvalue);
442 } else {
443 PrintF("%s unrecognized\n", arg1);
444 }
445 }
446 } else {
447 if (argc == 3) {
448 if (strcmp(arg2, "single") == 0) {
449 int64_t value;
450 float fvalue;
451 int fpuregnum = FPURegisters::Number(arg1);
452
453 if (fpuregnum != kInvalidFPURegister) {
454 value = GetFPURegisterValue(fpuregnum);
455 value &= 0xffffffffUL;
456 fvalue = GetFPURegisterValueFloat(fpuregnum);
457 PrintF("%s: 0x%08lx %11.4e\n", arg1, value, fvalue);
458 } else {
459 PrintF("%s unrecognized\n", arg1);
460 }
461 } else {
462 PrintF("print <fpu register> single\n");
463 }
464 } else {
465 PrintF("print <register> or print <fpu register> single\n");
466 }
467 }
468 } else if ((strcmp(cmd, "po") == 0)
469 || (strcmp(cmd, "printobject") == 0)) {
470 if (argc == 2) {
471 int64_t value;
472 OFStream os(stdout);
473 if (GetValue(arg1, &value)) {
474 Object* obj = reinterpret_cast<Object*>(value);
475 os << arg1 << ": \n";
476#ifdef DEBUG
477 obj->Print(os);
478 os << "\n";
479#else
480 os << Brief(obj) << "\n";
481#endif
482 } else {
483 os << arg1 << " unrecognized\n";
484 }
485 } else {
486 PrintF("printobject <value>\n");
487 }
488 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
489 int64_t* cur = NULL;
490 int64_t* end = NULL;
491 int next_arg = 1;
492
493 if (strcmp(cmd, "stack") == 0) {
494 cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
495 } else { // Command "mem".
496 int64_t value;
497 if (!GetValue(arg1, &value)) {
498 PrintF("%s unrecognized\n", arg1);
499 continue;
500 }
501 cur = reinterpret_cast<int64_t*>(value);
502 next_arg++;
503 }
504
505 int64_t words;
506 if (argc == next_arg) {
507 words = 10;
508 } else {
509 if (!GetValue(argv[next_arg], &words)) {
510 words = 10;
511 }
512 }
513 end = cur + words;
514
515 while (cur < end) {
516 PrintF(" 0x%012lx: 0x%016lx %14ld",
517 reinterpret_cast<intptr_t>(cur), *cur, *cur);
518 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
519 int64_t value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 Heap* current_heap = sim_->isolate_->heap();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100521 if (((value & 1) == 0) ||
522 current_heap->ContainsSlow(obj->address())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523 PrintF(" (");
524 if ((value & 1) == 0) {
525 PrintF("smi %d", static_cast<int>(value >> 32));
526 } else {
527 obj->ShortPrint();
528 }
529 PrintF(")");
530 }
531 PrintF("\n");
532 cur++;
533 }
534
535 } else if ((strcmp(cmd, "disasm") == 0) ||
536 (strcmp(cmd, "dpc") == 0) ||
537 (strcmp(cmd, "di") == 0)) {
538 disasm::NameConverter converter;
539 disasm::Disassembler dasm(converter);
540 // Use a reasonably large buffer.
541 v8::internal::EmbeddedVector<char, 256> buffer;
542
543 byte* cur = NULL;
544 byte* end = NULL;
545
546 if (argc == 1) {
547 cur = reinterpret_cast<byte*>(sim_->get_pc());
548 end = cur + (10 * Instruction::kInstrSize);
549 } else if (argc == 2) {
550 int regnum = Registers::Number(arg1);
551 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
552 // The argument is an address or a register name.
553 int64_t value;
554 if (GetValue(arg1, &value)) {
555 cur = reinterpret_cast<byte*>(value);
556 // Disassemble 10 instructions at <arg1>.
557 end = cur + (10 * Instruction::kInstrSize);
558 }
559 } else {
560 // The argument is the number of instructions.
561 int64_t value;
562 if (GetValue(arg1, &value)) {
563 cur = reinterpret_cast<byte*>(sim_->get_pc());
564 // Disassemble <arg1> instructions.
565 end = cur + (value * Instruction::kInstrSize);
566 }
567 }
568 } else {
569 int64_t value1;
570 int64_t value2;
571 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
572 cur = reinterpret_cast<byte*>(value1);
573 end = cur + (value2 * Instruction::kInstrSize);
574 }
575 }
576
577 while (cur < end) {
578 dasm.InstructionDecode(buffer, cur);
579 PrintF(" 0x%08lx %s\n",
580 reinterpret_cast<intptr_t>(cur), buffer.start());
581 cur += Instruction::kInstrSize;
582 }
583 } else if (strcmp(cmd, "gdb") == 0) {
584 PrintF("relinquishing control to gdb\n");
585 v8::base::OS::DebugBreak();
586 PrintF("regaining control from gdb\n");
587 } else if (strcmp(cmd, "break") == 0) {
588 if (argc == 2) {
589 int64_t value;
590 if (GetValue(arg1, &value)) {
591 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
592 PrintF("setting breakpoint failed\n");
593 }
594 } else {
595 PrintF("%s unrecognized\n", arg1);
596 }
597 } else {
598 PrintF("break <address>\n");
599 }
600 } else if (strcmp(cmd, "del") == 0) {
601 if (!DeleteBreakpoint(NULL)) {
602 PrintF("deleting breakpoint failed\n");
603 }
604 } else if (strcmp(cmd, "flags") == 0) {
605 PrintF("No flags on MIPS !\n");
606 } else if (strcmp(cmd, "stop") == 0) {
607 int64_t value;
608 intptr_t stop_pc = sim_->get_pc() -
609 2 * Instruction::kInstrSize;
610 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
611 Instruction* msg_address =
612 reinterpret_cast<Instruction*>(stop_pc +
613 Instruction::kInstrSize);
614 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
615 // Remove the current stop.
616 if (sim_->IsStopInstruction(stop_instr)) {
617 stop_instr->SetInstructionBits(kNopInstr);
618 msg_address->SetInstructionBits(kNopInstr);
619 } else {
620 PrintF("Not at debugger stop.\n");
621 }
622 } else if (argc == 3) {
623 // Print information about all/the specified breakpoint(s).
624 if (strcmp(arg1, "info") == 0) {
625 if (strcmp(arg2, "all") == 0) {
626 PrintF("Stop information:\n");
627 for (uint32_t i = kMaxWatchpointCode + 1;
628 i <= kMaxStopCode;
629 i++) {
630 sim_->PrintStopInfo(i);
631 }
632 } else if (GetValue(arg2, &value)) {
633 sim_->PrintStopInfo(value);
634 } else {
635 PrintF("Unrecognized argument.\n");
636 }
637 } else if (strcmp(arg1, "enable") == 0) {
638 // Enable all/the specified breakpoint(s).
639 if (strcmp(arg2, "all") == 0) {
640 for (uint32_t i = kMaxWatchpointCode + 1;
641 i <= kMaxStopCode;
642 i++) {
643 sim_->EnableStop(i);
644 }
645 } else if (GetValue(arg2, &value)) {
646 sim_->EnableStop(value);
647 } else {
648 PrintF("Unrecognized argument.\n");
649 }
650 } else if (strcmp(arg1, "disable") == 0) {
651 // Disable all/the specified breakpoint(s).
652 if (strcmp(arg2, "all") == 0) {
653 for (uint32_t i = kMaxWatchpointCode + 1;
654 i <= kMaxStopCode;
655 i++) {
656 sim_->DisableStop(i);
657 }
658 } else if (GetValue(arg2, &value)) {
659 sim_->DisableStop(value);
660 } else {
661 PrintF("Unrecognized argument.\n");
662 }
663 }
664 } else {
665 PrintF("Wrong usage. Use help command for more information.\n");
666 }
667 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
668 // Print registers and disassemble.
669 PrintAllRegs();
670 PrintF("\n");
671
672 disasm::NameConverter converter;
673 disasm::Disassembler dasm(converter);
674 // Use a reasonably large buffer.
675 v8::internal::EmbeddedVector<char, 256> buffer;
676
677 byte* cur = NULL;
678 byte* end = NULL;
679
680 if (argc == 1) {
681 cur = reinterpret_cast<byte*>(sim_->get_pc());
682 end = cur + (10 * Instruction::kInstrSize);
683 } else if (argc == 2) {
684 int64_t value;
685 if (GetValue(arg1, &value)) {
686 cur = reinterpret_cast<byte*>(value);
687 // no length parameter passed, assume 10 instructions
688 end = cur + (10 * Instruction::kInstrSize);
689 }
690 } else {
691 int64_t value1;
692 int64_t value2;
693 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
694 cur = reinterpret_cast<byte*>(value1);
695 end = cur + (value2 * Instruction::kInstrSize);
696 }
697 }
698
699 while (cur < end) {
700 dasm.InstructionDecode(buffer, cur);
701 PrintF(" 0x%08lx %s\n",
702 reinterpret_cast<intptr_t>(cur), buffer.start());
703 cur += Instruction::kInstrSize;
704 }
705 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
706 PrintF("cont\n");
707 PrintF(" continue execution (alias 'c')\n");
708 PrintF("stepi\n");
709 PrintF(" step one instruction (alias 'si')\n");
710 PrintF("print <register>\n");
711 PrintF(" print register content (alias 'p')\n");
712 PrintF(" use register name 'all' to print all registers\n");
713 PrintF("printobject <register>\n");
714 PrintF(" print an object from a register (alias 'po')\n");
715 PrintF("stack [<words>]\n");
716 PrintF(" dump stack content, default dump 10 words)\n");
717 PrintF("mem <address> [<words>]\n");
718 PrintF(" dump memory content, default dump 10 words)\n");
719 PrintF("flags\n");
720 PrintF(" print flags\n");
721 PrintF("disasm [<instructions>]\n");
722 PrintF("disasm [<address/register>]\n");
723 PrintF("disasm [[<address/register>] <instructions>]\n");
724 PrintF(" disassemble code, default is 10 instructions\n");
725 PrintF(" from pc (alias 'di')\n");
726 PrintF("gdb\n");
727 PrintF(" enter gdb\n");
728 PrintF("break <address>\n");
729 PrintF(" set a break point on the address\n");
730 PrintF("del\n");
731 PrintF(" delete the breakpoint\n");
732 PrintF("stop feature:\n");
733 PrintF(" Description:\n");
734 PrintF(" Stops are debug instructions inserted by\n");
735 PrintF(" the Assembler::stop() function.\n");
736 PrintF(" When hitting a stop, the Simulator will\n");
737 PrintF(" stop and and give control to the Debugger.\n");
738 PrintF(" All stop codes are watched:\n");
739 PrintF(" - They can be enabled / disabled: the Simulator\n");
740 PrintF(" will / won't stop when hitting them.\n");
741 PrintF(" - The Simulator keeps track of how many times they \n");
742 PrintF(" are met. (See the info command.) Going over a\n");
743 PrintF(" disabled stop still increases its counter. \n");
744 PrintF(" Commands:\n");
745 PrintF(" stop info all/<code> : print infos about number <code>\n");
746 PrintF(" or all stop(s).\n");
747 PrintF(" stop enable/disable all/<code> : enables / disables\n");
748 PrintF(" all or number <code> stop(s)\n");
749 PrintF(" stop unstop\n");
750 PrintF(" ignore the stop instruction at the current location\n");
751 PrintF(" from now on\n");
752 } else {
753 PrintF("Unknown command: %s\n", cmd);
754 }
755 }
756 }
757
758 // Add all the breakpoints back to stop execution and enter the debugger
759 // shell when hit.
760 RedoBreakpoints();
761
762#undef COMMAND_SIZE
763#undef ARG_SIZE
764
765#undef STR
766#undef XSTR
767}
768
769
770static bool ICacheMatch(void* one, void* two) {
771 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
772 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
773 return one == two;
774}
775
776
777static uint32_t ICacheHash(void* key) {
778 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
779}
780
781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782static bool AllOnOnePage(uintptr_t start, size_t size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 intptr_t start_page = (start & ~CachePage::kPageMask);
784 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
785 return start_page == end_page;
786}
787
788
789void Simulator::set_last_debugger_input(char* input) {
790 DeleteArray(last_debugger_input_);
791 last_debugger_input_ = input;
792}
793
794
795void Simulator::FlushICache(v8::internal::HashMap* i_cache,
796 void* start_addr,
797 size_t size) {
798 int64_t start = reinterpret_cast<int64_t>(start_addr);
799 int64_t intra_line = (start & CachePage::kLineMask);
800 start -= intra_line;
801 size += intra_line;
802 size = ((size - 1) | CachePage::kLineMask) + 1;
803 int offset = (start & CachePage::kPageMask);
804 while (!AllOnOnePage(start, size - 1)) {
805 int bytes_to_flush = CachePage::kPageSize - offset;
806 FlushOnePage(i_cache, start, bytes_to_flush);
807 start += bytes_to_flush;
808 size -= bytes_to_flush;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 offset = 0;
811 }
812 if (size != 0) {
813 FlushOnePage(i_cache, start, size);
814 }
815}
816
817
818CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 v8::internal::HashMap::Entry* entry =
820 i_cache->LookupOrInsert(page, ICacheHash(page));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000821 if (entry->value == NULL) {
822 CachePage* new_page = new CachePage();
823 entry->value = new_page;
824 }
825 return reinterpret_cast<CachePage*>(entry->value);
826}
827
828
829// Flush from start up to and not including start + size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
831 size_t size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 DCHECK(size <= CachePage::kPageSize);
833 DCHECK(AllOnOnePage(start, size - 1));
834 DCHECK((start & CachePage::kLineMask) == 0);
835 DCHECK((size & CachePage::kLineMask) == 0);
836 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
837 int offset = (start & CachePage::kPageMask);
838 CachePage* cache_page = GetCachePage(i_cache, page);
839 char* valid_bytemap = cache_page->ValidityByte(offset);
840 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
841}
842
843
844void Simulator::CheckICache(v8::internal::HashMap* i_cache,
845 Instruction* instr) {
846 int64_t address = reinterpret_cast<int64_t>(instr);
847 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
848 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
849 int offset = (address & CachePage::kPageMask);
850 CachePage* cache_page = GetCachePage(i_cache, page);
851 char* cache_valid_byte = cache_page->ValidityByte(offset);
852 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
853 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
854 if (cache_hit) {
855 // Check that the data in memory matches the contents of the I-cache.
856 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
857 cache_page->CachedData(offset),
858 Instruction::kInstrSize));
859 } else {
860 // Cache miss. Load memory into the cache.
861 memcpy(cached_line, line, CachePage::kLineLength);
862 *cache_valid_byte = CachePage::LINE_VALID;
863 }
864}
865
866
867void Simulator::Initialize(Isolate* isolate) {
868 if (isolate->simulator_initialized()) return;
869 isolate->set_simulator_initialized(true);
870 ::v8::internal::ExternalReference::set_redirector(isolate,
871 &RedirectExternalReference);
872}
873
874
875Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
876 i_cache_ = isolate_->simulator_i_cache();
877 if (i_cache_ == NULL) {
878 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
879 isolate_->set_simulator_i_cache(i_cache_);
880 }
881 Initialize(isolate);
882 // Set up simulator support first. Some of this information is needed to
883 // setup the architecture state.
884 stack_size_ = FLAG_sim_stack_size * KB;
885 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
886 pc_modified_ = false;
887 icount_ = 0;
888 break_count_ = 0;
889 break_pc_ = NULL;
890 break_instr_ = 0;
891
892 // Set up architecture state.
893 // All registers are initialized to zero to start with.
894 for (int i = 0; i < kNumSimuRegisters; i++) {
895 registers_[i] = 0;
896 }
897 for (int i = 0; i < kNumFPURegisters; i++) {
898 FPUregisters_[i] = 0;
899 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900
901 if (kArchVariant == kMips64r6) {
902 FCSR_ = kFCSRNaN2008FlagMask;
903 } else {
904 FCSR_ = 0;
905 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906
907 // The sp is initialized to point to the bottom (high address) of the
908 // allocated stack area. To be safe in potential stack underflows we leave
909 // some buffer below.
910 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64;
911 // The ra and pc are initialized to a known bad value that will cause an
912 // access violation if the simulator ever tries to execute it.
913 registers_[pc] = bad_ra;
914 registers_[ra] = bad_ra;
915 InitializeCoverage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916
917 last_debugger_input_ = NULL;
918}
919
920
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922
923
924// When the generated code calls an external reference we need to catch that in
925// the simulator. The external reference will be a function compiled for the
926// host architecture. We need to call that function instead of trying to
927// execute it with the simulator. We do that by redirecting the external
928// reference to a swi (software-interrupt) instruction that is handled by
929// the simulator. We write the original destination of the jump just at a known
930// offset from the swi instruction so the simulator knows what to call.
931class Redirection {
932 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000933 Redirection(Isolate* isolate, void* external_function,
934 ExternalReference::Type type)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935 : external_function_(external_function),
936 swi_instruction_(rtCallRedirInstr),
937 type_(type),
938 next_(NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000939 next_ = isolate->simulator_redirection();
940 Simulator::current(isolate)->
941 FlushICache(isolate->simulator_i_cache(),
942 reinterpret_cast<void*>(&swi_instruction_),
943 Instruction::kInstrSize);
944 isolate->set_simulator_redirection(this);
945 }
946
947 void* address_of_swi_instruction() {
948 return reinterpret_cast<void*>(&swi_instruction_);
949 }
950
951 void* external_function() { return external_function_; }
952 ExternalReference::Type type() { return type_; }
953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 static Redirection* Get(Isolate* isolate, void* external_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 ExternalReference::Type type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956 Redirection* current = isolate->simulator_redirection();
957 for (; current != NULL; current = current->next_) {
958 if (current->external_function_ == external_function) return current;
959 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 return new Redirection(isolate, external_function, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000961 }
962
963 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
964 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
965 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000966 addr_of_swi - offsetof(Redirection, swi_instruction_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000967 return reinterpret_cast<Redirection*>(addr_of_redirection);
968 }
969
970 static void* ReverseRedirection(int64_t reg) {
971 Redirection* redirection = FromSwiInstruction(
972 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
973 return redirection->external_function();
974 }
975
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000976 static void DeleteChain(Redirection* redirection) {
977 while (redirection != nullptr) {
978 Redirection* next = redirection->next_;
979 delete redirection;
980 redirection = next;
981 }
982 }
983
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000984 private:
985 void* external_function_;
986 uint32_t swi_instruction_;
987 ExternalReference::Type type_;
988 Redirection* next_;
989};
990
991
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000992// static
993void Simulator::TearDown(HashMap* i_cache, Redirection* first) {
994 Redirection::DeleteChain(first);
995 if (i_cache != nullptr) {
996 for (HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
997 entry = i_cache->Next(entry)) {
998 delete static_cast<CachePage*>(entry->value);
999 }
1000 delete i_cache;
1001 }
1002}
1003
1004
1005void* Simulator::RedirectExternalReference(Isolate* isolate,
1006 void* external_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009 return redirection->address_of_swi_instruction();
1010}
1011
1012
1013// Get the active Simulator for the current thread.
1014Simulator* Simulator::current(Isolate* isolate) {
1015 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
1016 isolate->FindOrAllocatePerThreadDataForThisThread();
1017 DCHECK(isolate_data != NULL);
1018 DCHECK(isolate_data != NULL);
1019
1020 Simulator* sim = isolate_data->simulator();
1021 if (sim == NULL) {
1022 // TODO(146): delete the simulator object when a thread/isolate goes away.
1023 sim = new Simulator(isolate);
1024 isolate_data->set_simulator(sim);
1025 }
1026 return sim;
1027}
1028
1029
1030// Sets the register in the architecture state. It will also deal with updating
1031// Simulator internal state for special registers such as PC.
1032void Simulator::set_register(int reg, int64_t value) {
1033 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1034 if (reg == pc) {
1035 pc_modified_ = true;
1036 }
1037
1038 // Zero register always holds 0.
1039 registers_[reg] = (reg == 0) ? 0 : value;
1040}
1041
1042
1043void Simulator::set_dw_register(int reg, const int* dbl) {
1044 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1045 registers_[reg] = dbl[1];
1046 registers_[reg] = registers_[reg] << 32;
1047 registers_[reg] += dbl[0];
1048}
1049
1050
1051void Simulator::set_fpu_register(int fpureg, int64_t value) {
1052 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1053 FPUregisters_[fpureg] = value;
1054}
1055
1056
1057void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1058 // Set ONLY lower 32-bits, leaving upper bits untouched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001060 int32_t* pword;
1061 if (kArchEndian == kLittle) {
1062 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1063 } else {
1064 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]) + 1;
1065 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001066 *pword = value;
1067}
1068
1069
1070void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1071 // Set ONLY upper 32-bits, leaving lower bits untouched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001073 int32_t* phiword;
1074 if (kArchEndian == kLittle) {
1075 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1076 } else {
1077 phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1078 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001079 *phiword = value;
1080}
1081
1082
1083void Simulator::set_fpu_register_float(int fpureg, float value) {
1084 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1085 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
1086}
1087
1088
1089void Simulator::set_fpu_register_double(int fpureg, double value) {
1090 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1091 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1092}
1093
1094
1095// Get the register from the architecture state. This function does handle
1096// the special case of accessing the PC register.
1097int64_t Simulator::get_register(int reg) const {
1098 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1099 if (reg == 0)
1100 return 0;
1101 else
1102 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1103}
1104
1105
1106double Simulator::get_double_from_register_pair(int reg) {
1107 // TODO(plind): bad ABI stuff, refactor or remove.
1108 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1109
1110 double dm_val = 0.0;
1111 // Read the bits from the unsigned integer register_[] array
1112 // into the double precision floating point value and return it.
1113 char buffer[sizeof(registers_[0])];
1114 memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
1115 memcpy(&dm_val, buffer, sizeof(registers_[0]));
1116 return(dm_val);
1117}
1118
1119
1120int64_t Simulator::get_fpu_register(int fpureg) const {
1121 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1122 return FPUregisters_[fpureg];
1123}
1124
1125
1126int32_t Simulator::get_fpu_register_word(int fpureg) const {
1127 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1128 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1129}
1130
1131
1132int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1133 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1134 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1135}
1136
1137
1138int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1139 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1140 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
1141}
1142
1143
1144float Simulator::get_fpu_register_float(int fpureg) const {
1145 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1146 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
1147}
1148
1149
1150double Simulator::get_fpu_register_double(int fpureg) const {
1151 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1152 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1153}
1154
1155
1156// Runtime FP routines take up to two double arguments and zero
1157// or one integer arguments. All are constructed here,
1158// from a0-a3 or f12 and f13 (n64), or f14 (O32).
1159void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1160 if (!IsMipsSoftFloatABI) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001161 const int fparg2 = 13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 *x = get_fpu_register_double(12);
1163 *y = get_fpu_register_double(fparg2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164 *z = static_cast<int32_t>(get_register(a2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001165 } else {
1166 // TODO(plind): bad ABI stuff, refactor or remove.
1167 // We use a char buffer to get around the strict-aliasing rules which
1168 // otherwise allow the compiler to optimize away the copy.
1169 char buffer[sizeof(*x)];
1170 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1171
1172 // Registers a0 and a1 -> x.
1173 reg_buffer[0] = get_register(a0);
1174 reg_buffer[1] = get_register(a1);
1175 memcpy(x, buffer, sizeof(buffer));
1176 // Registers a2 and a3 -> y.
1177 reg_buffer[0] = get_register(a2);
1178 reg_buffer[1] = get_register(a3);
1179 memcpy(y, buffer, sizeof(buffer));
1180 // Register 2 -> z.
1181 reg_buffer[0] = get_register(a2);
1182 memcpy(z, buffer, sizeof(*z));
1183 }
1184}
1185
1186
1187// The return value is either in v0/v1 or f0.
1188void Simulator::SetFpResult(const double& result) {
1189 if (!IsMipsSoftFloatABI) {
1190 set_fpu_register_double(0, result);
1191 } else {
1192 char buffer[2 * sizeof(registers_[0])];
1193 int64_t* reg_buffer = reinterpret_cast<int64_t*>(buffer);
1194 memcpy(buffer, &result, sizeof(buffer));
1195 // Copy result to v0 and v1.
1196 set_register(v0, reg_buffer[0]);
1197 set_register(v1, reg_buffer[1]);
1198 }
1199}
1200
1201
1202// Helper functions for setting and testing the FCSR register's bits.
1203void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1204 if (value) {
1205 FCSR_ |= (1 << cc);
1206 } else {
1207 FCSR_ &= ~(1 << cc);
1208 }
1209}
1210
1211
1212bool Simulator::test_fcsr_bit(uint32_t cc) {
1213 return FCSR_ & (1 << cc);
1214}
1215
1216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001217void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1218 FCSR_ |= mode & kFPURoundingModeMask;
1219}
1220
1221
1222unsigned int Simulator::get_fcsr_rounding_mode() {
1223 return FCSR_ & kFPURoundingModeMask;
1224}
1225
1226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227// Sets the rounding error codes in FCSR based on the result of the rounding.
1228// Returns true if the operation was invalid.
1229bool Simulator::set_fcsr_round_error(double original, double rounded) {
1230 bool ret = false;
1231 double max_int32 = std::numeric_limits<int32_t>::max();
1232 double min_int32 = std::numeric_limits<int32_t>::min();
1233
1234 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1235 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1236 ret = true;
1237 }
1238
1239 if (original != rounded) {
1240 set_fcsr_bit(kFCSRInexactFlagBit, true);
1241 }
1242
1243 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1244 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1245 ret = true;
1246 }
1247
1248 if (rounded > max_int32 || rounded < min_int32) {
1249 set_fcsr_bit(kFCSROverflowFlagBit, true);
1250 // The reference is not really clear but it seems this is required:
1251 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1252 ret = true;
1253 }
1254
1255 return ret;
1256}
1257
1258
1259// Sets the rounding error codes in FCSR based on the result of the rounding.
1260// Returns true if the operation was invalid.
1261bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1262 bool ret = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1264 // loading the most accurate representation into max_int64, which is 2^63.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265 double max_int64 = std::numeric_limits<int64_t>::max();
1266 double min_int64 = std::numeric_limits<int64_t>::min();
1267
1268 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1269 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1270 ret = true;
1271 }
1272
1273 if (original != rounded) {
1274 set_fcsr_bit(kFCSRInexactFlagBit, true);
1275 }
1276
1277 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1278 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1279 ret = true;
1280 }
1281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 if (rounded >= max_int64 || rounded < min_int64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 set_fcsr_bit(kFCSROverflowFlagBit, true);
1284 // The reference is not really clear but it seems this is required:
1285 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1286 ret = true;
1287 }
1288
1289 return ret;
1290}
1291
1292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001293// Sets the rounding error codes in FCSR based on the result of the rounding.
1294// Returns true if the operation was invalid.
1295bool Simulator::set_fcsr_round_error(float original, float rounded) {
1296 bool ret = false;
1297 double max_int32 = std::numeric_limits<int32_t>::max();
1298 double min_int32 = std::numeric_limits<int32_t>::min();
1299
1300 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1301 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1302 ret = true;
1303 }
1304
1305 if (original != rounded) {
1306 set_fcsr_bit(kFCSRInexactFlagBit, true);
1307 }
1308
1309 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1310 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1311 ret = true;
1312 }
1313
1314 if (rounded > max_int32 || rounded < min_int32) {
1315 set_fcsr_bit(kFCSROverflowFlagBit, true);
1316 // The reference is not really clear but it seems this is required:
1317 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1318 ret = true;
1319 }
1320
1321 return ret;
1322}
1323
1324void Simulator::set_fpu_register_word_invalid_result(float original,
1325 float rounded) {
1326 if (FCSR_ & kFCSRNaN2008FlagMask) {
1327 double max_int32 = std::numeric_limits<int32_t>::max();
1328 double min_int32 = std::numeric_limits<int32_t>::min();
1329 if (std::isnan(original)) {
1330 set_fpu_register_word(fd_reg(), 0);
1331 } else if (rounded > max_int32) {
1332 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1333 } else if (rounded < min_int32) {
1334 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1335 } else {
1336 UNREACHABLE();
1337 }
1338 } else {
1339 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1340 }
1341}
1342
1343
1344void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1345 if (FCSR_ & kFCSRNaN2008FlagMask) {
1346 double max_int32 = std::numeric_limits<int32_t>::max();
1347 double min_int32 = std::numeric_limits<int32_t>::min();
1348 if (std::isnan(original)) {
1349 set_fpu_register(fd_reg(), 0);
1350 } else if (rounded > max_int32) {
1351 set_fpu_register(fd_reg(), kFPUInvalidResult);
1352 } else if (rounded < min_int32) {
1353 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1354 } else {
1355 UNREACHABLE();
1356 }
1357 } else {
1358 set_fpu_register(fd_reg(), kFPUInvalidResult);
1359 }
1360}
1361
1362
1363void Simulator::set_fpu_register_invalid_result64(float original,
1364 float rounded) {
1365 if (FCSR_ & kFCSRNaN2008FlagMask) {
1366 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1367 // loading the most accurate representation into max_int64, which is 2^63.
1368 double max_int64 = std::numeric_limits<int64_t>::max();
1369 double min_int64 = std::numeric_limits<int64_t>::min();
1370 if (std::isnan(original)) {
1371 set_fpu_register(fd_reg(), 0);
1372 } else if (rounded >= max_int64) {
1373 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1374 } else if (rounded < min_int64) {
1375 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1376 } else {
1377 UNREACHABLE();
1378 }
1379 } else {
1380 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1381 }
1382}
1383
1384
1385void Simulator::set_fpu_register_word_invalid_result(double original,
1386 double rounded) {
1387 if (FCSR_ & kFCSRNaN2008FlagMask) {
1388 double max_int32 = std::numeric_limits<int32_t>::max();
1389 double min_int32 = std::numeric_limits<int32_t>::min();
1390 if (std::isnan(original)) {
1391 set_fpu_register_word(fd_reg(), 0);
1392 } else if (rounded > max_int32) {
1393 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1394 } else if (rounded < min_int32) {
1395 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1396 } else {
1397 UNREACHABLE();
1398 }
1399 } else {
1400 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1401 }
1402}
1403
1404
1405void Simulator::set_fpu_register_invalid_result(double original,
1406 double rounded) {
1407 if (FCSR_ & kFCSRNaN2008FlagMask) {
1408 double max_int32 = std::numeric_limits<int32_t>::max();
1409 double min_int32 = std::numeric_limits<int32_t>::min();
1410 if (std::isnan(original)) {
1411 set_fpu_register(fd_reg(), 0);
1412 } else if (rounded > max_int32) {
1413 set_fpu_register(fd_reg(), kFPUInvalidResult);
1414 } else if (rounded < min_int32) {
1415 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1416 } else {
1417 UNREACHABLE();
1418 }
1419 } else {
1420 set_fpu_register(fd_reg(), kFPUInvalidResult);
1421 }
1422}
1423
1424
1425void Simulator::set_fpu_register_invalid_result64(double original,
1426 double rounded) {
1427 if (FCSR_ & kFCSRNaN2008FlagMask) {
1428 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1429 // loading the most accurate representation into max_int64, which is 2^63.
1430 double max_int64 = std::numeric_limits<int64_t>::max();
1431 double min_int64 = std::numeric_limits<int64_t>::min();
1432 if (std::isnan(original)) {
1433 set_fpu_register(fd_reg(), 0);
1434 } else if (rounded >= max_int64) {
1435 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1436 } else if (rounded < min_int64) {
1437 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1438 } else {
1439 UNREACHABLE();
1440 }
1441 } else {
1442 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1443 }
1444}
1445
1446
1447// Sets the rounding error codes in FCSR based on the result of the rounding.
1448// Returns true if the operation was invalid.
1449bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1450 bool ret = false;
1451 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1452 // loading the most accurate representation into max_int64, which is 2^63.
1453 double max_int64 = std::numeric_limits<int64_t>::max();
1454 double min_int64 = std::numeric_limits<int64_t>::min();
1455
1456 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1457 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1458 ret = true;
1459 }
1460
1461 if (original != rounded) {
1462 set_fcsr_bit(kFCSRInexactFlagBit, true);
1463 }
1464
1465 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1466 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1467 ret = true;
1468 }
1469
1470 if (rounded >= max_int64 || rounded < min_int64) {
1471 set_fcsr_bit(kFCSROverflowFlagBit, true);
1472 // The reference is not really clear but it seems this is required:
1473 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1474 ret = true;
1475 }
1476
1477 return ret;
1478}
1479
1480
1481// For cvt instructions only
1482void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1483 int32_t& rounded_int, double fs) {
1484 // 0 RN (round to nearest): Round a result to the nearest
1485 // representable value; if the result is exactly halfway between
1486 // two representable values, round to zero. Behave like round_w_d.
1487
1488 // 1 RZ (round toward zero): Round a result to the closest
1489 // representable value whose absolute value is less than or
1490 // equal to the infinitely accurate result. Behave like trunc_w_d.
1491
1492 // 2 RP (round up, or toward +infinity): Round a result to the
1493 // next representable value up. Behave like ceil_w_d.
1494
1495 // 3 RN (round down, or toward −infinity): Round a result to
1496 // the next representable value down. Behave like floor_w_d.
1497 switch (FCSR_ & 3) {
1498 case kRoundToNearest:
1499 rounded = std::floor(fs + 0.5);
1500 rounded_int = static_cast<int32_t>(rounded);
1501 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1502 // If the number is halfway between two integers,
1503 // round to the even one.
1504 rounded_int--;
1505 }
1506 break;
1507 case kRoundToZero:
1508 rounded = trunc(fs);
1509 rounded_int = static_cast<int32_t>(rounded);
1510 break;
1511 case kRoundToPlusInf:
1512 rounded = std::ceil(fs);
1513 rounded_int = static_cast<int32_t>(rounded);
1514 break;
1515 case kRoundToMinusInf:
1516 rounded = std::floor(fs);
1517 rounded_int = static_cast<int32_t>(rounded);
1518 break;
1519 }
1520}
1521
1522
1523void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1524 int64_t& rounded_int, double fs) {
1525 // 0 RN (round to nearest): Round a result to the nearest
1526 // representable value; if the result is exactly halfway between
1527 // two representable values, round to zero. Behave like round_w_d.
1528
1529 // 1 RZ (round toward zero): Round a result to the closest
1530 // representable value whose absolute value is less than or.
1531 // equal to the infinitely accurate result. Behave like trunc_w_d.
1532
1533 // 2 RP (round up, or toward +infinity): Round a result to the
1534 // next representable value up. Behave like ceil_w_d.
1535
1536 // 3 RN (round down, or toward −infinity): Round a result to
1537 // the next representable value down. Behave like floor_w_d.
1538 switch (FCSR_ & 3) {
1539 case kRoundToNearest:
1540 rounded = std::floor(fs + 0.5);
1541 rounded_int = static_cast<int64_t>(rounded);
1542 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1543 // If the number is halfway between two integers,
1544 // round to the even one.
1545 rounded_int--;
1546 }
1547 break;
1548 case kRoundToZero:
1549 rounded = trunc(fs);
1550 rounded_int = static_cast<int64_t>(rounded);
1551 break;
1552 case kRoundToPlusInf:
1553 rounded = std::ceil(fs);
1554 rounded_int = static_cast<int64_t>(rounded);
1555 break;
1556 case kRoundToMinusInf:
1557 rounded = std::floor(fs);
1558 rounded_int = static_cast<int64_t>(rounded);
1559 break;
1560 }
1561}
1562
1563
1564// for cvt instructions only
1565void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1566 int32_t& rounded_int, float fs) {
1567 // 0 RN (round to nearest): Round a result to the nearest
1568 // representable value; if the result is exactly halfway between
1569 // two representable values, round to zero. Behave like round_w_d.
1570
1571 // 1 RZ (round toward zero): Round a result to the closest
1572 // representable value whose absolute value is less than or
1573 // equal to the infinitely accurate result. Behave like trunc_w_d.
1574
1575 // 2 RP (round up, or toward +infinity): Round a result to the
1576 // next representable value up. Behave like ceil_w_d.
1577
1578 // 3 RN (round down, or toward −infinity): Round a result to
1579 // the next representable value down. Behave like floor_w_d.
1580 switch (FCSR_ & 3) {
1581 case kRoundToNearest:
1582 rounded = std::floor(fs + 0.5);
1583 rounded_int = static_cast<int32_t>(rounded);
1584 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1585 // If the number is halfway between two integers,
1586 // round to the even one.
1587 rounded_int--;
1588 }
1589 break;
1590 case kRoundToZero:
1591 rounded = trunc(fs);
1592 rounded_int = static_cast<int32_t>(rounded);
1593 break;
1594 case kRoundToPlusInf:
1595 rounded = std::ceil(fs);
1596 rounded_int = static_cast<int32_t>(rounded);
1597 break;
1598 case kRoundToMinusInf:
1599 rounded = std::floor(fs);
1600 rounded_int = static_cast<int32_t>(rounded);
1601 break;
1602 }
1603}
1604
1605
1606void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1607 int64_t& rounded_int, float fs) {
1608 // 0 RN (round to nearest): Round a result to the nearest
1609 // representable value; if the result is exactly halfway between
1610 // two representable values, round to zero. Behave like round_w_d.
1611
1612 // 1 RZ (round toward zero): Round a result to the closest
1613 // representable value whose absolute value is less than or.
1614 // equal to the infinitely accurate result. Behave like trunc_w_d.
1615
1616 // 2 RP (round up, or toward +infinity): Round a result to the
1617 // next representable value up. Behave like ceil_w_d.
1618
1619 // 3 RN (round down, or toward −infinity): Round a result to
1620 // the next representable value down. Behave like floor_w_d.
1621 switch (FCSR_ & 3) {
1622 case kRoundToNearest:
1623 rounded = std::floor(fs + 0.5);
1624 rounded_int = static_cast<int64_t>(rounded);
1625 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1626 // If the number is halfway between two integers,
1627 // round to the even one.
1628 rounded_int--;
1629 }
1630 break;
1631 case kRoundToZero:
1632 rounded = trunc(fs);
1633 rounded_int = static_cast<int64_t>(rounded);
1634 break;
1635 case kRoundToPlusInf:
1636 rounded = std::ceil(fs);
1637 rounded_int = static_cast<int64_t>(rounded);
1638 break;
1639 case kRoundToMinusInf:
1640 rounded = std::floor(fs);
1641 rounded_int = static_cast<int64_t>(rounded);
1642 break;
1643 }
1644}
1645
1646
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001647// Raw access to the PC register.
1648void Simulator::set_pc(int64_t value) {
1649 pc_modified_ = true;
1650 registers_[pc] = value;
1651}
1652
1653
1654bool Simulator::has_bad_pc() const {
1655 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1656}
1657
1658
1659// Raw access to the PC register without the special adjustment when reading.
1660int64_t Simulator::get_pc() const {
1661 return registers_[pc];
1662}
1663
1664
1665// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1666// interrupt is caused. On others it does a funky rotation thing. For now we
1667// simply disallow unaligned reads, but at some point we may want to move to
1668// emulating the rotate behaviour. Note that simulator runs have the runtime
1669// system running directly on the host system and only generated code is
1670// executed in the simulator. Since the host is typically IA32 we will not
1671// get the correct MIPS-like behaviour on unaligned accesses.
1672
1673// TODO(plind): refactor this messy debug code when we do unaligned access.
1674void Simulator::DieOrDebug() {
1675 if (1) { // Flag for this was removed.
1676 MipsDebugger dbg(this);
1677 dbg.Debug();
1678 } else {
1679 base::OS::Abort();
1680 }
1681}
1682
1683
1684void Simulator::TraceRegWr(int64_t value) {
1685 if (::v8::internal::FLAG_trace_sim) {
1686 SNPrintF(trace_buf_, "%016lx", value);
1687 }
1688}
1689
1690
1691// TODO(plind): consider making icount_ printing a flag option.
1692void Simulator::TraceMemRd(int64_t addr, int64_t value) {
1693 if (::v8::internal::FLAG_trace_sim) {
1694 SNPrintF(trace_buf_, "%016lx <-- [%016lx] (%ld)",
1695 value, addr, icount_);
1696 }
1697}
1698
1699
1700void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
1701 if (::v8::internal::FLAG_trace_sim) {
1702 switch (t) {
1703 case BYTE:
1704 SNPrintF(trace_buf_, " %02x --> [%016lx]",
1705 static_cast<int8_t>(value), addr);
1706 break;
1707 case HALF:
1708 SNPrintF(trace_buf_, " %04x --> [%016lx]",
1709 static_cast<int16_t>(value), addr);
1710 break;
1711 case WORD:
1712 SNPrintF(trace_buf_, " %08x --> [%016lx]",
1713 static_cast<int32_t>(value), addr);
1714 break;
1715 case DWORD:
1716 SNPrintF(trace_buf_, "%016lx --> [%016lx] (%ld)",
1717 value, addr, icount_);
1718 break;
1719 }
1720 }
1721}
1722
1723
1724// TODO(plind): sign-extend and zero-extend not implmented properly
1725// on all the ReadXX functions, I don't think re-interpret cast does it.
1726int32_t Simulator::ReadW(int64_t addr, Instruction* instr) {
1727 if (addr >=0 && addr < 0x400) {
1728 // This has to be a NULL-dereference, drop into debugger.
1729 PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n",
1730 addr, reinterpret_cast<intptr_t>(instr));
1731 DieOrDebug();
1732 }
1733 if ((addr & 0x3) == 0) {
1734 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1735 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1736 return *ptr;
1737 }
1738 PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1739 addr,
1740 reinterpret_cast<intptr_t>(instr));
1741 DieOrDebug();
1742 return 0;
1743}
1744
1745
1746uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) {
1747 if (addr >=0 && addr < 0x400) {
1748 // This has to be a NULL-dereference, drop into debugger.
1749 PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n",
1750 addr, reinterpret_cast<intptr_t>(instr));
1751 DieOrDebug();
1752 }
1753 if ((addr & 0x3) == 0) {
1754 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1755 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1756 return *ptr;
1757 }
1758 PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1759 addr,
1760 reinterpret_cast<intptr_t>(instr));
1761 DieOrDebug();
1762 return 0;
1763}
1764
1765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001766void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001767 if (addr >= 0 && addr < 0x400) {
1768 // This has to be a NULL-dereference, drop into debugger.
1769 PrintF("Memory write to bad address: 0x%08lx, pc=0x%08lx\n",
1770 addr, reinterpret_cast<intptr_t>(instr));
1771 DieOrDebug();
1772 }
1773 if ((addr & 0x3) == 0) {
1774 TraceMemWr(addr, value, WORD);
1775 int* ptr = reinterpret_cast<int*>(addr);
1776 *ptr = value;
1777 return;
1778 }
1779 PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1780 addr,
1781 reinterpret_cast<intptr_t>(instr));
1782 DieOrDebug();
1783}
1784
1785
1786int64_t Simulator::Read2W(int64_t addr, Instruction* instr) {
1787 if (addr >=0 && addr < 0x400) {
1788 // This has to be a NULL-dereference, drop into debugger.
1789 PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n",
1790 addr, reinterpret_cast<intptr_t>(instr));
1791 DieOrDebug();
1792 }
1793 if ((addr & kPointerAlignmentMask) == 0) {
1794 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1795 TraceMemRd(addr, *ptr);
1796 return *ptr;
1797 }
1798 PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1799 addr,
1800 reinterpret_cast<intptr_t>(instr));
1801 DieOrDebug();
1802 return 0;
1803}
1804
1805
1806void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) {
1807 if (addr >= 0 && addr < 0x400) {
1808 // This has to be a NULL-dereference, drop into debugger.
1809 PrintF("Memory write to bad address: 0x%08lx, pc=0x%08lx\n",
1810 addr, reinterpret_cast<intptr_t>(instr));
1811 DieOrDebug();
1812 }
1813 if ((addr & kPointerAlignmentMask) == 0) {
1814 TraceMemWr(addr, value, DWORD);
1815 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1816 *ptr = value;
1817 return;
1818 }
1819 PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1820 addr,
1821 reinterpret_cast<intptr_t>(instr));
1822 DieOrDebug();
1823}
1824
1825
1826double Simulator::ReadD(int64_t addr, Instruction* instr) {
1827 if ((addr & kDoubleAlignmentMask) == 0) {
1828 double* ptr = reinterpret_cast<double*>(addr);
1829 return *ptr;
1830 }
1831 PrintF("Unaligned (double) read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1832 addr,
1833 reinterpret_cast<intptr_t>(instr));
1834 base::OS::Abort();
1835 return 0;
1836}
1837
1838
1839void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
1840 if ((addr & kDoubleAlignmentMask) == 0) {
1841 double* ptr = reinterpret_cast<double*>(addr);
1842 *ptr = value;
1843 return;
1844 }
1845 PrintF("Unaligned (double) write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1846 addr,
1847 reinterpret_cast<intptr_t>(instr));
1848 DieOrDebug();
1849}
1850
1851
1852uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
1853 if ((addr & 1) == 0) {
1854 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1855 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1856 return *ptr;
1857 }
1858 PrintF("Unaligned unsigned halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1859 addr,
1860 reinterpret_cast<intptr_t>(instr));
1861 DieOrDebug();
1862 return 0;
1863}
1864
1865
1866int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
1867 if ((addr & 1) == 0) {
1868 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1869 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1870 return *ptr;
1871 }
1872 PrintF("Unaligned signed halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1873 addr,
1874 reinterpret_cast<intptr_t>(instr));
1875 DieOrDebug();
1876 return 0;
1877}
1878
1879
1880void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
1881 if ((addr & 1) == 0) {
1882 TraceMemWr(addr, value, HALF);
1883 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1884 *ptr = value;
1885 return;
1886 }
1887 PrintF(
1888 "Unaligned unsigned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1889 addr,
1890 reinterpret_cast<intptr_t>(instr));
1891 DieOrDebug();
1892}
1893
1894
1895void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
1896 if ((addr & 1) == 0) {
1897 TraceMemWr(addr, value, HALF);
1898 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1899 *ptr = value;
1900 return;
1901 }
1902 PrintF("Unaligned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
1903 addr,
1904 reinterpret_cast<intptr_t>(instr));
1905 DieOrDebug();
1906}
1907
1908
1909uint32_t Simulator::ReadBU(int64_t addr) {
1910 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1911 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1912 return *ptr & 0xff;
1913}
1914
1915
1916int32_t Simulator::ReadB(int64_t addr) {
1917 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1918 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1919 return *ptr;
1920}
1921
1922
1923void Simulator::WriteB(int64_t addr, uint8_t value) {
1924 TraceMemWr(addr, value, BYTE);
1925 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1926 *ptr = value;
1927}
1928
1929
1930void Simulator::WriteB(int64_t addr, int8_t value) {
1931 TraceMemWr(addr, value, BYTE);
1932 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1933 *ptr = value;
1934}
1935
1936
1937// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001938uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1939 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1940 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1941 if (GetCurrentStackPosition() < c_limit) {
1942 return reinterpret_cast<uintptr_t>(get_sp());
1943 }
1944
1945 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1946 // to prevent overrunning the stack when pushing values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001947 return reinterpret_cast<uintptr_t>(stack_) + 1024;
1948}
1949
1950
1951// Unsupported instructions use Format to print an error and stop execution.
1952void Simulator::Format(Instruction* instr, const char* format) {
1953 PrintF("Simulator found unsupported instruction:\n 0x%08lx: %s\n",
1954 reinterpret_cast<intptr_t>(instr), format);
1955 UNIMPLEMENTED_MIPS();
1956}
1957
1958
1959// Calls into the V8 runtime are based on this very simple interface.
1960// Note: To be able to return two values from some calls the code in runtime.cc
1961// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1962// 64-bit value. With the code below we assume that all runtime calls return
1963// 64 bits of result. If they don't, the v1 result register contains a bogus
1964// value, which is fine because it is caller-saved.
1965
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001966typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
1967 int64_t arg1,
1968 int64_t arg2,
1969 int64_t arg3,
1970 int64_t arg4,
1971 int64_t arg5);
1972
Ben Murdoch097c5b22016-05-18 11:27:45 +01001973typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int64_t arg0, int64_t arg1,
1974 int64_t arg2, int64_t arg3,
1975 int64_t arg4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001976
1977// These prototypes handle the four types of FP calls.
1978typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1979typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1980typedef double (*SimulatorRuntimeFPCall)(double darg0);
1981typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1982
1983// This signature supports direct call in to API function native callback
1984// (refer to InvocationCallback in v8.h).
1985typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
1986typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1);
1987
1988// This signature supports direct call to accessor getter callback.
1989typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
1990typedef void (*SimulatorRuntimeProfilingGetterCall)(
1991 int64_t arg0, int64_t arg1, void* arg2);
1992
1993// Software interrupt instructions are used by the simulator to call into the
1994// C-based V8 runtime. They are also used for debugging with simulator.
1995void Simulator::SoftwareInterrupt(Instruction* instr) {
1996 // There are several instructions that could get us here,
1997 // the break_ instruction, or several variants of traps. All
1998 // Are "SPECIAL" class opcode, and are distinuished by function.
1999 int32_t func = instr->FunctionFieldRaw();
2000 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
2001 // We first check if we met a call_rt_redirected.
2002 if (instr->InstructionBits() == rtCallRedirInstr) {
2003 Redirection* redirection = Redirection::FromSwiInstruction(instr);
2004 int64_t arg0 = get_register(a0);
2005 int64_t arg1 = get_register(a1);
2006 int64_t arg2 = get_register(a2);
2007 int64_t arg3 = get_register(a3);
2008 int64_t arg4, arg5;
2009
Ben Murdoch097c5b22016-05-18 11:27:45 +01002010 arg4 = get_register(a4); // Abi n64 register a4.
2011 arg5 = get_register(a5); // Abi n64 register a5.
2012
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002013 bool fp_call =
2014 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2015 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2016 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2017 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2018
2019 if (!IsMipsSoftFloatABI) {
2020 // With the hard floating point calling convention, double
2021 // arguments are passed in FPU registers. Fetch the arguments
2022 // from there and call the builtin using soft floating point
2023 // convention.
2024 switch (redirection->type()) {
2025 case ExternalReference::BUILTIN_FP_FP_CALL:
2026 case ExternalReference::BUILTIN_COMPARE_CALL:
2027 arg0 = get_fpu_register(f12);
2028 arg1 = get_fpu_register(f13);
2029 arg2 = get_fpu_register(f14);
2030 arg3 = get_fpu_register(f15);
2031 break;
2032 case ExternalReference::BUILTIN_FP_CALL:
2033 arg0 = get_fpu_register(f12);
2034 arg1 = get_fpu_register(f13);
2035 break;
2036 case ExternalReference::BUILTIN_FP_INT_CALL:
2037 arg0 = get_fpu_register(f12);
2038 arg1 = get_fpu_register(f13);
2039 arg2 = get_register(a2);
2040 break;
2041 default:
2042 break;
2043 }
2044 }
2045
2046 // This is dodgy but it works because the C entry stubs are never moved.
2047 // See comment in codegen-arm.cc and bug 1242173.
2048 int64_t saved_ra = get_register(ra);
2049
2050 intptr_t external =
2051 reinterpret_cast<intptr_t>(redirection->external_function());
2052
2053 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2054 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2055 // simulator. Soft-float has additional abstraction of ExternalReference,
2056 // to support serialization.
2057 if (fp_call) {
2058 double dval0, dval1; // one or two double parameters
2059 int32_t ival; // zero or one integer parameters
2060 int64_t iresult = 0; // integer return value
2061 double dresult = 0; // double return value
2062 GetFpArgs(&dval0, &dval1, &ival);
2063 SimulatorRuntimeCall generic_target =
2064 reinterpret_cast<SimulatorRuntimeCall>(external);
2065 if (::v8::internal::FLAG_trace_sim) {
2066 switch (redirection->type()) {
2067 case ExternalReference::BUILTIN_FP_FP_CALL:
2068 case ExternalReference::BUILTIN_COMPARE_CALL:
2069 PrintF("Call to host function at %p with args %f, %f",
2070 FUNCTION_ADDR(generic_target), dval0, dval1);
2071 break;
2072 case ExternalReference::BUILTIN_FP_CALL:
2073 PrintF("Call to host function at %p with arg %f",
2074 FUNCTION_ADDR(generic_target), dval0);
2075 break;
2076 case ExternalReference::BUILTIN_FP_INT_CALL:
2077 PrintF("Call to host function at %p with args %f, %d",
2078 FUNCTION_ADDR(generic_target), dval0, ival);
2079 break;
2080 default:
2081 UNREACHABLE();
2082 break;
2083 }
2084 }
2085 switch (redirection->type()) {
2086 case ExternalReference::BUILTIN_COMPARE_CALL: {
2087 SimulatorRuntimeCompareCall target =
2088 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2089 iresult = target(dval0, dval1);
2090 set_register(v0, static_cast<int64_t>(iresult));
2091 // set_register(v1, static_cast<int64_t>(iresult >> 32));
2092 break;
2093 }
2094 case ExternalReference::BUILTIN_FP_FP_CALL: {
2095 SimulatorRuntimeFPFPCall target =
2096 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2097 dresult = target(dval0, dval1);
2098 SetFpResult(dresult);
2099 break;
2100 }
2101 case ExternalReference::BUILTIN_FP_CALL: {
2102 SimulatorRuntimeFPCall target =
2103 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2104 dresult = target(dval0);
2105 SetFpResult(dresult);
2106 break;
2107 }
2108 case ExternalReference::BUILTIN_FP_INT_CALL: {
2109 SimulatorRuntimeFPIntCall target =
2110 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2111 dresult = target(dval0, ival);
2112 SetFpResult(dresult);
2113 break;
2114 }
2115 default:
2116 UNREACHABLE();
2117 break;
2118 }
2119 if (::v8::internal::FLAG_trace_sim) {
2120 switch (redirection->type()) {
2121 case ExternalReference::BUILTIN_COMPARE_CALL:
2122 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2123 break;
2124 case ExternalReference::BUILTIN_FP_FP_CALL:
2125 case ExternalReference::BUILTIN_FP_CALL:
2126 case ExternalReference::BUILTIN_FP_INT_CALL:
2127 PrintF("Returned %f\n", dresult);
2128 break;
2129 default:
2130 UNREACHABLE();
2131 break;
2132 }
2133 }
2134 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2135 if (::v8::internal::FLAG_trace_sim) {
2136 PrintF("Call to host function at %p args %08lx\n",
2137 reinterpret_cast<void*>(external), arg0);
2138 }
2139 SimulatorRuntimeDirectApiCall target =
2140 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2141 target(arg0);
2142 } else if (
2143 redirection->type() == ExternalReference::PROFILING_API_CALL) {
2144 if (::v8::internal::FLAG_trace_sim) {
2145 PrintF("Call to host function at %p args %08lx %08lx\n",
2146 reinterpret_cast<void*>(external), arg0, arg1);
2147 }
2148 SimulatorRuntimeProfilingApiCall target =
2149 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2150 target(arg0, Redirection::ReverseRedirection(arg1));
2151 } else if (
2152 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2153 if (::v8::internal::FLAG_trace_sim) {
2154 PrintF("Call to host function at %p args %08lx %08lx\n",
2155 reinterpret_cast<void*>(external), arg0, arg1);
2156 }
2157 SimulatorRuntimeDirectGetterCall target =
2158 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2159 target(arg0, arg1);
2160 } else if (
2161 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2162 if (::v8::internal::FLAG_trace_sim) {
2163 PrintF("Call to host function at %p args %08lx %08lx %08lx\n",
2164 reinterpret_cast<void*>(external), arg0, arg1, arg2);
2165 }
2166 SimulatorRuntimeProfilingGetterCall target =
2167 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2168 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002169 } else if (redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE) {
2170 // builtin call returning ObjectTriple.
2171 SimulatorRuntimeTripleCall target =
2172 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
2173 if (::v8::internal::FLAG_trace_sim) {
2174 PrintF(
2175 "Call to host triple returning runtime function %p "
2176 "args %016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", %016" PRIx64
2177 ", %016" PRIx64 "\n",
2178 FUNCTION_ADDR(target), arg1, arg2, arg3, arg4, arg5);
2179 }
2180 // arg0 is a hidden argument pointing to the return location, so don't
2181 // pass it to the target function.
2182 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
2183 if (::v8::internal::FLAG_trace_sim) {
2184 PrintF("Returned { %p, %p, %p }\n", result.x, result.y, result.z);
2185 }
2186 // Return is passed back in address pointed to by hidden first argument.
2187 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
2188 *sim_result = result;
2189 set_register(v0, arg0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002190 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002191 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2192 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002193 SimulatorRuntimeCall target =
2194 reinterpret_cast<SimulatorRuntimeCall>(external);
2195 if (::v8::internal::FLAG_trace_sim) {
2196 PrintF(
2197 "Call to host function at %p "
2198 "args %08lx, %08lx, %08lx, %08lx, %08lx, %08lx\n",
2199 FUNCTION_ADDR(target),
2200 arg0,
2201 arg1,
2202 arg2,
2203 arg3,
2204 arg4,
2205 arg5);
2206 }
2207 // int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2208 // set_register(v0, static_cast<int32_t>(result));
2209 // set_register(v1, static_cast<int32_t>(result >> 32));
2210 ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2211 set_register(v0, (int64_t)(result.x));
2212 set_register(v1, (int64_t)(result.y));
2213 }
2214 if (::v8::internal::FLAG_trace_sim) {
2215 PrintF("Returned %08lx : %08lx\n", get_register(v1), get_register(v0));
2216 }
2217 set_register(ra, saved_ra);
2218 set_pc(get_register(ra));
2219
2220 } else if (func == BREAK && code <= kMaxStopCode) {
2221 if (IsWatchpoint(code)) {
2222 PrintWatchpoint(code);
2223 } else {
2224 IncreaseStopCounter(code);
2225 HandleStop(code, instr);
2226 }
2227 } else {
2228 // All remaining break_ codes, and all traps are handled here.
2229 MipsDebugger dbg(this);
2230 dbg.Debug();
2231 }
2232}
2233
2234
2235// Stop helper functions.
2236bool Simulator::IsWatchpoint(uint64_t code) {
2237 return (code <= kMaxWatchpointCode);
2238}
2239
2240
2241void Simulator::PrintWatchpoint(uint64_t code) {
2242 MipsDebugger dbg(this);
2243 ++break_count_;
2244 PrintF("\n---- break %ld marker: %3d (instr count: %8ld) ----------"
2245 "----------------------------------",
2246 code, break_count_, icount_);
2247 dbg.PrintAllRegs(); // Print registers and continue running.
2248}
2249
2250
2251void Simulator::HandleStop(uint64_t code, Instruction* instr) {
2252 // Stop if it is enabled, otherwise go on jumping over the stop
2253 // and the message address.
2254 if (IsEnabledStop(code)) {
2255 MipsDebugger dbg(this);
2256 dbg.Stop(instr);
2257 } else {
2258 set_pc(get_pc() + 2 * Instruction::kInstrSize);
2259 }
2260}
2261
2262
2263bool Simulator::IsStopInstruction(Instruction* instr) {
2264 int32_t func = instr->FunctionFieldRaw();
2265 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2266 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2267}
2268
2269
2270bool Simulator::IsEnabledStop(uint64_t code) {
2271 DCHECK(code <= kMaxStopCode);
2272 DCHECK(code > kMaxWatchpointCode);
2273 return !(watched_stops_[code].count & kStopDisabledBit);
2274}
2275
2276
2277void Simulator::EnableStop(uint64_t code) {
2278 if (!IsEnabledStop(code)) {
2279 watched_stops_[code].count &= ~kStopDisabledBit;
2280 }
2281}
2282
2283
2284void Simulator::DisableStop(uint64_t code) {
2285 if (IsEnabledStop(code)) {
2286 watched_stops_[code].count |= kStopDisabledBit;
2287 }
2288}
2289
2290
2291void Simulator::IncreaseStopCounter(uint64_t code) {
2292 DCHECK(code <= kMaxStopCode);
2293 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
2294 PrintF("Stop counter for code %ld has overflowed.\n"
2295 "Enabling this code and reseting the counter to 0.\n", code);
2296 watched_stops_[code].count = 0;
2297 EnableStop(code);
2298 } else {
2299 watched_stops_[code].count++;
2300 }
2301}
2302
2303
2304// Print a stop status.
2305void Simulator::PrintStopInfo(uint64_t code) {
2306 if (code <= kMaxWatchpointCode) {
2307 PrintF("That is a watchpoint, not a stop.\n");
2308 return;
2309 } else if (code > kMaxStopCode) {
2310 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2311 return;
2312 }
2313 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2314 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2315 // Don't print the state of unused breakpoints.
2316 if (count != 0) {
2317 if (watched_stops_[code].desc) {
2318 PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i, \t%s\n",
2319 code, code, state, count, watched_stops_[code].desc);
2320 } else {
2321 PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i\n",
2322 code, code, state, count);
2323 }
2324 }
2325}
2326
2327
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002328void Simulator::SignalException(Exception e) {
2329 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2330 static_cast<int>(e));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331}
2332
Ben Murdoch097c5b22016-05-18 11:27:45 +01002333// Min/Max template functions for Double and Single arguments.
2334
2335template <typename T>
2336static T FPAbs(T a);
2337
2338template <>
2339double FPAbs<double>(double a) {
2340 return fabs(a);
2341}
2342
2343template <>
2344float FPAbs<float>(float a) {
2345 return fabsf(a);
2346}
2347
2348template <typename T>
2349static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2350 if (std::isnan(a) && std::isnan(b)) {
2351 result = a;
2352 } else if (std::isnan(a)) {
2353 result = b;
2354 } else if (std::isnan(b)) {
2355 result = a;
2356 } else if (b == a) {
2357 // Handle -0.0 == 0.0 case.
2358 // std::signbit() returns int 0 or 1 so substracting MaxMinKind::kMax
2359 // negates the result.
2360 result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2361 } else {
2362 return false;
2363 }
2364 return true;
2365}
2366
2367template <typename T>
2368static T FPUMin(T a, T b) {
2369 T result;
2370 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2371 return result;
2372 } else {
2373 return b < a ? b : a;
2374 }
2375}
2376
2377template <typename T>
2378static T FPUMax(T a, T b) {
2379 T result;
2380 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2381 return result;
2382 } else {
2383 return b > a ? b : a;
2384 }
2385}
2386
2387template <typename T>
2388static T FPUMinA(T a, T b) {
2389 T result;
2390 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2391 if (FPAbs(a) < FPAbs(b)) {
2392 result = a;
2393 } else if (FPAbs(b) < FPAbs(a)) {
2394 result = b;
2395 } else {
2396 result = a < b ? a : b;
2397 }
2398 }
2399 return result;
2400}
2401
2402template <typename T>
2403static T FPUMaxA(T a, T b) {
2404 T result;
2405 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2406 if (FPAbs(a) > FPAbs(b)) {
2407 result = a;
2408 } else if (FPAbs(b) > FPAbs(a)) {
2409 result = b;
2410 } else {
2411 result = a > b ? a : b;
2412 }
2413 }
2414 return result;
2415}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002416
2417// Handle execution based on instruction types.
2418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002419void Simulator::DecodeTypeRegisterSRsType() {
2420 float fs, ft, fd;
2421 fs = get_fpu_register_float(fs_reg());
2422 ft = get_fpu_register_float(ft_reg());
2423 fd = get_fpu_register_float(fd_reg());
2424 int32_t ft_int = bit_cast<int32_t>(ft);
2425 int32_t fd_int = bit_cast<int32_t>(fd);
2426 uint32_t cc, fcsr_cc;
2427 cc = get_instr()->FCccValue();
2428 fcsr_cc = get_fcsr_condition_bit(cc);
2429 switch (get_instr()->FunctionFieldRaw()) {
2430 case RINT: {
2431 DCHECK(kArchVariant == kMips64r6);
2432 float result, temp_result;
2433 double temp;
2434 float upper = std::ceil(fs);
2435 float lower = std::floor(fs);
2436 switch (get_fcsr_rounding_mode()) {
2437 case kRoundToNearest:
2438 if (upper - fs < fs - lower) {
2439 result = upper;
2440 } else if (upper - fs > fs - lower) {
2441 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002442 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002443 temp_result = upper / 2;
2444 float reminder = modf(temp_result, &temp);
2445 if (reminder == 0) {
2446 result = upper;
2447 } else {
2448 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002449 }
2450 }
2451 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002452 case kRoundToZero:
2453 result = (fs > 0 ? lower : upper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002454 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002455 case kRoundToPlusInf:
2456 result = upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002457 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002458 case kRoundToMinusInf:
2459 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002460 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002461 }
2462 set_fpu_register_float(fd_reg(), result);
2463 if (result != fs) {
2464 set_fcsr_bit(kFCSRInexactFlagBit, true);
2465 }
2466 break;
2467 }
2468 case ADD_S:
2469 set_fpu_register_float(fd_reg(), fs + ft);
2470 break;
2471 case SUB_S:
2472 set_fpu_register_float(fd_reg(), fs - ft);
2473 break;
2474 case MUL_S:
2475 set_fpu_register_float(fd_reg(), fs * ft);
2476 break;
2477 case DIV_S:
2478 set_fpu_register_float(fd_reg(), fs / ft);
2479 break;
2480 case ABS_S:
2481 set_fpu_register_float(fd_reg(), fabs(fs));
2482 break;
2483 case MOV_S:
2484 set_fpu_register_float(fd_reg(), fs);
2485 break;
2486 case NEG_S:
2487 set_fpu_register_float(fd_reg(), -fs);
2488 break;
2489 case SQRT_S:
2490 lazily_initialize_fast_sqrt(isolate_);
2491 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
2492 break;
2493 case RSQRT_S: {
2494 lazily_initialize_fast_sqrt(isolate_);
2495 float result = 1.0 / fast_sqrt(fs, isolate_);
2496 set_fpu_register_float(fd_reg(), result);
2497 break;
2498 }
2499 case RECIP_S: {
2500 float result = 1.0 / fs;
2501 set_fpu_register_float(fd_reg(), result);
2502 break;
2503 }
2504 case C_F_D:
2505 set_fcsr_bit(fcsr_cc, false);
2506 break;
2507 case C_UN_D:
2508 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2509 break;
2510 case C_EQ_D:
2511 set_fcsr_bit(fcsr_cc, (fs == ft));
2512 break;
2513 case C_UEQ_D:
2514 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2515 break;
2516 case C_OLT_D:
2517 set_fcsr_bit(fcsr_cc, (fs < ft));
2518 break;
2519 case C_ULT_D:
2520 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2521 break;
2522 case C_OLE_D:
2523 set_fcsr_bit(fcsr_cc, (fs <= ft));
2524 break;
2525 case C_ULE_D:
2526 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2527 break;
2528 case CVT_D_S:
2529 set_fpu_register_double(fd_reg(), static_cast<double>(fs));
2530 break;
2531 case CLASS_S: { // Mips64r6 instruction
2532 // Convert float input to uint32_t for easier bit manipulation
2533 uint32_t classed = bit_cast<uint32_t>(fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002535 // Extracting sign, exponent and mantissa from the input float
2536 uint32_t sign = (classed >> 31) & 1;
2537 uint32_t exponent = (classed >> 23) & 0x000000ff;
2538 uint32_t mantissa = classed & 0x007fffff;
2539 uint32_t result;
2540 float fResult;
2541
2542 // Setting flags if input float is negative infinity,
2543 // positive infinity, negative zero or positive zero
2544 bool negInf = (classed == 0xFF800000);
2545 bool posInf = (classed == 0x7F800000);
2546 bool negZero = (classed == 0x80000000);
2547 bool posZero = (classed == 0x00000000);
2548
2549 bool signalingNan;
2550 bool quietNan;
2551 bool negSubnorm;
2552 bool posSubnorm;
2553 bool negNorm;
2554 bool posNorm;
2555
2556 // Setting flags if float is NaN
2557 signalingNan = false;
2558 quietNan = false;
2559 if (!negInf && !posInf && (exponent == 0xff)) {
2560 quietNan = ((mantissa & 0x00200000) == 0) &&
2561 ((mantissa & (0x00200000 - 1)) == 0);
2562 signalingNan = !quietNan;
2563 }
2564
2565 // Setting flags if float is subnormal number
2566 posSubnorm = false;
2567 negSubnorm = false;
2568 if ((exponent == 0) && (mantissa != 0)) {
2569 DCHECK(sign == 0 || sign == 1);
2570 posSubnorm = (sign == 0);
2571 negSubnorm = (sign == 1);
2572 }
2573
2574 // Setting flags if float is normal number
2575 posNorm = false;
2576 negNorm = false;
2577 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2578 !quietNan && !negZero && !posZero) {
2579 DCHECK(sign == 0 || sign == 1);
2580 posNorm = (sign == 0);
2581 negNorm = (sign == 1);
2582 }
2583
2584 // Calculating result according to description of CLASS.S instruction
2585 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2586 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2587 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2588
2589 DCHECK(result != 0);
2590
2591 fResult = bit_cast<float>(result);
2592 set_fpu_register_float(fd_reg(), fResult);
2593
2594 break;
2595 }
2596 case CVT_L_S: {
2597 float rounded;
2598 int64_t result;
2599 round64_according_to_fcsr(fs, rounded, result, fs);
2600 set_fpu_register(fd_reg(), result);
2601 if (set_fcsr_round64_error(fs, rounded)) {
2602 set_fpu_register_invalid_result64(fs, rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002603 }
2604 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002605 }
2606 case CVT_W_S: {
2607 float rounded;
2608 int32_t result;
2609 round_according_to_fcsr(fs, rounded, result, fs);
2610 set_fpu_register_word(fd_reg(), result);
2611 if (set_fcsr_round_error(fs, rounded)) {
2612 set_fpu_register_word_invalid_result(fs, rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002613 }
2614 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002615 }
2616 case TRUNC_W_S: { // Truncate single to word (round towards 0).
2617 float rounded = trunc(fs);
2618 int32_t result = static_cast<int32_t>(rounded);
2619 set_fpu_register_word(fd_reg(), result);
2620 if (set_fcsr_round_error(fs, rounded)) {
2621 set_fpu_register_word_invalid_result(fs, rounded);
2622 }
2623 } break;
2624 case TRUNC_L_S: { // Mips64r2 instruction.
2625 float rounded = trunc(fs);
2626 int64_t result = static_cast<int64_t>(rounded);
2627 set_fpu_register(fd_reg(), result);
2628 if (set_fcsr_round64_error(fs, rounded)) {
2629 set_fpu_register_invalid_result64(fs, rounded);
2630 }
2631 break;
2632 }
2633 case ROUND_W_S: {
2634 float rounded = std::floor(fs + 0.5);
2635 int32_t result = static_cast<int32_t>(rounded);
2636 if ((result & 1) != 0 && result - fs == 0.5) {
2637 // If the number is halfway between two integers,
2638 // round to the even one.
2639 result--;
2640 }
2641 set_fpu_register_word(fd_reg(), result);
2642 if (set_fcsr_round_error(fs, rounded)) {
2643 set_fpu_register_word_invalid_result(fs, rounded);
2644 }
2645 break;
2646 }
2647 case ROUND_L_S: { // Mips64r2 instruction.
2648 float rounded = std::floor(fs + 0.5);
2649 int64_t result = static_cast<int64_t>(rounded);
2650 if ((result & 1) != 0 && result - fs == 0.5) {
2651 // If the number is halfway between two integers,
2652 // round to the even one.
2653 result--;
2654 }
2655 int64_t i64 = static_cast<int64_t>(result);
2656 set_fpu_register(fd_reg(), i64);
2657 if (set_fcsr_round64_error(fs, rounded)) {
2658 set_fpu_register_invalid_result64(fs, rounded);
2659 }
2660 break;
2661 }
2662 case FLOOR_L_S: { // Mips64r2 instruction.
2663 float rounded = floor(fs);
2664 int64_t result = static_cast<int64_t>(rounded);
2665 set_fpu_register(fd_reg(), result);
2666 if (set_fcsr_round64_error(fs, rounded)) {
2667 set_fpu_register_invalid_result64(fs, rounded);
2668 }
2669 break;
2670 }
2671 case FLOOR_W_S: // Round double to word towards negative infinity.
2672 {
2673 float rounded = std::floor(fs);
2674 int32_t result = static_cast<int32_t>(rounded);
2675 set_fpu_register_word(fd_reg(), result);
2676 if (set_fcsr_round_error(fs, rounded)) {
2677 set_fpu_register_word_invalid_result(fs, rounded);
2678 }
2679 } break;
2680 case CEIL_W_S: // Round double to word towards positive infinity.
2681 {
2682 float rounded = std::ceil(fs);
2683 int32_t result = static_cast<int32_t>(rounded);
2684 set_fpu_register_word(fd_reg(), result);
2685 if (set_fcsr_round_error(fs, rounded)) {
2686 set_fpu_register_invalid_result(fs, rounded);
2687 }
2688 } break;
2689 case CEIL_L_S: { // Mips64r2 instruction.
2690 float rounded = ceil(fs);
2691 int64_t result = static_cast<int64_t>(rounded);
2692 set_fpu_register(fd_reg(), result);
2693 if (set_fcsr_round64_error(fs, rounded)) {
2694 set_fpu_register_invalid_result64(fs, rounded);
2695 }
2696 break;
2697 }
2698 case MINA:
2699 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002700 set_fpu_register_float(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002701 break;
2702 case MAXA:
2703 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002704 set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002705 break;
2706 case MIN:
2707 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002708 set_fpu_register_float(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002709 break;
2710 case MAX:
2711 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002712 set_fpu_register_float(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002713 break;
2714 case SEL:
2715 DCHECK(kArchVariant == kMips64r6);
2716 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2717 break;
2718 case SELEQZ_C:
2719 DCHECK(kArchVariant == kMips64r6);
2720 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
2721 ? get_fpu_register_float(fs_reg())
2722 : 0.0);
2723 break;
2724 case SELNEZ_C:
2725 DCHECK(kArchVariant == kMips64r6);
2726 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
2727 ? get_fpu_register_float(fs_reg())
2728 : 0.0);
2729 break;
2730 case MOVZ_C: {
2731 DCHECK(kArchVariant == kMips64r2);
2732 if (rt() == 0) {
2733 set_fpu_register_float(fd_reg(), fs);
2734 }
2735 break;
2736 }
2737 case MOVN_C: {
2738 DCHECK(kArchVariant == kMips64r2);
2739 if (rt() != 0) {
2740 set_fpu_register_float(fd_reg(), fs);
2741 }
2742 break;
2743 }
2744 case MOVF: {
2745 // Same function field for MOVT.D and MOVF.D
2746 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2747 ft_cc = get_fcsr_condition_bit(ft_cc);
2748
2749 if (get_instr()->Bit(16)) { // Read Tf bit.
2750 // MOVT.D
2751 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
2752 } else {
2753 // MOVF.D
2754 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
2755 }
2756 break;
2757 }
2758 default:
2759 // TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
2760 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
2761 UNREACHABLE();
2762 }
2763}
2764
2765
2766void Simulator::DecodeTypeRegisterDRsType() {
2767 double ft, fs, fd;
2768 uint32_t cc, fcsr_cc;
2769 fs = get_fpu_register_double(fs_reg());
2770 ft = (get_instr()->FunctionFieldRaw() != MOVF)
2771 ? get_fpu_register_double(ft_reg())
2772 : 0.0;
2773 fd = get_fpu_register_double(fd_reg());
2774 cc = get_instr()->FCccValue();
2775 fcsr_cc = get_fcsr_condition_bit(cc);
2776 int64_t ft_int = bit_cast<int64_t>(ft);
2777 int64_t fd_int = bit_cast<int64_t>(fd);
2778 switch (get_instr()->FunctionFieldRaw()) {
2779 case RINT: {
2780 DCHECK(kArchVariant == kMips64r6);
2781 double result, temp, temp_result;
2782 double upper = std::ceil(fs);
2783 double lower = std::floor(fs);
2784 switch (get_fcsr_rounding_mode()) {
2785 case kRoundToNearest:
2786 if (upper - fs < fs - lower) {
2787 result = upper;
2788 } else if (upper - fs > fs - lower) {
2789 result = lower;
2790 } else {
2791 temp_result = upper / 2;
2792 double reminder = modf(temp_result, &temp);
2793 if (reminder == 0) {
2794 result = upper;
2795 } else {
2796 result = lower;
2797 }
2798 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002799 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002800 case kRoundToZero:
2801 result = (fs > 0 ? lower : upper);
2802 break;
2803 case kRoundToPlusInf:
2804 result = upper;
2805 break;
2806 case kRoundToMinusInf:
2807 result = lower;
2808 break;
2809 }
2810 set_fpu_register_double(fd_reg(), result);
2811 if (result != fs) {
2812 set_fcsr_bit(kFCSRInexactFlagBit, true);
2813 }
2814 break;
2815 }
2816 case SEL:
2817 DCHECK(kArchVariant == kMips64r6);
2818 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2819 break;
2820 case SELEQZ_C:
2821 DCHECK(kArchVariant == kMips64r6);
2822 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2823 break;
2824 case SELNEZ_C:
2825 DCHECK(kArchVariant == kMips64r6);
2826 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2827 break;
2828 case MOVZ_C: {
2829 DCHECK(kArchVariant == kMips64r2);
2830 if (rt() == 0) {
2831 set_fpu_register_double(fd_reg(), fs);
2832 }
2833 break;
2834 }
2835 case MOVN_C: {
2836 DCHECK(kArchVariant == kMips64r2);
2837 if (rt() != 0) {
2838 set_fpu_register_double(fd_reg(), fs);
2839 }
2840 break;
2841 }
2842 case MOVF: {
2843 // Same function field for MOVT.D and MOVF.D
2844 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2845 ft_cc = get_fcsr_condition_bit(ft_cc);
2846 if (get_instr()->Bit(16)) { // Read Tf bit.
2847 // MOVT.D
2848 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2849 } else {
2850 // MOVF.D
2851 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2852 }
2853 break;
2854 }
2855 case MINA:
2856 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002857 set_fpu_register_double(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002858 break;
2859 case MAXA:
2860 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002861 set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002862 break;
2863 case MIN:
2864 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002865 set_fpu_register_double(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002866 break;
2867 case MAX:
2868 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002869 set_fpu_register_double(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002870 break;
2871 case ADD_D:
2872 set_fpu_register_double(fd_reg(), fs + ft);
2873 break;
2874 case SUB_D:
2875 set_fpu_register_double(fd_reg(), fs - ft);
2876 break;
2877 case MUL_D:
2878 set_fpu_register_double(fd_reg(), fs * ft);
2879 break;
2880 case DIV_D:
2881 set_fpu_register_double(fd_reg(), fs / ft);
2882 break;
2883 case ABS_D:
2884 set_fpu_register_double(fd_reg(), fabs(fs));
2885 break;
2886 case MOV_D:
2887 set_fpu_register_double(fd_reg(), fs);
2888 break;
2889 case NEG_D:
2890 set_fpu_register_double(fd_reg(), -fs);
2891 break;
2892 case SQRT_D:
2893 lazily_initialize_fast_sqrt(isolate_);
2894 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
2895 break;
2896 case RSQRT_D: {
2897 lazily_initialize_fast_sqrt(isolate_);
2898 double result = 1.0 / fast_sqrt(fs, isolate_);
2899 set_fpu_register_double(fd_reg(), result);
2900 break;
2901 }
2902 case RECIP_D: {
2903 double result = 1.0 / fs;
2904 set_fpu_register_double(fd_reg(), result);
2905 break;
2906 }
2907 case C_UN_D:
2908 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2909 break;
2910 case C_EQ_D:
2911 set_fcsr_bit(fcsr_cc, (fs == ft));
2912 break;
2913 case C_UEQ_D:
2914 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2915 break;
2916 case C_OLT_D:
2917 set_fcsr_bit(fcsr_cc, (fs < ft));
2918 break;
2919 case C_ULT_D:
2920 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2921 break;
2922 case C_OLE_D:
2923 set_fcsr_bit(fcsr_cc, (fs <= ft));
2924 break;
2925 case C_ULE_D:
2926 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2927 break;
2928 case CVT_W_D: { // Convert double to word.
2929 double rounded;
2930 int32_t result;
2931 round_according_to_fcsr(fs, rounded, result, fs);
2932 set_fpu_register_word(fd_reg(), result);
2933 if (set_fcsr_round_error(fs, rounded)) {
2934 set_fpu_register_word_invalid_result(fs, rounded);
2935 }
2936 break;
2937 }
2938 case ROUND_W_D: // Round double to word (round half to even).
2939 {
2940 double rounded = std::floor(fs + 0.5);
2941 int32_t result = static_cast<int32_t>(rounded);
2942 if ((result & 1) != 0 && result - fs == 0.5) {
2943 // If the number is halfway between two integers,
2944 // round to the even one.
2945 result--;
2946 }
2947 set_fpu_register_word(fd_reg(), result);
2948 if (set_fcsr_round_error(fs, rounded)) {
2949 set_fpu_register_invalid_result(fs, rounded);
2950 }
2951 } break;
2952 case TRUNC_W_D: // Truncate double to word (round towards 0).
2953 {
2954 double rounded = trunc(fs);
2955 int32_t result = static_cast<int32_t>(rounded);
2956 set_fpu_register_word(fd_reg(), result);
2957 if (set_fcsr_round_error(fs, rounded)) {
2958 set_fpu_register_invalid_result(fs, rounded);
2959 }
2960 } break;
2961 case FLOOR_W_D: // Round double to word towards negative infinity.
2962 {
2963 double rounded = std::floor(fs);
2964 int32_t result = static_cast<int32_t>(rounded);
2965 set_fpu_register_word(fd_reg(), result);
2966 if (set_fcsr_round_error(fs, rounded)) {
2967 set_fpu_register_invalid_result(fs, rounded);
2968 }
2969 } break;
2970 case CEIL_W_D: // Round double to word towards positive infinity.
2971 {
2972 double rounded = std::ceil(fs);
2973 int32_t result = static_cast<int32_t>(rounded);
2974 set_fpu_register_word(fd_reg(), result);
2975 if (set_fcsr_round_error(fs, rounded)) {
2976 set_fpu_register_invalid_result(fs, rounded);
2977 }
2978 } break;
2979 case CVT_S_D: // Convert double to float (single).
2980 set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2981 break;
2982 case CVT_L_D: { // Mips64r2: Truncate double to 64-bit long-word.
2983 double rounded;
2984 int64_t result;
2985 round64_according_to_fcsr(fs, rounded, result, fs);
2986 set_fpu_register(fd_reg(), result);
2987 if (set_fcsr_round64_error(fs, rounded)) {
2988 set_fpu_register_invalid_result64(fs, rounded);
2989 }
2990 break;
2991 }
2992 case ROUND_L_D: { // Mips64r2 instruction.
2993 double rounded = std::floor(fs + 0.5);
2994 int64_t result = static_cast<int64_t>(rounded);
2995 if ((result & 1) != 0 && result - fs == 0.5) {
2996 // If the number is halfway between two integers,
2997 // round to the even one.
2998 result--;
2999 }
3000 int64_t i64 = static_cast<int64_t>(result);
3001 set_fpu_register(fd_reg(), i64);
3002 if (set_fcsr_round64_error(fs, rounded)) {
3003 set_fpu_register_invalid_result64(fs, rounded);
3004 }
3005 break;
3006 }
3007 case TRUNC_L_D: { // Mips64r2 instruction.
3008 double rounded = trunc(fs);
3009 int64_t result = static_cast<int64_t>(rounded);
3010 set_fpu_register(fd_reg(), result);
3011 if (set_fcsr_round64_error(fs, rounded)) {
3012 set_fpu_register_invalid_result64(fs, rounded);
3013 }
3014 break;
3015 }
3016 case FLOOR_L_D: { // Mips64r2 instruction.
3017 double rounded = floor(fs);
3018 int64_t result = static_cast<int64_t>(rounded);
3019 set_fpu_register(fd_reg(), result);
3020 if (set_fcsr_round64_error(fs, rounded)) {
3021 set_fpu_register_invalid_result64(fs, rounded);
3022 }
3023 break;
3024 }
3025 case CEIL_L_D: { // Mips64r2 instruction.
3026 double rounded = ceil(fs);
3027 int64_t result = static_cast<int64_t>(rounded);
3028 set_fpu_register(fd_reg(), result);
3029 if (set_fcsr_round64_error(fs, rounded)) {
3030 set_fpu_register_invalid_result64(fs, rounded);
3031 }
3032 break;
3033 }
3034 case CLASS_D: { // Mips64r6 instruction
3035 // Convert double input to uint64_t for easier bit manipulation
3036 uint64_t classed = bit_cast<uint64_t>(fs);
3037
3038 // Extracting sign, exponent and mantissa from the input double
3039 uint32_t sign = (classed >> 63) & 1;
3040 uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
3041 uint64_t mantissa = classed & 0x000fffffffffffff;
3042 uint64_t result;
3043 double dResult;
3044
3045 // Setting flags if input double is negative infinity,
3046 // positive infinity, negative zero or positive zero
3047 bool negInf = (classed == 0xFFF0000000000000);
3048 bool posInf = (classed == 0x7FF0000000000000);
3049 bool negZero = (classed == 0x8000000000000000);
3050 bool posZero = (classed == 0x0000000000000000);
3051
3052 bool signalingNan;
3053 bool quietNan;
3054 bool negSubnorm;
3055 bool posSubnorm;
3056 bool negNorm;
3057 bool posNorm;
3058
3059 // Setting flags if double is NaN
3060 signalingNan = false;
3061 quietNan = false;
3062 if (!negInf && !posInf && exponent == 0x7ff) {
3063 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
3064 ((mantissa & (0x0008000000000000 - 1)) == 0);
3065 signalingNan = !quietNan;
3066 }
3067
3068 // Setting flags if double is subnormal number
3069 posSubnorm = false;
3070 negSubnorm = false;
3071 if ((exponent == 0) && (mantissa != 0)) {
3072 DCHECK(sign == 0 || sign == 1);
3073 posSubnorm = (sign == 0);
3074 negSubnorm = (sign == 1);
3075 }
3076
3077 // Setting flags if double is normal number
3078 posNorm = false;
3079 negNorm = false;
3080 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3081 !quietNan && !negZero && !posZero) {
3082 DCHECK(sign == 0 || sign == 1);
3083 posNorm = (sign == 0);
3084 negNorm = (sign == 1);
3085 }
3086
3087 // Calculating result according to description of CLASS.D instruction
3088 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3089 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3090 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3091
3092 DCHECK(result != 0);
3093
3094 dResult = bit_cast<double>(result);
3095 set_fpu_register_double(fd_reg(), dResult);
3096
3097 break;
3098 }
3099 case C_F_D: {
3100 set_fcsr_bit(fcsr_cc, false);
3101 break;
3102 }
3103 default:
3104 UNREACHABLE();
3105 }
3106}
3107
3108
3109void Simulator::DecodeTypeRegisterWRsType() {
3110 float fs = get_fpu_register_float(fs_reg());
3111 float ft = get_fpu_register_float(ft_reg());
3112 int64_t alu_out = 0x12345678;
3113 switch (get_instr()->FunctionFieldRaw()) {
3114 case CVT_S_W: // Convert word to float (single).
3115 alu_out = get_fpu_register_signed_word(fs_reg());
3116 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
3117 break;
3118 case CVT_D_W: // Convert word to double.
3119 alu_out = get_fpu_register_signed_word(fs_reg());
3120 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
3121 break;
3122 case CMP_AF:
3123 set_fpu_register_word(fd_reg(), 0);
3124 break;
3125 case CMP_UN:
3126 if (std::isnan(fs) || std::isnan(ft)) {
3127 set_fpu_register_word(fd_reg(), -1);
3128 } else {
3129 set_fpu_register_word(fd_reg(), 0);
3130 }
3131 break;
3132 case CMP_EQ:
3133 if (fs == ft) {
3134 set_fpu_register_word(fd_reg(), -1);
3135 } else {
3136 set_fpu_register_word(fd_reg(), 0);
3137 }
3138 break;
3139 case CMP_UEQ:
3140 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3141 set_fpu_register_word(fd_reg(), -1);
3142 } else {
3143 set_fpu_register_word(fd_reg(), 0);
3144 }
3145 break;
3146 case CMP_LT:
3147 if (fs < ft) {
3148 set_fpu_register_word(fd_reg(), -1);
3149 } else {
3150 set_fpu_register_word(fd_reg(), 0);
3151 }
3152 break;
3153 case CMP_ULT:
3154 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3155 set_fpu_register_word(fd_reg(), -1);
3156 } else {
3157 set_fpu_register_word(fd_reg(), 0);
3158 }
3159 break;
3160 case CMP_LE:
3161 if (fs <= ft) {
3162 set_fpu_register_word(fd_reg(), -1);
3163 } else {
3164 set_fpu_register_word(fd_reg(), 0);
3165 }
3166 break;
3167 case CMP_ULE:
3168 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3169 set_fpu_register_word(fd_reg(), -1);
3170 } else {
3171 set_fpu_register_word(fd_reg(), 0);
3172 }
3173 break;
3174 case CMP_OR:
3175 if (!std::isnan(fs) && !std::isnan(ft)) {
3176 set_fpu_register_word(fd_reg(), -1);
3177 } else {
3178 set_fpu_register_word(fd_reg(), 0);
3179 }
3180 break;
3181 case CMP_UNE:
3182 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3183 set_fpu_register_word(fd_reg(), -1);
3184 } else {
3185 set_fpu_register_word(fd_reg(), 0);
3186 }
3187 break;
3188 case CMP_NE:
3189 if (fs != ft) {
3190 set_fpu_register_word(fd_reg(), -1);
3191 } else {
3192 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003193 }
3194 break;
3195 default:
3196 UNREACHABLE();
3197 }
3198}
3199
3200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003201void Simulator::DecodeTypeRegisterLRsType() {
3202 double fs = get_fpu_register_double(fs_reg());
3203 double ft = get_fpu_register_double(ft_reg());
3204 int64_t i64;
3205 switch (get_instr()->FunctionFieldRaw()) {
3206 case CVT_D_L: // Mips32r2 instruction.
3207 i64 = get_fpu_register(fs_reg());
3208 set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3209 break;
3210 case CVT_S_L:
3211 i64 = get_fpu_register(fs_reg());
3212 set_fpu_register_float(fd_reg(), static_cast<float>(i64));
3213 break;
3214 case CMP_AF:
3215 set_fpu_register(fd_reg(), 0);
3216 break;
3217 case CMP_UN:
3218 if (std::isnan(fs) || std::isnan(ft)) {
3219 set_fpu_register(fd_reg(), -1);
3220 } else {
3221 set_fpu_register(fd_reg(), 0);
3222 }
3223 break;
3224 case CMP_EQ:
3225 if (fs == ft) {
3226 set_fpu_register(fd_reg(), -1);
3227 } else {
3228 set_fpu_register(fd_reg(), 0);
3229 }
3230 break;
3231 case CMP_UEQ:
3232 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3233 set_fpu_register(fd_reg(), -1);
3234 } else {
3235 set_fpu_register(fd_reg(), 0);
3236 }
3237 break;
3238 case CMP_LT:
3239 if (fs < ft) {
3240 set_fpu_register(fd_reg(), -1);
3241 } else {
3242 set_fpu_register(fd_reg(), 0);
3243 }
3244 break;
3245 case CMP_ULT:
3246 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3247 set_fpu_register(fd_reg(), -1);
3248 } else {
3249 set_fpu_register(fd_reg(), 0);
3250 }
3251 break;
3252 case CMP_LE:
3253 if (fs <= ft) {
3254 set_fpu_register(fd_reg(), -1);
3255 } else {
3256 set_fpu_register(fd_reg(), 0);
3257 }
3258 break;
3259 case CMP_ULE:
3260 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3261 set_fpu_register(fd_reg(), -1);
3262 } else {
3263 set_fpu_register(fd_reg(), 0);
3264 }
3265 break;
3266 case CMP_OR:
3267 if (!std::isnan(fs) && !std::isnan(ft)) {
3268 set_fpu_register(fd_reg(), -1);
3269 } else {
3270 set_fpu_register(fd_reg(), 0);
3271 }
3272 break;
3273 case CMP_UNE:
3274 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3275 set_fpu_register(fd_reg(), -1);
3276 } else {
3277 set_fpu_register(fd_reg(), 0);
3278 }
3279 break;
3280 case CMP_NE:
3281 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3282 set_fpu_register(fd_reg(), -1);
3283 } else {
3284 set_fpu_register(fd_reg(), 0);
3285 }
3286 break;
3287 default:
3288 UNREACHABLE();
3289 }
3290}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003291
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003293void Simulator::DecodeTypeRegisterCOP1() {
3294 switch (get_instr()->RsFieldRaw()) {
3295 case BC1: // Branch on coprocessor condition.
3296 case BC1EQZ:
3297 case BC1NEZ:
3298 UNREACHABLE();
3299 break;
3300 case CFC1:
3301 // At the moment only FCSR is supported.
3302 DCHECK(fs_reg() == kFCSRRegister);
3303 set_register(rt_reg(), FCSR_);
3304 break;
3305 case MFC1:
3306 set_register(rt_reg(),
3307 static_cast<int64_t>(get_fpu_register_word(fs_reg())));
3308 break;
3309 case DMFC1:
3310 set_register(rt_reg(), get_fpu_register(fs_reg()));
3311 break;
3312 case MFHC1:
3313 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3314 break;
3315 case CTC1: {
3316 // At the moment only FCSR is supported.
3317 DCHECK(fs_reg() == kFCSRRegister);
3318 uint32_t reg = static_cast<uint32_t>(rt());
3319 if (kArchVariant == kMips64r6) {
3320 FCSR_ = reg | kFCSRNaN2008FlagMask;
3321 } else {
3322 DCHECK(kArchVariant == kMips64r2);
3323 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3324 }
3325 break;
3326 }
3327 case MTC1:
3328 // Hardware writes upper 32-bits to zero on mtc1.
3329 set_fpu_register_hi_word(fs_reg(), 0);
3330 set_fpu_register_word(fs_reg(), static_cast<int32_t>(rt()));
3331 break;
3332 case DMTC1:
3333 set_fpu_register(fs_reg(), rt());
3334 break;
3335 case MTHC1:
3336 set_fpu_register_hi_word(fs_reg(), static_cast<int32_t>(rt()));
3337 break;
3338 case S:
3339 DecodeTypeRegisterSRsType();
3340 break;
3341 case D:
3342 DecodeTypeRegisterDRsType();
3343 break;
3344 case W:
3345 DecodeTypeRegisterWRsType();
3346 break;
3347 case L:
3348 DecodeTypeRegisterLRsType();
3349 break;
3350 default:
3351 UNREACHABLE();
3352 }
3353}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003355
3356void Simulator::DecodeTypeRegisterCOP1X() {
3357 switch (get_instr()->FunctionFieldRaw()) {
3358 case MADD_D:
3359 double fr, ft, fs;
3360 fr = get_fpu_register_double(fr_reg());
3361 fs = get_fpu_register_double(fs_reg());
3362 ft = get_fpu_register_double(ft_reg());
3363 set_fpu_register_double(fd_reg(), fs * ft + fr);
3364 break;
3365 default:
3366 UNREACHABLE();
3367 }
3368}
3369
3370
3371void Simulator::DecodeTypeRegisterSPECIAL() {
3372 int64_t i64hilo;
3373 uint64_t u64hilo;
3374 int64_t alu_out;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003375 bool do_interrupt = false;
3376
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003377 switch (get_instr()->FunctionFieldRaw()) {
3378 case SELEQZ_S:
3379 DCHECK(kArchVariant == kMips64r6);
3380 set_register(rd_reg(), rt() == 0 ? rs() : 0);
3381 break;
3382 case SELNEZ_S:
3383 DCHECK(kArchVariant == kMips64r6);
3384 set_register(rd_reg(), rt() != 0 ? rs() : 0);
3385 break;
3386 case JR: {
3387 int64_t next_pc = rs();
3388 int64_t current_pc = get_pc();
3389 Instruction* branch_delay_instr =
3390 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3391 BranchDelayInstructionDecode(branch_delay_instr);
3392 set_pc(next_pc);
3393 pc_modified_ = true;
3394 break;
3395 }
3396 case JALR: {
3397 int64_t next_pc = rs();
3398 int64_t current_pc = get_pc();
3399 int32_t return_addr_reg = rd_reg();
3400 Instruction* branch_delay_instr =
3401 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3402 BranchDelayInstructionDecode(branch_delay_instr);
3403 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3404 set_pc(next_pc);
3405 pc_modified_ = true;
3406 break;
3407 }
3408 case SLL:
3409 SetResult(rd_reg(), static_cast<int32_t>(rt()) << sa());
3410 break;
3411 case DSLL:
3412 SetResult(rd_reg(), rt() << sa());
3413 break;
3414 case DSLL32:
3415 SetResult(rd_reg(), rt() << sa() << 32);
3416 break;
3417 case SRL:
3418 if (rs_reg() == 0) {
3419 // Regular logical right shift of a word by a fixed number of
3420 // bits instruction. RS field is always equal to 0.
3421 // Sign-extend the 32-bit result.
3422 alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u()) >> sa());
3423 } else {
3424 // Logical right-rotate of a word by a fixed number of bits. This
3425 // is special case of SRL instruction, added in MIPS32 Release 2.
3426 // RS field is equal to 00001.
3427 alu_out = static_cast<int32_t>(
3428 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3429 static_cast<const uint32_t>(sa())));
3430 }
3431 SetResult(rd_reg(), alu_out);
3432 break;
3433 case DSRL:
3434 SetResult(rd_reg(), rt_u() >> sa());
3435 break;
3436 case DSRL32:
3437 SetResult(rd_reg(), rt_u() >> sa() >> 32);
3438 break;
3439 case SRA:
3440 SetResult(rd_reg(), (int32_t)rt() >> sa());
3441 break;
3442 case DSRA:
3443 SetResult(rd_reg(), rt() >> sa());
3444 break;
3445 case DSRA32:
3446 SetResult(rd_reg(), rt() >> sa() >> 32);
3447 break;
3448 case SLLV:
3449 SetResult(rd_reg(), (int32_t)rt() << rs());
3450 break;
3451 case DSLLV:
3452 SetResult(rd_reg(), rt() << rs());
3453 break;
3454 case SRLV:
3455 if (sa() == 0) {
3456 // Regular logical right-shift of a word by a variable number of
3457 // bits instruction. SA field is always equal to 0.
3458 alu_out = static_cast<int32_t>((uint32_t)rt_u() >> rs());
3459 } else {
3460 // Logical right-rotate of a word by a variable number of bits.
3461 // This is special case od SRLV instruction, added in MIPS32
3462 // Release 2. SA field is equal to 00001.
3463 alu_out = static_cast<int32_t>(
3464 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3465 static_cast<const uint32_t>(rs_u())));
3466 }
3467 SetResult(rd_reg(), alu_out);
3468 break;
3469 case DSRLV:
3470 if (sa() == 0) {
3471 // Regular logical right-shift of a word by a variable number of
3472 // bits instruction. SA field is always equal to 0.
3473 alu_out = rt_u() >> rs();
3474 } else {
3475 // Logical right-rotate of a word by a variable number of bits.
3476 // This is special case od SRLV instruction, added in MIPS32
3477 // Release 2. SA field is equal to 00001.
Ben Murdochda12d292016-06-02 14:46:10 +01003478 alu_out = base::bits::RotateRight64(rt_u(), rs_u());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003479 }
3480 SetResult(rd_reg(), alu_out);
3481 break;
3482 case SRAV:
3483 SetResult(rd_reg(), (int32_t)rt() >> rs());
3484 break;
3485 case DSRAV:
3486 SetResult(rd_reg(), rt() >> rs());
3487 break;
3488 case LSA: {
3489 DCHECK(kArchVariant == kMips64r6);
3490 int8_t sa = lsa_sa() + 1;
3491 int32_t _rt = static_cast<int32_t>(rt());
3492 int32_t _rs = static_cast<int32_t>(rs());
3493 int32_t res = _rs << sa;
3494 res += _rt;
3495 SetResult(rd_reg(), static_cast<int64_t>(res));
3496 break;
3497 }
3498 case DLSA:
3499 DCHECK(kArchVariant == kMips64r6);
3500 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3501 break;
3502 case MFHI: // MFHI == CLZ on R6.
3503 if (kArchVariant != kMips64r6) {
3504 DCHECK(sa() == 0);
3505 alu_out = get_register(HI);
3506 } else {
3507 // MIPS spec: If no bits were set in GPR rs(), the result written to
3508 // GPR rd() is 32.
3509 DCHECK(sa() == 1);
3510 alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u()));
3511 }
3512 SetResult(rd_reg(), alu_out);
3513 break;
3514 case MFLO: // MFLO == DCLZ on R6.
3515 if (kArchVariant != kMips64r6) {
3516 DCHECK(sa() == 0);
3517 alu_out = get_register(LO);
3518 } else {
3519 // MIPS spec: If no bits were set in GPR rs(), the result written to
3520 // GPR rd() is 64.
3521 DCHECK(sa() == 1);
3522 alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rs_u()));
3523 }
3524 SetResult(rd_reg(), alu_out);
3525 break;
3526 // Instructions using HI and LO registers.
3527 case MULT: { // MULT == D_MUL_MUH.
3528 int32_t rs_lo = static_cast<int32_t>(rs());
3529 int32_t rt_lo = static_cast<int32_t>(rt());
3530 i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
3531 if (kArchVariant != kMips64r6) {
3532 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3533 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3534 } else {
3535 switch (sa()) {
3536 case MUL_OP:
3537 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3538 break;
3539 case MUH_OP:
3540 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3541 break;
3542 default:
3543 UNIMPLEMENTED_MIPS();
3544 break;
3545 }
3546 }
3547 break;
3548 }
3549 case MULTU:
3550 u64hilo = static_cast<uint64_t>(rs_u() & 0xffffffff) *
3551 static_cast<uint64_t>(rt_u() & 0xffffffff);
3552 if (kArchVariant != kMips64r6) {
3553 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3554 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3555 } else {
3556 switch (sa()) {
3557 case MUL_OP:
3558 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3559 break;
3560 case MUH_OP:
3561 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3562 break;
3563 default:
3564 UNIMPLEMENTED_MIPS();
3565 break;
3566 }
3567 }
3568 break;
3569 case DMULT: // DMULT == D_MUL_MUH.
3570 if (kArchVariant != kMips64r6) {
3571 set_register(LO, rs() * rt());
3572 set_register(HI, MultiplyHighSigned(rs(), rt()));
3573 } else {
3574 switch (sa()) {
3575 case MUL_OP:
3576 set_register(rd_reg(), rs() * rt());
3577 break;
3578 case MUH_OP:
3579 set_register(rd_reg(), MultiplyHighSigned(rs(), rt()));
3580 break;
3581 default:
3582 UNIMPLEMENTED_MIPS();
3583 break;
3584 }
3585 }
3586 break;
3587 case DMULTU:
3588 UNIMPLEMENTED_MIPS();
3589 break;
3590 case DIV:
3591 case DDIV: {
3592 const int64_t int_min_value =
3593 get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
3594 switch (kArchVariant) {
3595 case kMips64r2:
3596 // Divide by zero and overflow was not checked in the
3597 // configuration step - div and divu do not raise exceptions. On
3598 // division by 0 the result will be UNPREDICTABLE. On overflow
3599 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3600 if (rs() == int_min_value && rt() == -1) {
3601 set_register(LO, int_min_value);
3602 set_register(HI, 0);
3603 } else if (rt() != 0) {
3604 set_register(LO, rs() / rt());
3605 set_register(HI, rs() % rt());
3606 }
3607 break;
3608 case kMips64r6:
3609 switch (sa()) {
3610 case DIV_OP:
3611 if (rs() == int_min_value && rt() == -1) {
3612 set_register(rd_reg(), int_min_value);
3613 } else if (rt() != 0) {
3614 set_register(rd_reg(), rs() / rt());
3615 }
3616 break;
3617 case MOD_OP:
3618 if (rs() == int_min_value && rt() == -1) {
3619 set_register(rd_reg(), 0);
3620 } else if (rt() != 0) {
3621 set_register(rd_reg(), rs() % rt());
3622 }
3623 break;
3624 default:
3625 UNIMPLEMENTED_MIPS();
3626 break;
3627 }
3628 break;
3629 default:
3630 break;
3631 }
3632 break;
3633 }
3634 case DIVU:
3635 switch (kArchVariant) {
3636 case kMips64r6: {
3637 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
3638 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
3639 switch (get_instr()->SaValue()) {
3640 case DIV_OP:
3641 if (rt_u_32 != 0) {
3642 set_register(rd_reg(), rs_u_32 / rt_u_32);
3643 }
3644 break;
3645 case MOD_OP:
3646 if (rt_u() != 0) {
3647 set_register(rd_reg(), rs_u_32 % rt_u_32);
3648 }
3649 break;
3650 default:
3651 UNIMPLEMENTED_MIPS();
3652 break;
3653 }
3654 } break;
3655 default: {
3656 if (rt_u() != 0) {
3657 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
3658 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
3659 set_register(LO, rs_u_32 / rt_u_32);
3660 set_register(HI, rs_u_32 % rt_u_32);
3661 }
3662 }
3663 }
3664 break;
3665 case DDIVU:
3666 switch (kArchVariant) {
3667 case kMips64r6: {
3668 switch (get_instr()->SaValue()) {
3669 case DIV_OP:
3670 if (rt_u() != 0) {
3671 set_register(rd_reg(), rs_u() / rt_u());
3672 }
3673 break;
3674 case MOD_OP:
3675 if (rt_u() != 0) {
3676 set_register(rd_reg(), rs_u() % rt_u());
3677 }
3678 break;
3679 default:
3680 UNIMPLEMENTED_MIPS();
3681 break;
3682 }
3683 } break;
3684 default: {
3685 if (rt_u() != 0) {
3686 set_register(LO, rs_u() / rt_u());
3687 set_register(HI, rs_u() % rt_u());
3688 }
3689 }
3690 }
3691 break;
3692 case ADD:
3693 case DADD:
3694 if (HaveSameSign(rs(), rt())) {
3695 if (rs() > 0) {
3696 if (rs() > (Registers::kMaxValue - rt())) {
3697 SignalException(kIntegerOverflow);
3698 }
3699 } else if (rs() < 0) {
3700 if (rs() < (Registers::kMinValue - rt())) {
3701 SignalException(kIntegerUnderflow);
3702 }
3703 }
3704 }
3705 SetResult(rd_reg(), rs() + rt());
3706 break;
3707 case ADDU: {
3708 int32_t alu32_out = static_cast<int32_t>(rs() + rt());
3709 // Sign-extend result of 32bit operation into 64bit register.
3710 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3711 break;
3712 }
3713 case DADDU:
3714 SetResult(rd_reg(), rs() + rt());
3715 break;
3716 case SUB:
3717 case DSUB:
3718 if (!HaveSameSign(rs(), rt())) {
3719 if (rs() > 0) {
3720 if (rs() > (Registers::kMaxValue + rt())) {
3721 SignalException(kIntegerOverflow);
3722 }
3723 } else if (rs() < 0) {
3724 if (rs() < (Registers::kMinValue + rt())) {
3725 SignalException(kIntegerUnderflow);
3726 }
3727 }
3728 }
3729 SetResult(rd_reg(), rs() - rt());
3730 break;
3731 case SUBU: {
3732 int32_t alu32_out = static_cast<int32_t>(rs() - rt());
3733 // Sign-extend result of 32bit operation into 64bit register.
3734 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3735 break;
3736 }
3737 case DSUBU:
3738 SetResult(rd_reg(), rs() - rt());
3739 break;
3740 case AND:
3741 SetResult(rd_reg(), rs() & rt());
3742 break;
3743 case OR:
3744 SetResult(rd_reg(), rs() | rt());
3745 break;
3746 case XOR:
3747 SetResult(rd_reg(), rs() ^ rt());
3748 break;
3749 case NOR:
3750 SetResult(rd_reg(), ~(rs() | rt()));
3751 break;
3752 case SLT:
3753 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3754 break;
3755 case SLTU:
3756 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3757 break;
3758 // Break and trap instructions.
3759 case BREAK:
3760 do_interrupt = true;
3761 break;
3762 case TGE:
3763 do_interrupt = rs() >= rt();
3764 break;
3765 case TGEU:
3766 do_interrupt = rs_u() >= rt_u();
3767 break;
3768 case TLT:
3769 do_interrupt = rs() < rt();
3770 break;
3771 case TLTU:
3772 do_interrupt = rs_u() < rt_u();
3773 break;
3774 case TEQ:
3775 do_interrupt = rs() == rt();
3776 break;
3777 case TNE:
3778 do_interrupt = rs() != rt();
3779 break;
3780 // Conditional moves.
3781 case MOVN:
3782 if (rt()) {
3783 SetResult(rd_reg(), rs());
3784 }
3785 break;
3786 case MOVCI: {
3787 uint32_t cc = get_instr()->FBccValue();
3788 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3789 if (get_instr()->Bit(16)) { // Read Tf bit.
3790 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3791 } else {
3792 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3793 }
3794 break;
3795 }
3796 case MOVZ:
3797 if (!rt()) {
3798 SetResult(rd_reg(), rs());
3799 }
3800 break;
3801 default:
3802 UNREACHABLE();
3803 }
3804 if (do_interrupt) {
3805 SoftwareInterrupt(get_instr());
3806 }
3807}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003808
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003809
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003810void Simulator::DecodeTypeRegisterSPECIAL2() {
3811 int64_t alu_out;
3812 switch (get_instr()->FunctionFieldRaw()) {
3813 case MUL:
3814 alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u());
3815 SetResult(rd_reg(), alu_out);
3816 // HI and LO are UNPREDICTABLE after the operation.
3817 set_register(LO, Unpredictable);
3818 set_register(HI, Unpredictable);
3819 break;
3820 case CLZ:
3821 // MIPS32 spec: If no bits were set in GPR rs(), the result written to
3822 // GPR rd is 32.
3823 alu_out = base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u()));
3824 SetResult(rd_reg(), alu_out);
3825 break;
3826 case DCLZ:
3827 // MIPS64 spec: If no bits were set in GPR rs(), the result written to
3828 // GPR rd is 64.
3829 alu_out = base::bits::CountLeadingZeros64(static_cast<uint64_t>(rs_u()));
3830 SetResult(rd_reg(), alu_out);
3831 break;
3832 default:
3833 alu_out = 0x12345678;
3834 UNREACHABLE();
3835 }
3836}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003837
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003838
3839void Simulator::DecodeTypeRegisterSPECIAL3() {
3840 int64_t alu_out;
3841 switch (get_instr()->FunctionFieldRaw()) {
3842 case INS: { // Mips64r2 instruction.
3843 // Interpret rd field as 5-bit msb of insert.
3844 uint16_t msb = rd_reg();
3845 // Interpret sa field as 5-bit lsb of insert.
3846 uint16_t lsb = sa();
3847 uint16_t size = msb - lsb + 1;
3848 uint64_t mask = (1ULL << size) - 1;
3849 alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) |
3850 ((rs_u() & mask) << lsb));
3851 SetResult(rt_reg(), alu_out);
3852 break;
3853 }
3854 case DINS: { // Mips64r2 instruction.
3855 // Interpret rd field as 5-bit msb of insert.
3856 uint16_t msb = rd_reg();
3857 // Interpret sa field as 5-bit lsb of insert.
3858 uint16_t lsb = sa();
3859 uint16_t size = msb - lsb + 1;
3860 uint64_t mask = (1ULL << size) - 1;
3861 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3862 SetResult(rt_reg(), alu_out);
3863 break;
3864 }
3865 case EXT: { // Mips64r2 instruction.
3866 // Interpret rd field as 5-bit msb of extract.
3867 uint16_t msb = rd_reg();
3868 // Interpret sa field as 5-bit lsb of extract.
3869 uint16_t lsb = sa();
3870 uint16_t size = msb + 1;
3871 uint64_t mask = (1ULL << size) - 1;
3872 alu_out = static_cast<int32_t>((rs_u() & (mask << lsb)) >> lsb);
3873 SetResult(rt_reg(), alu_out);
3874 break;
3875 }
3876 case DEXT: { // Mips64r2 instruction.
3877 // Interpret rd field as 5-bit msb of extract.
3878 uint16_t msb = rd_reg();
3879 // Interpret sa field as 5-bit lsb of extract.
3880 uint16_t lsb = sa();
3881 uint16_t size = msb + 1;
3882 uint64_t mask = (1ULL << size) - 1;
3883 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3884 SetResult(rt_reg(), alu_out);
3885 break;
3886 }
3887 case DEXTM: {
3888 // Interpret rd field as 5-bit msb of extract.
3889 uint16_t msb = rd_reg();
3890 // Interpret sa field as 5-bit lsb of extract.
3891 uint16_t lsb = sa();
3892 uint16_t size = msb + 33;
3893 uint64_t mask = (1ULL << size) - 1;
3894 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3895 SetResult(rt_reg(), alu_out);
3896 break;
3897 }
3898 case DEXTU: {
3899 // Interpret rd field as 5-bit msb of extract.
3900 uint16_t msb = rd_reg();
3901 // Interpret sa field as 5-bit lsb of extract.
3902 uint16_t lsb = sa() + 32;
3903 uint16_t size = msb + 1;
3904 uint64_t mask = (1ULL << size) - 1;
3905 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3906 SetResult(rt_reg(), alu_out);
3907 break;
3908 }
3909 case BSHFL: {
3910 int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
3911 switch (sa) {
3912 case BITSWAP: {
3913 uint32_t input = static_cast<uint32_t>(rt());
3914 uint32_t output = 0;
3915 uint8_t i_byte, o_byte;
3916
3917 // Reverse the bit in byte for each individual byte
3918 for (int i = 0; i < 4; i++) {
3919 output = output >> 8;
3920 i_byte = input & 0xff;
3921
3922 // Fast way to reverse bits in byte
3923 // Devised by Sean Anderson, July 13, 2001
3924 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3925 (i_byte * 0x8020LU & 0x88440LU)) *
3926 0x10101LU >>
3927 16);
3928
3929 output = output | (static_cast<uint32_t>(o_byte << 24));
3930 input = input >> 8;
3931 }
3932
3933 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
3934 break;
3935 }
3936 case SEB:
3937 case SEH:
3938 case WSBH:
3939 alu_out = 0x12345678;
3940 UNREACHABLE();
3941 break;
3942 default: {
3943 const uint8_t bp2 = get_instr()->Bp2Value();
3944 sa >>= kBp2Bits;
3945 switch (sa) {
3946 case ALIGN: {
3947 if (bp2 == 0) {
3948 alu_out = static_cast<int32_t>(rt());
3949 } else {
3950 uint64_t rt_hi = rt() << (8 * bp2);
3951 uint64_t rs_lo = rs() >> (8 * (4 - bp2));
3952 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
3953 }
3954 break;
3955 }
3956 default:
3957 alu_out = 0x12345678;
3958 UNREACHABLE();
3959 break;
3960 }
3961 break;
3962 }
3963 }
3964 SetResult(rd_reg(), alu_out);
3965 break;
3966 }
3967 case DBSHFL: {
3968 int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
3969 switch (sa) {
3970 case DBITSWAP: {
3971 switch (sa) {
3972 case DBITSWAP_SA: { // Mips64r6
3973 uint64_t input = static_cast<uint64_t>(rt());
3974 uint64_t output = 0;
3975 uint8_t i_byte, o_byte;
3976
3977 // Reverse the bit in byte for each individual byte
3978 for (int i = 0; i < 8; i++) {
3979 output = output >> 8;
3980 i_byte = input & 0xff;
3981
3982 // Fast way to reverse bits in byte
3983 // Devised by Sean Anderson, July 13, 2001
3984 o_byte =
3985 static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3986 (i_byte * 0x8020LU & 0x88440LU)) *
3987 0x10101LU >>
3988 16);
3989
3990 output = output | ((static_cast<uint64_t>(o_byte) << 56));
3991 input = input >> 8;
3992 }
3993
3994 alu_out = static_cast<int64_t>(output);
3995 break;
3996 }
3997 }
3998 break;
3999 }
4000 case DSBH:
4001 case DSHD:
4002 alu_out = 0x12345678;
4003 UNREACHABLE();
4004 break;
4005 default: {
4006 const uint8_t bp3 = get_instr()->Bp3Value();
4007 sa >>= kBp3Bits;
4008 switch (sa) {
4009 case DALIGN: {
4010 if (bp3 == 0) {
4011 alu_out = static_cast<int64_t>(rt());
4012 } else {
4013 uint64_t rt_hi = rt() << (8 * bp3);
4014 uint64_t rs_lo = rs() >> (8 * (8 - bp3));
4015 alu_out = static_cast<int64_t>(rt_hi | rs_lo);
4016 }
4017 break;
4018 }
4019 default:
4020 alu_out = 0x12345678;
4021 UNREACHABLE();
4022 break;
4023 }
4024 break;
4025 }
4026 }
4027 SetResult(rd_reg(), alu_out);
4028 break;
4029 }
4030 default:
4031 UNREACHABLE();
4032 }
4033}
4034
4035
4036void Simulator::DecodeTypeRegister(Instruction* instr) {
4037 set_instr(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004038
4039 // ---------- Execution.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004040 switch (instr->OpcodeFieldRaw()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004041 case COP1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004042 DecodeTypeRegisterCOP1();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004043 break;
4044 case COP1X:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004045 DecodeTypeRegisterCOP1X();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004046 break;
4047 case SPECIAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004048 DecodeTypeRegisterSPECIAL();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004049 break;
4050 case SPECIAL2:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004051 DecodeTypeRegisterSPECIAL2();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004052 break;
4053 case SPECIAL3:
4054 switch (instr->FunctionFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004055 case BSHFL: {
4056 int32_t saVal = sa();
4057 saVal >>= kBp2Bits;
4058 switch (saVal) {
4059 case ALIGN: {
4060 DecodeTypeRegisterSPECIAL3();
4061 break;
4062 }
4063 }
4064 }
4065 case DBSHFL: {
4066 int32_t saVal = sa();
4067 saVal >>= kBp2Bits;
4068 switch (saVal) {
4069 case DALIGN: {
4070 DecodeTypeRegisterSPECIAL3();
4071 break;
4072 }
4073 }
4074 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004075 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004076 DecodeTypeRegisterSPECIAL3();
4077 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004078 }
4079 break;
4080 // Unimplemented opcodes raised an error in the configuration step before,
4081 // so we can use the default here to set the destination register in common
4082 // cases.
4083 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004084 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004085 }
4086}
4087
4088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004089// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004090void Simulator::DecodeTypeImmediate(Instruction* instr) {
4091 // Instruction fields.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004092 Opcode op = instr->OpcodeFieldRaw();
4093 int32_t rs_reg = instr->RsValue();
4094 int64_t rs = get_register(instr->RsValue());
4095 uint64_t rs_u = static_cast<uint64_t>(rs);
4096 int32_t rt_reg = instr->RtValue(); // Destination register.
4097 int64_t rt = get_register(rt_reg);
4098 int16_t imm16 = instr->Imm16Value();
4099 int32_t imm18 = instr->Imm18Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004101 int32_t ft_reg = instr->FtValue(); // Destination register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004102
4103 // Zero extended immediate.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004104 uint64_t oe_imm16 = 0xffff & imm16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105 // Sign extended immediate.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004106 int64_t se_imm16 = imm16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004107 int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004109 // Next pc.
4110 int64_t next_pc = bad_ra;
4111
4112 // Used for conditional branch instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004113 bool execute_branch_delay_instruction = false;
4114
4115 // Used for arithmetic instructions.
4116 int64_t alu_out = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004117
4118 // Used for memory instructions.
4119 int64_t addr = 0x0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004120 // Alignment for 32-bit integers used in LWL, LWR, etc.
4121 const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
4122
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004123 // Branch instructions common part.
4124 auto BranchAndLinkHelper = [this, instr, &next_pc,
4125 &execute_branch_delay_instruction](
4126 bool do_branch) {
4127 execute_branch_delay_instruction = true;
4128 int64_t current_pc = get_pc();
4129 if (do_branch) {
4130 int16_t imm16 = instr->Imm16Value();
4131 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4132 set_register(31, current_pc + 2 * Instruction::kInstrSize);
4133 } else {
4134 next_pc = current_pc + 2 * Instruction::kInstrSize;
4135 }
4136 };
4137
4138 auto BranchHelper = [this, instr, &next_pc,
4139 &execute_branch_delay_instruction](bool do_branch) {
4140 execute_branch_delay_instruction = true;
4141 int64_t current_pc = get_pc();
4142 if (do_branch) {
4143 int16_t imm16 = instr->Imm16Value();
4144 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4145 } else {
4146 next_pc = current_pc + 2 * Instruction::kInstrSize;
4147 }
4148 };
4149
4150 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
4151 int bits) {
4152 int64_t current_pc = get_pc();
4153 CheckForbiddenSlot(current_pc);
4154 if (do_branch) {
4155 int32_t imm = instr->ImmValue(bits);
4156 imm <<= 32 - bits;
4157 imm >>= 32 - bits;
4158 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
4159 set_register(31, current_pc + Instruction::kInstrSize);
4160 }
4161 };
4162
4163 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
4164 int64_t current_pc = get_pc();
4165 CheckForbiddenSlot(current_pc);
4166 if (do_branch) {
4167 int32_t imm = instr->ImmValue(bits);
4168 imm <<= 32 - bits;
4169 imm >>= 32 - bits;
4170 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
4171 }
4172 };
4173
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004174 switch (op) {
4175 // ------------- COP1. Coprocessor instructions.
4176 case COP1:
4177 switch (instr->RsFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004178 case BC1: { // Branch on coprocessor condition.
4179 uint32_t cc = instr->FBccValue();
4180 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4181 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
4182 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
4183 BranchHelper(do_branch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004184 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004185 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004186 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004187 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004188 break;
4189 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004190 BranchHelper(get_fpu_register(ft_reg) & 0x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004191 break;
4192 default:
4193 UNREACHABLE();
4194 }
4195 break;
4196 // ------------- REGIMM class.
4197 case REGIMM:
4198 switch (instr->RtFieldRaw()) {
4199 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004200 BranchHelper(rs < 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004201 break;
4202 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004203 BranchHelper(rs >= 0);
4204 break;
4205 case BLTZAL:
4206 BranchAndLinkHelper(rs < 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004207 break;
4208 case BGEZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004209 BranchAndLinkHelper(rs >= 0);
4210 break;
4211 case DAHI:
4212 SetResult(rs_reg, rs + (se_imm16 << 32));
4213 break;
4214 case DATI:
4215 SetResult(rs_reg, rs + (se_imm16 << 48));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004216 break;
4217 default:
4218 UNREACHABLE();
4219 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004220 break; // case REGIMM.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004221 // ------------- Branch instructions.
4222 // When comparing to zero, the encoding of rt field is always 0, so we don't
4223 // need to replace rt with zero.
4224 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004225 BranchHelper(rs == rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004226 break;
4227 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004228 BranchHelper(rs != rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004229 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004230 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4231 if (kArchVariant == kMips64r6) {
4232 if (rt_reg != 0) {
4233 if (rs_reg == 0) { // BLEZALC
4234 BranchAndLinkCompactHelper(rt <= 0, 16);
4235 } else {
4236 if (rs_reg == rt_reg) { // BGEZALC
4237 BranchAndLinkCompactHelper(rt >= 0, 16);
4238 } else { // BGEUC
4239 BranchCompactHelper(
4240 static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16);
4241 }
4242 }
4243 } else { // BLEZ
4244 BranchHelper(rs <= 0);
4245 }
4246 } else { // BLEZ
4247 BranchHelper(rs <= 0);
4248 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004249 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004250 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4251 if (kArchVariant == kMips64r6) {
4252 if (rt_reg != 0) {
4253 if (rs_reg == 0) { // BGTZALC
4254 BranchAndLinkCompactHelper(rt > 0, 16);
4255 } else {
4256 if (rt_reg == rs_reg) { // BLTZALC
4257 BranchAndLinkCompactHelper(rt < 0, 16);
4258 } else { // BLTUC
4259 BranchCompactHelper(
4260 static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16);
4261 }
4262 }
4263 } else { // BGTZ
4264 BranchHelper(rs > 0);
4265 }
4266 } else { // BGTZ
4267 BranchHelper(rs > 0);
4268 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004269 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004270 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4271 if (kArchVariant == kMips64r6) {
4272 if (rt_reg != 0) {
4273 if (rs_reg == 0) { // BLEZC
4274 BranchCompactHelper(rt <= 0, 16);
4275 } else {
4276 if (rs_reg == rt_reg) { // BGEZC
4277 BranchCompactHelper(rt >= 0, 16);
4278 } else { // BGEC/BLEC
4279 BranchCompactHelper(rs >= rt, 16);
4280 }
4281 }
4282 }
4283 } else { // BLEZL
4284 BranchAndLinkHelper(rs <= 0);
4285 }
4286 break;
4287 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4288 if (kArchVariant == kMips64r6) {
4289 if (rt_reg != 0) {
4290 if (rs_reg == 0) { // BGTZC
4291 BranchCompactHelper(rt > 0, 16);
4292 } else {
4293 if (rs_reg == rt_reg) { // BLTZC
4294 BranchCompactHelper(rt < 0, 16);
4295 } else { // BLTC/BGTC
4296 BranchCompactHelper(rs < rt, 16);
4297 }
4298 }
4299 }
4300 } else { // BGTZL
4301 BranchAndLinkHelper(rs > 0);
4302 }
4303 break;
4304 case POP66: // BEQZC, JIC
4305 if (rs_reg != 0) { // BEQZC
4306 BranchCompactHelper(rs == 0, 21);
4307 } else { // JIC
4308 next_pc = rt + imm16;
4309 }
4310 break;
4311 case POP76: // BNEZC, JIALC
4312 if (rs_reg != 0) { // BNEZC
4313 BranchCompactHelper(rs != 0, 21);
4314 } else { // JIALC
4315 int64_t current_pc = get_pc();
4316 set_register(31, current_pc + Instruction::kInstrSize);
4317 next_pc = rt + imm16;
4318 }
4319 break;
4320 case BC:
4321 BranchCompactHelper(true, 26);
4322 break;
4323 case BALC:
4324 BranchAndLinkCompactHelper(true, 26);
4325 break;
4326 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4327 if (kArchVariant == kMips64r6) {
4328 if (rs_reg >= rt_reg) { // BOVC
Ben Murdochda12d292016-06-02 14:46:10 +01004329 bool condition = !is_int32(rs) || !is_int32(rt) || !is_int32(rs + rt);
4330 BranchCompactHelper(condition, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004331 } else {
4332 if (rs_reg == 0) { // BEQZALC
4333 BranchAndLinkCompactHelper(rt == 0, 16);
4334 } else { // BEQC
4335 BranchCompactHelper(rt == rs, 16);
4336 }
4337 }
4338 } else { // ADDI
4339 if (HaveSameSign(rs, se_imm16)) {
4340 if (rs > 0) {
4341 if (rs <= Registers::kMaxValue - se_imm16) {
4342 SignalException(kIntegerOverflow);
4343 }
4344 } else if (rs < 0) {
4345 if (rs >= Registers::kMinValue - se_imm16) {
4346 SignalException(kIntegerUnderflow);
4347 }
4348 }
4349 }
4350 SetResult(rt_reg, rs + se_imm16);
4351 }
4352 break;
4353 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4354 if (kArchVariant == kMips64r6) {
4355 if (rs_reg >= rt_reg) { // BNVC
Ben Murdochda12d292016-06-02 14:46:10 +01004356 bool condition = is_int32(rs) && is_int32(rt) && is_int32(rs + rt);
4357 BranchCompactHelper(condition, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004358 } else {
4359 if (rs_reg == 0) { // BNEZALC
4360 BranchAndLinkCompactHelper(rt != 0, 16);
4361 } else { // BNEC
4362 BranchCompactHelper(rt != rs, 16);
4363 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004364 }
4365 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004366 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004367 // ------------- Arithmetic instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004368 case ADDIU: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004369 int32_t alu32_out = static_cast<int32_t>(rs + se_imm16);
4370 // Sign-extend result of 32bit operation into 64bit register.
4371 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004372 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004373 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004374 case DADDIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004375 SetResult(rt_reg, rs + se_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004376 break;
4377 case SLTI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004378 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004379 break;
4380 case SLTIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004381 SetResult(rt_reg, rs_u < static_cast<uint64_t>(se_imm16) ? 1 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004382 break;
4383 case ANDI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004384 SetResult(rt_reg, rs & oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004385 break;
4386 case ORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004387 SetResult(rt_reg, rs | oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004388 break;
4389 case XORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004390 SetResult(rt_reg, rs ^ oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004391 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004392 case LUI:
4393 if (rs_reg != 0) {
4394 // AUI instruction.
4395 DCHECK(kArchVariant == kMips64r6);
4396 int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16));
4397 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
4398 } else {
4399 // LUI instruction.
4400 int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004401 // Sign-extend result of 32bit operation into 64bit register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004402 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004403 }
4404 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004405 case DAUI:
4406 DCHECK(kArchVariant == kMips64r6);
4407 DCHECK(rs_reg != 0);
4408 SetResult(rt_reg, rs + (se_imm16 << 16));
4409 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004410 // ------------- Memory instructions.
4411 case LB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004412 set_register(rt_reg, ReadB(rs + se_imm16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004413 break;
4414 case LH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004415 set_register(rt_reg, ReadH(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004416 break;
4417 case LWL: {
4418 // al_offset is offset of the effective address within an aligned word.
4419 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4420 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4421 uint32_t mask = (1 << byte_shift * 8) - 1;
4422 addr = rs + se_imm16 - al_offset;
4423 alu_out = ReadW(addr, instr);
4424 alu_out <<= byte_shift * 8;
4425 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004426 set_register(rt_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004427 break;
4428 }
4429 case LW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004430 set_register(rt_reg, ReadW(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004431 break;
4432 case LWU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004433 set_register(rt_reg, ReadWU(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004434 break;
4435 case LD:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004436 set_register(rt_reg, Read2W(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004437 break;
4438 case LBU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004439 set_register(rt_reg, ReadBU(rs + se_imm16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004440 break;
4441 case LHU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004442 set_register(rt_reg, ReadHU(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004443 break;
4444 case LWR: {
4445 // al_offset is offset of the effective address within an aligned word.
4446 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4447 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4448 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4449 addr = rs + se_imm16 - al_offset;
4450 alu_out = ReadW(addr, instr);
4451 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4452 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004453 set_register(rt_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004454 break;
4455 }
4456 case SB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004457 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004458 break;
4459 case SH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004460 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004461 break;
4462 case SWL: {
4463 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4464 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4465 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4466 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004467 uint64_t mem_value = ReadW(addr, instr) & mask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004468 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004469 WriteW(addr, static_cast<int32_t>(mem_value), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004470 break;
4471 }
4472 case SW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004473 WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr);
4474 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004475 case SD:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004476 Write2W(rs + se_imm16, rt, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004477 break;
4478 case SWR: {
4479 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4480 uint32_t mask = (1 << al_offset * 8) - 1;
4481 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004482 uint64_t mem_value = ReadW(addr, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004483 mem_value = (rt << al_offset * 8) | (mem_value & mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004484 WriteW(addr, static_cast<int32_t>(mem_value), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004485 break;
4486 }
4487 case LWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004488 set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
4489 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004490 break;
4491 case LDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004492 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004493 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004494 case SWC1: {
4495 int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg));
4496 WriteW(rs + se_imm16, alu_out_32, instr);
4497 break;
4498 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004499 case SDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004500 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004501 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004502 // ------------- PC-Relative instructions.
4503 case PCREL: {
4504 // rt field: checking 5-bits.
4505 int32_t imm21 = instr->Imm21Value();
4506 int64_t current_pc = get_pc();
4507 uint8_t rt = (imm21 >> kImm16Bits);
4508 switch (rt) {
4509 case ALUIPC:
4510 addr = current_pc + (se_imm16 << 16);
4511 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4512 break;
4513 case AUIPC:
4514 alu_out = current_pc + (se_imm16 << 16);
4515 break;
4516 default: {
4517 int32_t imm19 = instr->Imm19Value();
4518 // rt field: checking the most significant 3-bits.
4519 rt = (imm21 >> kImm18Bits);
4520 switch (rt) {
4521 case LDPC:
4522 addr =
4523 (current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
4524 alu_out = Read2W(addr, instr);
4525 break;
4526 default: {
4527 // rt field: checking the most significant 2-bits.
4528 rt = (imm21 >> kImm19Bits);
4529 switch (rt) {
4530 case LWUPC: {
4531 // Set sign.
4532 imm19 <<= (kOpcodeBits + kRsBits + 2);
4533 imm19 >>= (kOpcodeBits + kRsBits + 2);
4534 addr = current_pc + (imm19 << 2);
4535 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4536 alu_out = *ptr;
4537 break;
4538 }
4539 case LWPC: {
4540 // Set sign.
4541 imm19 <<= (kOpcodeBits + kRsBits + 2);
4542 imm19 >>= (kOpcodeBits + kRsBits + 2);
4543 addr = current_pc + (imm19 << 2);
4544 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
4545 alu_out = *ptr;
4546 break;
4547 }
4548 case ADDIUPC: {
4549 int64_t se_imm19 =
4550 imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
4551 alu_out = current_pc + (se_imm19 << 2);
4552 break;
4553 }
4554 default:
4555 UNREACHABLE();
4556 break;
4557 }
4558 break;
4559 }
4560 }
4561 break;
4562 }
4563 }
4564 set_register(rs_reg, alu_out);
4565 break;
4566 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004567 default:
4568 UNREACHABLE();
4569 }
4570
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004571 if (execute_branch_delay_instruction) {
4572 // Execute branch delay slot
4573 // We don't check for end_sim_pc. First it should not be met as the current
4574 // pc is valid. Secondly a jump should always execute its branch delay slot.
4575 Instruction* branch_delay_instr =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004576 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004577 BranchDelayInstructionDecode(branch_delay_instr);
4578 }
4579
4580 // If needed update pc after the branch delay execution.
4581 if (next_pc != bad_ra) {
4582 set_pc(next_pc);
4583 }
4584}
4585
4586
4587// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
4588void Simulator::DecodeTypeJump(Instruction* instr) {
4589 // Get current pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004590 int64_t current_pc = get_pc();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004591 // Get unchanged bits of pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004592 int64_t pc_high_bits = current_pc & 0xfffffffff0000000;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004593 // Next pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004594 int64_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004595
4596 // Execute branch delay slot.
4597 // We don't check for end_sim_pc. First it should not be met as the current pc
4598 // is valid. Secondly a jump should always execute its branch delay slot.
4599 Instruction* branch_delay_instr =
4600 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
4601 BranchDelayInstructionDecode(branch_delay_instr);
4602
4603 // Update pc and ra if necessary.
4604 // Do this after the branch delay execution.
4605 if (instr->IsLinkingInstruction()) {
4606 set_register(31, current_pc + 2 * Instruction::kInstrSize);
4607 }
4608 set_pc(next_pc);
4609 pc_modified_ = true;
4610}
4611
4612
4613// Executes the current instruction.
4614void Simulator::InstructionDecode(Instruction* instr) {
4615 if (v8::internal::FLAG_check_icache) {
4616 CheckICache(isolate_->simulator_i_cache(), instr);
4617 }
4618 pc_modified_ = false;
4619
4620 v8::internal::EmbeddedVector<char, 256> buffer;
4621
4622 if (::v8::internal::FLAG_trace_sim) {
4623 SNPrintF(trace_buf_, " ");
4624 disasm::NameConverter converter;
4625 disasm::Disassembler dasm(converter);
4626 // Use a reasonably large buffer.
4627 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
4628 }
4629
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004630 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004631 case Instruction::kRegisterType:
4632 DecodeTypeRegister(instr);
4633 break;
4634 case Instruction::kImmediateType:
4635 DecodeTypeImmediate(instr);
4636 break;
4637 case Instruction::kJumpType:
4638 DecodeTypeJump(instr);
4639 break;
4640 default:
4641 UNSUPPORTED();
4642 }
4643
4644 if (::v8::internal::FLAG_trace_sim) {
4645 PrintF(" 0x%08lx %-44s %s\n", reinterpret_cast<intptr_t>(instr),
4646 buffer.start(), trace_buf_.start());
4647 }
4648
4649 if (!pc_modified_) {
4650 set_register(pc, reinterpret_cast<int64_t>(instr) +
4651 Instruction::kInstrSize);
4652 }
4653}
4654
4655
4656
4657void Simulator::Execute() {
4658 // Get the PC to simulate. Cannot use the accessor here as we need the
4659 // raw PC value and not the one used as input to arithmetic instructions.
4660 int64_t program_counter = get_pc();
4661 if (::v8::internal::FLAG_stop_sim_at == 0) {
4662 // Fast version of the dispatch loop without checking whether the simulator
4663 // should be stopping at a particular executed instruction.
4664 while (program_counter != end_sim_pc) {
4665 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4666 icount_++;
4667 InstructionDecode(instr);
4668 program_counter = get_pc();
4669 }
4670 } else {
4671 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4672 // we reach the particular instuction count.
4673 while (program_counter != end_sim_pc) {
4674 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4675 icount_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004676 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004677 MipsDebugger dbg(this);
4678 dbg.Debug();
4679 } else {
4680 InstructionDecode(instr);
4681 }
4682 program_counter = get_pc();
4683 }
4684 }
4685}
4686
4687
4688void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004689 // Adjust JS-based stack limit to C-based stack limit.
4690 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4691
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004692 // Prepare to execute the code at entry.
4693 set_register(pc, reinterpret_cast<int64_t>(entry));
4694 // Put down marker for end of simulation. The simulator will stop simulation
4695 // when the PC reaches this value. By saving the "end simulation" value into
4696 // the LR the simulation stops when returning to this call point.
4697 set_register(ra, end_sim_pc);
4698
4699 // Remember the values of callee-saved registers.
4700 // The code below assumes that r9 is not used as sb (static base) in
4701 // simulator code and therefore is regarded as a callee-saved register.
4702 int64_t s0_val = get_register(s0);
4703 int64_t s1_val = get_register(s1);
4704 int64_t s2_val = get_register(s2);
4705 int64_t s3_val = get_register(s3);
4706 int64_t s4_val = get_register(s4);
4707 int64_t s5_val = get_register(s5);
4708 int64_t s6_val = get_register(s6);
4709 int64_t s7_val = get_register(s7);
4710 int64_t gp_val = get_register(gp);
4711 int64_t sp_val = get_register(sp);
4712 int64_t fp_val = get_register(fp);
4713
4714 // Set up the callee-saved registers with a known value. To be able to check
4715 // that they are preserved properly across JS execution.
4716 int64_t callee_saved_value = icount_;
4717 set_register(s0, callee_saved_value);
4718 set_register(s1, callee_saved_value);
4719 set_register(s2, callee_saved_value);
4720 set_register(s3, callee_saved_value);
4721 set_register(s4, callee_saved_value);
4722 set_register(s5, callee_saved_value);
4723 set_register(s6, callee_saved_value);
4724 set_register(s7, callee_saved_value);
4725 set_register(gp, callee_saved_value);
4726 set_register(fp, callee_saved_value);
4727
4728 // Start the simulation.
4729 Execute();
4730
4731 // Check that the callee-saved registers have been preserved.
4732 CHECK_EQ(callee_saved_value, get_register(s0));
4733 CHECK_EQ(callee_saved_value, get_register(s1));
4734 CHECK_EQ(callee_saved_value, get_register(s2));
4735 CHECK_EQ(callee_saved_value, get_register(s3));
4736 CHECK_EQ(callee_saved_value, get_register(s4));
4737 CHECK_EQ(callee_saved_value, get_register(s5));
4738 CHECK_EQ(callee_saved_value, get_register(s6));
4739 CHECK_EQ(callee_saved_value, get_register(s7));
4740 CHECK_EQ(callee_saved_value, get_register(gp));
4741 CHECK_EQ(callee_saved_value, get_register(fp));
4742
4743 // Restore callee-saved registers with the original value.
4744 set_register(s0, s0_val);
4745 set_register(s1, s1_val);
4746 set_register(s2, s2_val);
4747 set_register(s3, s3_val);
4748 set_register(s4, s4_val);
4749 set_register(s5, s5_val);
4750 set_register(s6, s6_val);
4751 set_register(s7, s7_val);
4752 set_register(gp, gp_val);
4753 set_register(sp, sp_val);
4754 set_register(fp, fp_val);
4755}
4756
4757
4758int64_t Simulator::Call(byte* entry, int argument_count, ...) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004759 const int kRegisterPassedArguments = 8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004760 va_list parameters;
4761 va_start(parameters, argument_count);
4762 // Set up arguments.
4763
4764 // First four arguments passed in registers in both ABI's.
4765 DCHECK(argument_count >= 4);
4766 set_register(a0, va_arg(parameters, int64_t));
4767 set_register(a1, va_arg(parameters, int64_t));
4768 set_register(a2, va_arg(parameters, int64_t));
4769 set_register(a3, va_arg(parameters, int64_t));
4770
Ben Murdoch097c5b22016-05-18 11:27:45 +01004771 // Up to eight arguments passed in registers in N64 ABI.
4772 // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this.
4773 if (argument_count >= 5) set_register(a4, va_arg(parameters, int64_t));
4774 if (argument_count >= 6) set_register(a5, va_arg(parameters, int64_t));
4775 if (argument_count >= 7) set_register(a6, va_arg(parameters, int64_t));
4776 if (argument_count >= 8) set_register(a7, va_arg(parameters, int64_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004777
4778 // Remaining arguments passed on stack.
4779 int64_t original_stack = get_register(sp);
4780 // Compute position of stack on entry to generated code.
4781 int stack_args_count = (argument_count > kRegisterPassedArguments) ?
4782 (argument_count - kRegisterPassedArguments) : 0;
4783 int stack_args_size = stack_args_count * sizeof(int64_t) + kCArgsSlotsSize;
4784 int64_t entry_stack = original_stack - stack_args_size;
4785
4786 if (base::OS::ActivationFrameAlignment() != 0) {
4787 entry_stack &= -base::OS::ActivationFrameAlignment();
4788 }
4789 // Store remaining arguments on stack, from low to high memory.
4790 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4791 for (int i = kRegisterPassedArguments; i < argument_count; i++) {
4792 int stack_index = i - kRegisterPassedArguments + kCArgSlotCount;
4793 stack_argument[stack_index] = va_arg(parameters, int64_t);
4794 }
4795 va_end(parameters);
4796 set_register(sp, entry_stack);
4797
4798 CallInternal(entry);
4799
4800 // Pop stack passed arguments.
4801 CHECK_EQ(entry_stack, get_register(sp));
4802 set_register(sp, original_stack);
4803
4804 int64_t result = get_register(v0);
4805 return result;
4806}
4807
4808
4809double Simulator::CallFP(byte* entry, double d0, double d1) {
4810 if (!IsMipsSoftFloatABI) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004811 const FPURegister fparg2 = f13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004812 set_fpu_register_double(f12, d0);
4813 set_fpu_register_double(fparg2, d1);
4814 } else {
4815 int buffer[2];
4816 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4817 memcpy(buffer, &d0, sizeof(d0));
4818 set_dw_register(a0, buffer);
4819 memcpy(buffer, &d1, sizeof(d1));
4820 set_dw_register(a2, buffer);
4821 }
4822 CallInternal(entry);
4823 if (!IsMipsSoftFloatABI) {
4824 return get_fpu_register_double(f0);
4825 } else {
4826 return get_double_from_register_pair(v0);
4827 }
4828}
4829
4830
4831uintptr_t Simulator::PushAddress(uintptr_t address) {
4832 int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
4833 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4834 *stack_slot = address;
4835 set_register(sp, new_sp);
4836 return new_sp;
4837}
4838
4839
4840uintptr_t Simulator::PopAddress() {
4841 int64_t current_sp = get_register(sp);
4842 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4843 uintptr_t address = *stack_slot;
4844 set_register(sp, current_sp + sizeof(uintptr_t));
4845 return address;
4846}
4847
4848
4849#undef UNSUPPORTED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004850} // namespace internal
4851} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004852
4853#endif // USE_SIMULATOR
4854
4855#endif // V8_TARGET_ARCH_MIPS64