blob: ed484ef2fbf0e2b764e840b5283d698c071fc5a6 [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.
Ben Murdochc5610432016-08-08 18:44:38 +0100271 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64
272 "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273 REG_INFO(1), REG_INFO(2), REG_INFO(4));
274 // v1, a1.
Ben Murdochc5610432016-08-08 18:44:38 +0100275 PrintF("%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
276 " %14" PRId64 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 "", REG_INFO(3), REG_INFO(5));
278 // a2.
Ben Murdochc5610432016-08-08 18:44:38 +0100279 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
280 REG_INFO(6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281 // a3.
Ben Murdochc5610432016-08-08 18:44:38 +0100282 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
283 REG_INFO(7));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 PrintF("\n");
285 // a4-t3, s0-s7
286 for (int i = 0; i < 8; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100287 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
288 " %14" PRId64 " \n",
289 REG_INFO(8 + i), REG_INFO(16 + i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 }
291 PrintF("\n");
292 // t8, k0, LO.
Ben Murdochc5610432016-08-08 18:44:38 +0100293 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
294 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 REG_INFO(24), REG_INFO(26), REG_INFO(32));
296 // t9, k1, HI.
Ben Murdochc5610432016-08-08 18:44:38 +0100297 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
298 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 REG_INFO(25), REG_INFO(27), REG_INFO(33));
300 // sp, fp, gp.
Ben Murdochc5610432016-08-08 18:44:38 +0100301 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
302 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303 REG_INFO(29), REG_INFO(30), REG_INFO(28));
304 // pc.
Ben Murdochc5610432016-08-08 18:44:38 +0100305 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
306 " %14" PRId64 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 REG_INFO(31), REG_INFO(34));
308
309#undef REG_INFO
310#undef FPU_REG_INFO
311}
312
313
314void MipsDebugger::PrintAllRegsIncludingFPU() {
315#define FPU_REG_INFO(n) FPURegisters::Name(n), \
316 GetFPURegisterValue(n), \
317 GetFPURegisterValueDouble(n)
318
319 PrintAllRegs();
320
321 PrintF("\n\n");
322 // f0, f1, f2, ... f31.
323 // TODO(plind): consider printing 2 columns for space efficiency.
Ben Murdochc5610432016-08-08 18:44:38 +0100324 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(0));
325 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(1));
326 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(2));
327 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(3));
328 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(4));
329 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(5));
330 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(6));
331 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(7));
332 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(8));
333 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(9));
334 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(10));
335 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(11));
336 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(12));
337 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(13));
338 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(14));
339 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(15));
340 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(16));
341 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(17));
342 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(18));
343 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(19));
344 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(20));
345 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(21));
346 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(22));
347 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(23));
348 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(24));
349 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(25));
350 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(26));
351 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(27));
352 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(28));
353 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(29));
354 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(30));
355 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(31));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356
357#undef REG_INFO
358#undef FPU_REG_INFO
359}
360
361
362void MipsDebugger::Debug() {
363 intptr_t last_pc = -1;
364 bool done = false;
365
366#define COMMAND_SIZE 63
367#define ARG_SIZE 255
368
369#define STR(a) #a
370#define XSTR(a) STR(a)
371
372 char cmd[COMMAND_SIZE + 1];
373 char arg1[ARG_SIZE + 1];
374 char arg2[ARG_SIZE + 1];
375 char* argv[3] = { cmd, arg1, arg2 };
376
377 // Make sure to have a proper terminating character if reaching the limit.
378 cmd[COMMAND_SIZE] = 0;
379 arg1[ARG_SIZE] = 0;
380 arg2[ARG_SIZE] = 0;
381
382 // Undo all set breakpoints while running in the debugger shell. This will
383 // make them invisible to all commands.
384 UndoBreakpoints();
385
386 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
387 if (last_pc != sim_->get_pc()) {
388 disasm::NameConverter converter;
389 disasm::Disassembler dasm(converter);
390 // Use a reasonably large buffer.
391 v8::internal::EmbeddedVector<char, 256> buffer;
392 dasm.InstructionDecode(buffer,
393 reinterpret_cast<byte*>(sim_->get_pc()));
Ben Murdochc5610432016-08-08 18:44:38 +0100394 PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000395 last_pc = sim_->get_pc();
396 }
397 char* line = ReadLine("sim> ");
398 if (line == NULL) {
399 break;
400 } else {
401 char* last_input = sim_->last_debugger_input();
402 if (strcmp(line, "\n") == 0 && last_input != NULL) {
403 line = last_input;
404 } else {
405 // Ownership is transferred to sim_;
406 sim_->set_last_debugger_input(line);
407 }
408 // Use sscanf to parse the individual parts of the command line. At the
409 // moment no command expects more than two parameters.
410 int argc = SScanF(line,
411 "%" XSTR(COMMAND_SIZE) "s "
412 "%" XSTR(ARG_SIZE) "s "
413 "%" XSTR(ARG_SIZE) "s",
414 cmd, arg1, arg2);
415 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
416 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
417 if (!(instr->IsTrap()) ||
418 instr->InstructionBits() == rtCallRedirInstr) {
419 sim_->InstructionDecode(
420 reinterpret_cast<Instruction*>(sim_->get_pc()));
421 } else {
422 // Allow si to jump over generated breakpoints.
423 PrintF("/!\\ Jumping over generated breakpoint.\n");
424 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
425 }
426 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
427 // Execute the one instruction we broke at with breakpoints disabled.
428 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
429 // Leave the debugger shell.
430 done = true;
431 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
432 if (argc == 2) {
433 int64_t value;
434 double dvalue;
435 if (strcmp(arg1, "all") == 0) {
436 PrintAllRegs();
437 } else if (strcmp(arg1, "allf") == 0) {
438 PrintAllRegsIncludingFPU();
439 } else {
440 int regnum = Registers::Number(arg1);
441 int fpuregnum = FPURegisters::Number(arg1);
442
443 if (regnum != kInvalidRegister) {
444 value = GetRegisterValue(regnum);
Ben Murdochc5610432016-08-08 18:44:38 +0100445 PrintF("%s: 0x%08" PRIx64 " %" PRId64 " \n", arg1, value,
446 value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 } else if (fpuregnum != kInvalidFPURegister) {
448 value = GetFPURegisterValue(fpuregnum);
449 dvalue = GetFPURegisterValueDouble(fpuregnum);
Ben Murdochc5610432016-08-08 18:44:38 +0100450 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000451 FPURegisters::Name(fpuregnum), value, dvalue);
452 } else {
453 PrintF("%s unrecognized\n", arg1);
454 }
455 }
456 } else {
457 if (argc == 3) {
458 if (strcmp(arg2, "single") == 0) {
459 int64_t value;
460 float fvalue;
461 int fpuregnum = FPURegisters::Number(arg1);
462
463 if (fpuregnum != kInvalidFPURegister) {
464 value = GetFPURegisterValue(fpuregnum);
465 value &= 0xffffffffUL;
466 fvalue = GetFPURegisterValueFloat(fpuregnum);
Ben Murdochc5610432016-08-08 18:44:38 +0100467 PrintF("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 } else {
469 PrintF("%s unrecognized\n", arg1);
470 }
471 } else {
472 PrintF("print <fpu register> single\n");
473 }
474 } else {
475 PrintF("print <register> or print <fpu register> single\n");
476 }
477 }
478 } else if ((strcmp(cmd, "po") == 0)
479 || (strcmp(cmd, "printobject") == 0)) {
480 if (argc == 2) {
481 int64_t value;
482 OFStream os(stdout);
483 if (GetValue(arg1, &value)) {
484 Object* obj = reinterpret_cast<Object*>(value);
485 os << arg1 << ": \n";
486#ifdef DEBUG
487 obj->Print(os);
488 os << "\n";
489#else
490 os << Brief(obj) << "\n";
491#endif
492 } else {
493 os << arg1 << " unrecognized\n";
494 }
495 } else {
496 PrintF("printobject <value>\n");
497 }
498 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
499 int64_t* cur = NULL;
500 int64_t* end = NULL;
501 int next_arg = 1;
502
503 if (strcmp(cmd, "stack") == 0) {
504 cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
505 } else { // Command "mem".
506 int64_t value;
507 if (!GetValue(arg1, &value)) {
508 PrintF("%s unrecognized\n", arg1);
509 continue;
510 }
511 cur = reinterpret_cast<int64_t*>(value);
512 next_arg++;
513 }
514
515 int64_t words;
516 if (argc == next_arg) {
517 words = 10;
518 } else {
519 if (!GetValue(argv[next_arg], &words)) {
520 words = 10;
521 }
522 }
523 end = cur + words;
524
525 while (cur < end) {
Ben Murdochc5610432016-08-08 18:44:38 +0100526 PrintF(" 0x%012" PRIxPTR " : 0x%016" PRIx64 " %14" PRId64 " ",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 reinterpret_cast<intptr_t>(cur), *cur, *cur);
528 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
529 int64_t value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 Heap* current_heap = sim_->isolate_->heap();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100531 if (((value & 1) == 0) ||
532 current_heap->ContainsSlow(obj->address())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 PrintF(" (");
534 if ((value & 1) == 0) {
535 PrintF("smi %d", static_cast<int>(value >> 32));
536 } else {
537 obj->ShortPrint();
538 }
539 PrintF(")");
540 }
541 PrintF("\n");
542 cur++;
543 }
544
545 } else if ((strcmp(cmd, "disasm") == 0) ||
546 (strcmp(cmd, "dpc") == 0) ||
547 (strcmp(cmd, "di") == 0)) {
548 disasm::NameConverter converter;
549 disasm::Disassembler dasm(converter);
550 // Use a reasonably large buffer.
551 v8::internal::EmbeddedVector<char, 256> buffer;
552
553 byte* cur = NULL;
554 byte* end = NULL;
555
556 if (argc == 1) {
557 cur = reinterpret_cast<byte*>(sim_->get_pc());
558 end = cur + (10 * Instruction::kInstrSize);
559 } else if (argc == 2) {
560 int regnum = Registers::Number(arg1);
561 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
562 // The argument is an address or a register name.
563 int64_t value;
564 if (GetValue(arg1, &value)) {
565 cur = reinterpret_cast<byte*>(value);
566 // Disassemble 10 instructions at <arg1>.
567 end = cur + (10 * Instruction::kInstrSize);
568 }
569 } else {
570 // The argument is the number of instructions.
571 int64_t value;
572 if (GetValue(arg1, &value)) {
573 cur = reinterpret_cast<byte*>(sim_->get_pc());
574 // Disassemble <arg1> instructions.
575 end = cur + (value * Instruction::kInstrSize);
576 }
577 }
578 } else {
579 int64_t value1;
580 int64_t value2;
581 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
582 cur = reinterpret_cast<byte*>(value1);
583 end = cur + (value2 * Instruction::kInstrSize);
584 }
585 }
586
587 while (cur < end) {
588 dasm.InstructionDecode(buffer, cur);
Ben Murdochc5610432016-08-08 18:44:38 +0100589 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
590 buffer.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 cur += Instruction::kInstrSize;
592 }
593 } else if (strcmp(cmd, "gdb") == 0) {
594 PrintF("relinquishing control to gdb\n");
595 v8::base::OS::DebugBreak();
596 PrintF("regaining control from gdb\n");
597 } else if (strcmp(cmd, "break") == 0) {
598 if (argc == 2) {
599 int64_t value;
600 if (GetValue(arg1, &value)) {
601 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
602 PrintF("setting breakpoint failed\n");
603 }
604 } else {
605 PrintF("%s unrecognized\n", arg1);
606 }
607 } else {
608 PrintF("break <address>\n");
609 }
610 } else if (strcmp(cmd, "del") == 0) {
611 if (!DeleteBreakpoint(NULL)) {
612 PrintF("deleting breakpoint failed\n");
613 }
614 } else if (strcmp(cmd, "flags") == 0) {
615 PrintF("No flags on MIPS !\n");
616 } else if (strcmp(cmd, "stop") == 0) {
617 int64_t value;
618 intptr_t stop_pc = sim_->get_pc() -
619 2 * Instruction::kInstrSize;
620 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
621 Instruction* msg_address =
622 reinterpret_cast<Instruction*>(stop_pc +
623 Instruction::kInstrSize);
624 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
625 // Remove the current stop.
626 if (sim_->IsStopInstruction(stop_instr)) {
627 stop_instr->SetInstructionBits(kNopInstr);
628 msg_address->SetInstructionBits(kNopInstr);
629 } else {
630 PrintF("Not at debugger stop.\n");
631 }
632 } else if (argc == 3) {
633 // Print information about all/the specified breakpoint(s).
634 if (strcmp(arg1, "info") == 0) {
635 if (strcmp(arg2, "all") == 0) {
636 PrintF("Stop information:\n");
637 for (uint32_t i = kMaxWatchpointCode + 1;
638 i <= kMaxStopCode;
639 i++) {
640 sim_->PrintStopInfo(i);
641 }
642 } else if (GetValue(arg2, &value)) {
643 sim_->PrintStopInfo(value);
644 } else {
645 PrintF("Unrecognized argument.\n");
646 }
647 } else if (strcmp(arg1, "enable") == 0) {
648 // Enable all/the specified breakpoint(s).
649 if (strcmp(arg2, "all") == 0) {
650 for (uint32_t i = kMaxWatchpointCode + 1;
651 i <= kMaxStopCode;
652 i++) {
653 sim_->EnableStop(i);
654 }
655 } else if (GetValue(arg2, &value)) {
656 sim_->EnableStop(value);
657 } else {
658 PrintF("Unrecognized argument.\n");
659 }
660 } else if (strcmp(arg1, "disable") == 0) {
661 // Disable all/the specified breakpoint(s).
662 if (strcmp(arg2, "all") == 0) {
663 for (uint32_t i = kMaxWatchpointCode + 1;
664 i <= kMaxStopCode;
665 i++) {
666 sim_->DisableStop(i);
667 }
668 } else if (GetValue(arg2, &value)) {
669 sim_->DisableStop(value);
670 } else {
671 PrintF("Unrecognized argument.\n");
672 }
673 }
674 } else {
675 PrintF("Wrong usage. Use help command for more information.\n");
676 }
677 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
678 // Print registers and disassemble.
679 PrintAllRegs();
680 PrintF("\n");
681
682 disasm::NameConverter converter;
683 disasm::Disassembler dasm(converter);
684 // Use a reasonably large buffer.
685 v8::internal::EmbeddedVector<char, 256> buffer;
686
687 byte* cur = NULL;
688 byte* end = NULL;
689
690 if (argc == 1) {
691 cur = reinterpret_cast<byte*>(sim_->get_pc());
692 end = cur + (10 * Instruction::kInstrSize);
693 } else if (argc == 2) {
694 int64_t value;
695 if (GetValue(arg1, &value)) {
696 cur = reinterpret_cast<byte*>(value);
697 // no length parameter passed, assume 10 instructions
698 end = cur + (10 * Instruction::kInstrSize);
699 }
700 } else {
701 int64_t value1;
702 int64_t value2;
703 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
704 cur = reinterpret_cast<byte*>(value1);
705 end = cur + (value2 * Instruction::kInstrSize);
706 }
707 }
708
709 while (cur < end) {
710 dasm.InstructionDecode(buffer, cur);
Ben Murdochc5610432016-08-08 18:44:38 +0100711 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
712 buffer.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 cur += Instruction::kInstrSize;
714 }
715 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
716 PrintF("cont\n");
717 PrintF(" continue execution (alias 'c')\n");
718 PrintF("stepi\n");
719 PrintF(" step one instruction (alias 'si')\n");
720 PrintF("print <register>\n");
721 PrintF(" print register content (alias 'p')\n");
722 PrintF(" use register name 'all' to print all registers\n");
723 PrintF("printobject <register>\n");
724 PrintF(" print an object from a register (alias 'po')\n");
725 PrintF("stack [<words>]\n");
726 PrintF(" dump stack content, default dump 10 words)\n");
727 PrintF("mem <address> [<words>]\n");
728 PrintF(" dump memory content, default dump 10 words)\n");
729 PrintF("flags\n");
730 PrintF(" print flags\n");
731 PrintF("disasm [<instructions>]\n");
732 PrintF("disasm [<address/register>]\n");
733 PrintF("disasm [[<address/register>] <instructions>]\n");
734 PrintF(" disassemble code, default is 10 instructions\n");
735 PrintF(" from pc (alias 'di')\n");
736 PrintF("gdb\n");
737 PrintF(" enter gdb\n");
738 PrintF("break <address>\n");
739 PrintF(" set a break point on the address\n");
740 PrintF("del\n");
741 PrintF(" delete the breakpoint\n");
742 PrintF("stop feature:\n");
743 PrintF(" Description:\n");
744 PrintF(" Stops are debug instructions inserted by\n");
745 PrintF(" the Assembler::stop() function.\n");
746 PrintF(" When hitting a stop, the Simulator will\n");
747 PrintF(" stop and and give control to the Debugger.\n");
748 PrintF(" All stop codes are watched:\n");
749 PrintF(" - They can be enabled / disabled: the Simulator\n");
750 PrintF(" will / won't stop when hitting them.\n");
751 PrintF(" - The Simulator keeps track of how many times they \n");
752 PrintF(" are met. (See the info command.) Going over a\n");
753 PrintF(" disabled stop still increases its counter. \n");
754 PrintF(" Commands:\n");
755 PrintF(" stop info all/<code> : print infos about number <code>\n");
756 PrintF(" or all stop(s).\n");
757 PrintF(" stop enable/disable all/<code> : enables / disables\n");
758 PrintF(" all or number <code> stop(s)\n");
759 PrintF(" stop unstop\n");
760 PrintF(" ignore the stop instruction at the current location\n");
761 PrintF(" from now on\n");
762 } else {
763 PrintF("Unknown command: %s\n", cmd);
764 }
765 }
766 }
767
768 // Add all the breakpoints back to stop execution and enter the debugger
769 // shell when hit.
770 RedoBreakpoints();
771
772#undef COMMAND_SIZE
773#undef ARG_SIZE
774
775#undef STR
776#undef XSTR
777}
778
779
780static bool ICacheMatch(void* one, void* two) {
781 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
782 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
783 return one == two;
784}
785
786
787static uint32_t ICacheHash(void* key) {
788 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
789}
790
791
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792static bool AllOnOnePage(uintptr_t start, size_t size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793 intptr_t start_page = (start & ~CachePage::kPageMask);
794 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
795 return start_page == end_page;
796}
797
798
799void Simulator::set_last_debugger_input(char* input) {
800 DeleteArray(last_debugger_input_);
801 last_debugger_input_ = input;
802}
803
Ben Murdoch61f157c2016-09-16 13:49:30 +0100804void Simulator::FlushICache(base::HashMap* i_cache, void* start_addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000805 size_t size) {
806 int64_t start = reinterpret_cast<int64_t>(start_addr);
807 int64_t intra_line = (start & CachePage::kLineMask);
808 start -= intra_line;
809 size += intra_line;
810 size = ((size - 1) | CachePage::kLineMask) + 1;
811 int offset = (start & CachePage::kPageMask);
812 while (!AllOnOnePage(start, size - 1)) {
813 int bytes_to_flush = CachePage::kPageSize - offset;
814 FlushOnePage(i_cache, start, bytes_to_flush);
815 start += bytes_to_flush;
816 size -= bytes_to_flush;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818 offset = 0;
819 }
820 if (size != 0) {
821 FlushOnePage(i_cache, start, size);
822 }
823}
824
Ben Murdoch61f157c2016-09-16 13:49:30 +0100825CachePage* Simulator::GetCachePage(base::HashMap* i_cache, void* page) {
826 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 if (entry->value == NULL) {
828 CachePage* new_page = new CachePage();
829 entry->value = new_page;
830 }
831 return reinterpret_cast<CachePage*>(entry->value);
832}
833
834
835// Flush from start up to and not including start + size.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100836void Simulator::FlushOnePage(base::HashMap* i_cache, intptr_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000837 size_t size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 DCHECK(size <= CachePage::kPageSize);
839 DCHECK(AllOnOnePage(start, size - 1));
840 DCHECK((start & CachePage::kLineMask) == 0);
841 DCHECK((size & CachePage::kLineMask) == 0);
842 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
843 int offset = (start & CachePage::kPageMask);
844 CachePage* cache_page = GetCachePage(i_cache, page);
845 char* valid_bytemap = cache_page->ValidityByte(offset);
846 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
847}
848
Ben Murdoch61f157c2016-09-16 13:49:30 +0100849void Simulator::CheckICache(base::HashMap* i_cache, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000850 int64_t address = reinterpret_cast<int64_t>(instr);
851 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
852 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
853 int offset = (address & CachePage::kPageMask);
854 CachePage* cache_page = GetCachePage(i_cache, page);
855 char* cache_valid_byte = cache_page->ValidityByte(offset);
856 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
857 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
858 if (cache_hit) {
859 // Check that the data in memory matches the contents of the I-cache.
860 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
861 cache_page->CachedData(offset),
862 Instruction::kInstrSize));
863 } else {
864 // Cache miss. Load memory into the cache.
865 memcpy(cached_line, line, CachePage::kLineLength);
866 *cache_valid_byte = CachePage::LINE_VALID;
867 }
868}
869
870
871void Simulator::Initialize(Isolate* isolate) {
872 if (isolate->simulator_initialized()) return;
873 isolate->set_simulator_initialized(true);
874 ::v8::internal::ExternalReference::set_redirector(isolate,
875 &RedirectExternalReference);
876}
877
878
879Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
880 i_cache_ = isolate_->simulator_i_cache();
881 if (i_cache_ == NULL) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100882 i_cache_ = new base::HashMap(&ICacheMatch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 isolate_->set_simulator_i_cache(i_cache_);
884 }
885 Initialize(isolate);
886 // Set up simulator support first. Some of this information is needed to
887 // setup the architecture state.
888 stack_size_ = FLAG_sim_stack_size * KB;
889 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
890 pc_modified_ = false;
891 icount_ = 0;
892 break_count_ = 0;
893 break_pc_ = NULL;
894 break_instr_ = 0;
895
896 // Set up architecture state.
897 // All registers are initialized to zero to start with.
898 for (int i = 0; i < kNumSimuRegisters; i++) {
899 registers_[i] = 0;
900 }
901 for (int i = 0; i < kNumFPURegisters; i++) {
902 FPUregisters_[i] = 0;
903 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904
905 if (kArchVariant == kMips64r6) {
906 FCSR_ = kFCSRNaN2008FlagMask;
907 } else {
908 FCSR_ = 0;
909 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000910
911 // The sp is initialized to point to the bottom (high address) of the
912 // allocated stack area. To be safe in potential stack underflows we leave
913 // some buffer below.
914 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64;
915 // The ra and pc are initialized to a known bad value that will cause an
916 // access violation if the simulator ever tries to execute it.
917 registers_[pc] = bad_ra;
918 registers_[ra] = bad_ra;
919 InitializeCoverage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000920
921 last_debugger_input_ = NULL;
922}
923
924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000925Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926
927
928// When the generated code calls an external reference we need to catch that in
929// the simulator. The external reference will be a function compiled for the
930// host architecture. We need to call that function instead of trying to
931// execute it with the simulator. We do that by redirecting the external
932// reference to a swi (software-interrupt) instruction that is handled by
933// the simulator. We write the original destination of the jump just at a known
934// offset from the swi instruction so the simulator knows what to call.
935class Redirection {
936 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000937 Redirection(Isolate* isolate, void* external_function,
938 ExternalReference::Type type)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000939 : external_function_(external_function),
940 swi_instruction_(rtCallRedirInstr),
941 type_(type),
942 next_(NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943 next_ = isolate->simulator_redirection();
944 Simulator::current(isolate)->
945 FlushICache(isolate->simulator_i_cache(),
946 reinterpret_cast<void*>(&swi_instruction_),
947 Instruction::kInstrSize);
948 isolate->set_simulator_redirection(this);
949 }
950
951 void* address_of_swi_instruction() {
952 return reinterpret_cast<void*>(&swi_instruction_);
953 }
954
955 void* external_function() { return external_function_; }
956 ExternalReference::Type type() { return type_; }
957
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000958 static Redirection* Get(Isolate* isolate, void* external_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 ExternalReference::Type type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960 Redirection* current = isolate->simulator_redirection();
961 for (; current != NULL; current = current->next_) {
962 if (current->external_function_ == external_function) return current;
963 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 return new Redirection(isolate, external_function, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000965 }
966
967 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
968 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
969 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000970 addr_of_swi - offsetof(Redirection, swi_instruction_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000971 return reinterpret_cast<Redirection*>(addr_of_redirection);
972 }
973
974 static void* ReverseRedirection(int64_t reg) {
975 Redirection* redirection = FromSwiInstruction(
976 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
977 return redirection->external_function();
978 }
979
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000980 static void DeleteChain(Redirection* redirection) {
981 while (redirection != nullptr) {
982 Redirection* next = redirection->next_;
983 delete redirection;
984 redirection = next;
985 }
986 }
987
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000988 private:
989 void* external_function_;
990 uint32_t swi_instruction_;
991 ExternalReference::Type type_;
992 Redirection* next_;
993};
994
995
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996// static
Ben Murdoch61f157c2016-09-16 13:49:30 +0100997void Simulator::TearDown(base::HashMap* i_cache, Redirection* first) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998 Redirection::DeleteChain(first);
999 if (i_cache != nullptr) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001000 for (base::HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001 entry = i_cache->Next(entry)) {
1002 delete static_cast<CachePage*>(entry->value);
1003 }
1004 delete i_cache;
1005 }
1006}
1007
1008
1009void* Simulator::RedirectExternalReference(Isolate* isolate,
1010 void* external_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001011 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001012 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 return redirection->address_of_swi_instruction();
1014}
1015
1016
1017// Get the active Simulator for the current thread.
1018Simulator* Simulator::current(Isolate* isolate) {
1019 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
1020 isolate->FindOrAllocatePerThreadDataForThisThread();
1021 DCHECK(isolate_data != NULL);
1022 DCHECK(isolate_data != NULL);
1023
1024 Simulator* sim = isolate_data->simulator();
1025 if (sim == NULL) {
1026 // TODO(146): delete the simulator object when a thread/isolate goes away.
1027 sim = new Simulator(isolate);
1028 isolate_data->set_simulator(sim);
1029 }
1030 return sim;
1031}
1032
1033
1034// Sets the register in the architecture state. It will also deal with updating
1035// Simulator internal state for special registers such as PC.
1036void Simulator::set_register(int reg, int64_t value) {
1037 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1038 if (reg == pc) {
1039 pc_modified_ = true;
1040 }
1041
1042 // Zero register always holds 0.
1043 registers_[reg] = (reg == 0) ? 0 : value;
1044}
1045
1046
1047void Simulator::set_dw_register(int reg, const int* dbl) {
1048 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1049 registers_[reg] = dbl[1];
1050 registers_[reg] = registers_[reg] << 32;
1051 registers_[reg] += dbl[0];
1052}
1053
1054
1055void Simulator::set_fpu_register(int fpureg, int64_t value) {
1056 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1057 FPUregisters_[fpureg] = value;
1058}
1059
1060
1061void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1062 // Set ONLY lower 32-bits, leaving upper bits untouched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001064 int32_t* pword;
1065 if (kArchEndian == kLittle) {
1066 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1067 } else {
1068 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]) + 1;
1069 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 *pword = value;
1071}
1072
1073
1074void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1075 // Set ONLY upper 32-bits, leaving lower bits untouched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001076 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 int32_t* phiword;
1078 if (kArchEndian == kLittle) {
1079 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1080 } else {
1081 phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1082 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001083 *phiword = value;
1084}
1085
1086
1087void Simulator::set_fpu_register_float(int fpureg, float value) {
1088 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1089 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
1090}
1091
1092
1093void Simulator::set_fpu_register_double(int fpureg, double value) {
1094 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1095 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1096}
1097
1098
1099// Get the register from the architecture state. This function does handle
1100// the special case of accessing the PC register.
1101int64_t Simulator::get_register(int reg) const {
1102 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1103 if (reg == 0)
1104 return 0;
1105 else
1106 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1107}
1108
1109
1110double Simulator::get_double_from_register_pair(int reg) {
1111 // TODO(plind): bad ABI stuff, refactor or remove.
1112 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1113
1114 double dm_val = 0.0;
1115 // Read the bits from the unsigned integer register_[] array
1116 // into the double precision floating point value and return it.
1117 char buffer[sizeof(registers_[0])];
1118 memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
1119 memcpy(&dm_val, buffer, sizeof(registers_[0]));
1120 return(dm_val);
1121}
1122
1123
1124int64_t Simulator::get_fpu_register(int fpureg) const {
1125 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1126 return FPUregisters_[fpureg];
1127}
1128
1129
1130int32_t Simulator::get_fpu_register_word(int fpureg) const {
1131 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1132 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1133}
1134
1135
1136int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1137 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1138 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1139}
1140
1141
1142int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1143 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1144 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
1145}
1146
1147
1148float Simulator::get_fpu_register_float(int fpureg) const {
1149 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1150 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
1151}
1152
1153
1154double Simulator::get_fpu_register_double(int fpureg) const {
1155 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1156 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1157}
1158
1159
1160// Runtime FP routines take up to two double arguments and zero
1161// or one integer arguments. All are constructed here,
1162// from a0-a3 or f12 and f13 (n64), or f14 (O32).
1163void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1164 if (!IsMipsSoftFloatABI) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001165 const int fparg2 = 13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 *x = get_fpu_register_double(12);
1167 *y = get_fpu_register_double(fparg2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001168 *z = static_cast<int32_t>(get_register(a2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001169 } else {
1170 // TODO(plind): bad ABI stuff, refactor or remove.
1171 // We use a char buffer to get around the strict-aliasing rules which
1172 // otherwise allow the compiler to optimize away the copy.
1173 char buffer[sizeof(*x)];
1174 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1175
1176 // Registers a0 and a1 -> x.
1177 reg_buffer[0] = get_register(a0);
1178 reg_buffer[1] = get_register(a1);
1179 memcpy(x, buffer, sizeof(buffer));
1180 // Registers a2 and a3 -> y.
1181 reg_buffer[0] = get_register(a2);
1182 reg_buffer[1] = get_register(a3);
1183 memcpy(y, buffer, sizeof(buffer));
1184 // Register 2 -> z.
1185 reg_buffer[0] = get_register(a2);
1186 memcpy(z, buffer, sizeof(*z));
1187 }
1188}
1189
1190
1191// The return value is either in v0/v1 or f0.
1192void Simulator::SetFpResult(const double& result) {
1193 if (!IsMipsSoftFloatABI) {
1194 set_fpu_register_double(0, result);
1195 } else {
1196 char buffer[2 * sizeof(registers_[0])];
1197 int64_t* reg_buffer = reinterpret_cast<int64_t*>(buffer);
1198 memcpy(buffer, &result, sizeof(buffer));
1199 // Copy result to v0 and v1.
1200 set_register(v0, reg_buffer[0]);
1201 set_register(v1, reg_buffer[1]);
1202 }
1203}
1204
1205
1206// Helper functions for setting and testing the FCSR register's bits.
1207void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1208 if (value) {
1209 FCSR_ |= (1 << cc);
1210 } else {
1211 FCSR_ &= ~(1 << cc);
1212 }
1213}
1214
1215
1216bool Simulator::test_fcsr_bit(uint32_t cc) {
1217 return FCSR_ & (1 << cc);
1218}
1219
1220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001221void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1222 FCSR_ |= mode & kFPURoundingModeMask;
1223}
1224
1225
1226unsigned int Simulator::get_fcsr_rounding_mode() {
1227 return FCSR_ & kFPURoundingModeMask;
1228}
1229
1230
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231// Sets the rounding error codes in FCSR based on the result of the rounding.
1232// Returns true if the operation was invalid.
1233bool Simulator::set_fcsr_round_error(double original, double rounded) {
1234 bool ret = false;
1235 double max_int32 = std::numeric_limits<int32_t>::max();
1236 double min_int32 = std::numeric_limits<int32_t>::min();
1237
1238 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1239 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1240 ret = true;
1241 }
1242
1243 if (original != rounded) {
1244 set_fcsr_bit(kFCSRInexactFlagBit, true);
1245 }
1246
1247 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1248 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1249 ret = true;
1250 }
1251
1252 if (rounded > max_int32 || rounded < min_int32) {
1253 set_fcsr_bit(kFCSROverflowFlagBit, true);
1254 // The reference is not really clear but it seems this is required:
1255 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1256 ret = true;
1257 }
1258
1259 return ret;
1260}
1261
1262
1263// Sets the rounding error codes in FCSR based on the result of the rounding.
1264// Returns true if the operation was invalid.
1265bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1266 bool ret = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1268 // loading the most accurate representation into max_int64, which is 2^63.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 double max_int64 = std::numeric_limits<int64_t>::max();
1270 double min_int64 = std::numeric_limits<int64_t>::min();
1271
1272 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1273 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1274 ret = true;
1275 }
1276
1277 if (original != rounded) {
1278 set_fcsr_bit(kFCSRInexactFlagBit, true);
1279 }
1280
1281 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1282 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1283 ret = true;
1284 }
1285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 if (rounded >= max_int64 || rounded < min_int64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287 set_fcsr_bit(kFCSROverflowFlagBit, true);
1288 // The reference is not really clear but it seems this is required:
1289 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1290 ret = true;
1291 }
1292
1293 return ret;
1294}
1295
1296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001297// Sets the rounding error codes in FCSR based on the result of the rounding.
1298// Returns true if the operation was invalid.
1299bool Simulator::set_fcsr_round_error(float original, float rounded) {
1300 bool ret = false;
1301 double max_int32 = std::numeric_limits<int32_t>::max();
1302 double min_int32 = std::numeric_limits<int32_t>::min();
1303
1304 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1305 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1306 ret = true;
1307 }
1308
1309 if (original != rounded) {
1310 set_fcsr_bit(kFCSRInexactFlagBit, true);
1311 }
1312
1313 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1314 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1315 ret = true;
1316 }
1317
1318 if (rounded > max_int32 || rounded < min_int32) {
1319 set_fcsr_bit(kFCSROverflowFlagBit, true);
1320 // The reference is not really clear but it seems this is required:
1321 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1322 ret = true;
1323 }
1324
1325 return ret;
1326}
1327
1328void Simulator::set_fpu_register_word_invalid_result(float original,
1329 float rounded) {
1330 if (FCSR_ & kFCSRNaN2008FlagMask) {
1331 double max_int32 = std::numeric_limits<int32_t>::max();
1332 double min_int32 = std::numeric_limits<int32_t>::min();
1333 if (std::isnan(original)) {
1334 set_fpu_register_word(fd_reg(), 0);
1335 } else if (rounded > max_int32) {
1336 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1337 } else if (rounded < min_int32) {
1338 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1339 } else {
1340 UNREACHABLE();
1341 }
1342 } else {
1343 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1344 }
1345}
1346
1347
1348void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1349 if (FCSR_ & kFCSRNaN2008FlagMask) {
1350 double max_int32 = std::numeric_limits<int32_t>::max();
1351 double min_int32 = std::numeric_limits<int32_t>::min();
1352 if (std::isnan(original)) {
1353 set_fpu_register(fd_reg(), 0);
1354 } else if (rounded > max_int32) {
1355 set_fpu_register(fd_reg(), kFPUInvalidResult);
1356 } else if (rounded < min_int32) {
1357 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1358 } else {
1359 UNREACHABLE();
1360 }
1361 } else {
1362 set_fpu_register(fd_reg(), kFPUInvalidResult);
1363 }
1364}
1365
1366
1367void Simulator::set_fpu_register_invalid_result64(float original,
1368 float rounded) {
1369 if (FCSR_ & kFCSRNaN2008FlagMask) {
1370 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1371 // loading the most accurate representation into max_int64, which is 2^63.
1372 double max_int64 = std::numeric_limits<int64_t>::max();
1373 double min_int64 = std::numeric_limits<int64_t>::min();
1374 if (std::isnan(original)) {
1375 set_fpu_register(fd_reg(), 0);
1376 } else if (rounded >= max_int64) {
1377 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1378 } else if (rounded < min_int64) {
1379 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1380 } else {
1381 UNREACHABLE();
1382 }
1383 } else {
1384 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1385 }
1386}
1387
1388
1389void Simulator::set_fpu_register_word_invalid_result(double original,
1390 double rounded) {
1391 if (FCSR_ & kFCSRNaN2008FlagMask) {
1392 double max_int32 = std::numeric_limits<int32_t>::max();
1393 double min_int32 = std::numeric_limits<int32_t>::min();
1394 if (std::isnan(original)) {
1395 set_fpu_register_word(fd_reg(), 0);
1396 } else if (rounded > max_int32) {
1397 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1398 } else if (rounded < min_int32) {
1399 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1400 } else {
1401 UNREACHABLE();
1402 }
1403 } else {
1404 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1405 }
1406}
1407
1408
1409void Simulator::set_fpu_register_invalid_result(double original,
1410 double rounded) {
1411 if (FCSR_ & kFCSRNaN2008FlagMask) {
1412 double max_int32 = std::numeric_limits<int32_t>::max();
1413 double min_int32 = std::numeric_limits<int32_t>::min();
1414 if (std::isnan(original)) {
1415 set_fpu_register(fd_reg(), 0);
1416 } else if (rounded > max_int32) {
1417 set_fpu_register(fd_reg(), kFPUInvalidResult);
1418 } else if (rounded < min_int32) {
1419 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1420 } else {
1421 UNREACHABLE();
1422 }
1423 } else {
1424 set_fpu_register(fd_reg(), kFPUInvalidResult);
1425 }
1426}
1427
1428
1429void Simulator::set_fpu_register_invalid_result64(double original,
1430 double rounded) {
1431 if (FCSR_ & kFCSRNaN2008FlagMask) {
1432 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1433 // loading the most accurate representation into max_int64, which is 2^63.
1434 double max_int64 = std::numeric_limits<int64_t>::max();
1435 double min_int64 = std::numeric_limits<int64_t>::min();
1436 if (std::isnan(original)) {
1437 set_fpu_register(fd_reg(), 0);
1438 } else if (rounded >= max_int64) {
1439 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1440 } else if (rounded < min_int64) {
1441 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1442 } else {
1443 UNREACHABLE();
1444 }
1445 } else {
1446 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1447 }
1448}
1449
1450
1451// Sets the rounding error codes in FCSR based on the result of the rounding.
1452// Returns true if the operation was invalid.
1453bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1454 bool ret = false;
1455 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1456 // loading the most accurate representation into max_int64, which is 2^63.
1457 double max_int64 = std::numeric_limits<int64_t>::max();
1458 double min_int64 = std::numeric_limits<int64_t>::min();
1459
1460 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1461 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1462 ret = true;
1463 }
1464
1465 if (original != rounded) {
1466 set_fcsr_bit(kFCSRInexactFlagBit, true);
1467 }
1468
1469 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1470 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1471 ret = true;
1472 }
1473
1474 if (rounded >= max_int64 || rounded < min_int64) {
1475 set_fcsr_bit(kFCSROverflowFlagBit, true);
1476 // The reference is not really clear but it seems this is required:
1477 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1478 ret = true;
1479 }
1480
1481 return ret;
1482}
1483
1484
1485// For cvt instructions only
1486void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1487 int32_t& rounded_int, double fs) {
1488 // 0 RN (round to nearest): Round a result to the nearest
1489 // representable value; if the result is exactly halfway between
1490 // two representable values, round to zero. Behave like round_w_d.
1491
1492 // 1 RZ (round toward zero): Round a result to the closest
1493 // representable value whose absolute value is less than or
1494 // equal to the infinitely accurate result. Behave like trunc_w_d.
1495
1496 // 2 RP (round up, or toward +infinity): Round a result to the
1497 // next representable value up. Behave like ceil_w_d.
1498
1499 // 3 RN (round down, or toward −infinity): Round a result to
1500 // the next representable value down. Behave like floor_w_d.
1501 switch (FCSR_ & 3) {
1502 case kRoundToNearest:
1503 rounded = std::floor(fs + 0.5);
1504 rounded_int = static_cast<int32_t>(rounded);
1505 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1506 // If the number is halfway between two integers,
1507 // round to the even one.
1508 rounded_int--;
1509 }
1510 break;
1511 case kRoundToZero:
1512 rounded = trunc(fs);
1513 rounded_int = static_cast<int32_t>(rounded);
1514 break;
1515 case kRoundToPlusInf:
1516 rounded = std::ceil(fs);
1517 rounded_int = static_cast<int32_t>(rounded);
1518 break;
1519 case kRoundToMinusInf:
1520 rounded = std::floor(fs);
1521 rounded_int = static_cast<int32_t>(rounded);
1522 break;
1523 }
1524}
1525
1526
1527void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1528 int64_t& rounded_int, double fs) {
1529 // 0 RN (round to nearest): Round a result to the nearest
1530 // representable value; if the result is exactly halfway between
1531 // two representable values, round to zero. Behave like round_w_d.
1532
1533 // 1 RZ (round toward zero): Round a result to the closest
1534 // representable value whose absolute value is less than or.
1535 // equal to the infinitely accurate result. Behave like trunc_w_d.
1536
1537 // 2 RP (round up, or toward +infinity): Round a result to the
1538 // next representable value up. Behave like ceil_w_d.
1539
1540 // 3 RN (round down, or toward −infinity): Round a result to
1541 // the next representable value down. Behave like floor_w_d.
1542 switch (FCSR_ & 3) {
1543 case kRoundToNearest:
1544 rounded = std::floor(fs + 0.5);
1545 rounded_int = static_cast<int64_t>(rounded);
1546 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1547 // If the number is halfway between two integers,
1548 // round to the even one.
1549 rounded_int--;
1550 }
1551 break;
1552 case kRoundToZero:
1553 rounded = trunc(fs);
1554 rounded_int = static_cast<int64_t>(rounded);
1555 break;
1556 case kRoundToPlusInf:
1557 rounded = std::ceil(fs);
1558 rounded_int = static_cast<int64_t>(rounded);
1559 break;
1560 case kRoundToMinusInf:
1561 rounded = std::floor(fs);
1562 rounded_int = static_cast<int64_t>(rounded);
1563 break;
1564 }
1565}
1566
1567
1568// for cvt instructions only
1569void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1570 int32_t& rounded_int, float fs) {
1571 // 0 RN (round to nearest): Round a result to the nearest
1572 // representable value; if the result is exactly halfway between
1573 // two representable values, round to zero. Behave like round_w_d.
1574
1575 // 1 RZ (round toward zero): Round a result to the closest
1576 // representable value whose absolute value is less than or
1577 // equal to the infinitely accurate result. Behave like trunc_w_d.
1578
1579 // 2 RP (round up, or toward +infinity): Round a result to the
1580 // next representable value up. Behave like ceil_w_d.
1581
1582 // 3 RN (round down, or toward −infinity): Round a result to
1583 // the next representable value down. Behave like floor_w_d.
1584 switch (FCSR_ & 3) {
1585 case kRoundToNearest:
1586 rounded = std::floor(fs + 0.5);
1587 rounded_int = static_cast<int32_t>(rounded);
1588 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1589 // If the number is halfway between two integers,
1590 // round to the even one.
1591 rounded_int--;
1592 }
1593 break;
1594 case kRoundToZero:
1595 rounded = trunc(fs);
1596 rounded_int = static_cast<int32_t>(rounded);
1597 break;
1598 case kRoundToPlusInf:
1599 rounded = std::ceil(fs);
1600 rounded_int = static_cast<int32_t>(rounded);
1601 break;
1602 case kRoundToMinusInf:
1603 rounded = std::floor(fs);
1604 rounded_int = static_cast<int32_t>(rounded);
1605 break;
1606 }
1607}
1608
1609
1610void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1611 int64_t& rounded_int, float fs) {
1612 // 0 RN (round to nearest): Round a result to the nearest
1613 // representable value; if the result is exactly halfway between
1614 // two representable values, round to zero. Behave like round_w_d.
1615
1616 // 1 RZ (round toward zero): Round a result to the closest
1617 // representable value whose absolute value is less than or.
1618 // equal to the infinitely accurate result. Behave like trunc_w_d.
1619
1620 // 2 RP (round up, or toward +infinity): Round a result to the
1621 // next representable value up. Behave like ceil_w_d.
1622
1623 // 3 RN (round down, or toward −infinity): Round a result to
1624 // the next representable value down. Behave like floor_w_d.
1625 switch (FCSR_ & 3) {
1626 case kRoundToNearest:
1627 rounded = std::floor(fs + 0.5);
1628 rounded_int = static_cast<int64_t>(rounded);
1629 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1630 // If the number is halfway between two integers,
1631 // round to the even one.
1632 rounded_int--;
1633 }
1634 break;
1635 case kRoundToZero:
1636 rounded = trunc(fs);
1637 rounded_int = static_cast<int64_t>(rounded);
1638 break;
1639 case kRoundToPlusInf:
1640 rounded = std::ceil(fs);
1641 rounded_int = static_cast<int64_t>(rounded);
1642 break;
1643 case kRoundToMinusInf:
1644 rounded = std::floor(fs);
1645 rounded_int = static_cast<int64_t>(rounded);
1646 break;
1647 }
1648}
1649
1650
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651// Raw access to the PC register.
1652void Simulator::set_pc(int64_t value) {
1653 pc_modified_ = true;
1654 registers_[pc] = value;
1655}
1656
1657
1658bool Simulator::has_bad_pc() const {
1659 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1660}
1661
1662
1663// Raw access to the PC register without the special adjustment when reading.
1664int64_t Simulator::get_pc() const {
1665 return registers_[pc];
1666}
1667
1668
1669// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1670// interrupt is caused. On others it does a funky rotation thing. For now we
1671// simply disallow unaligned reads, but at some point we may want to move to
1672// emulating the rotate behaviour. Note that simulator runs have the runtime
1673// system running directly on the host system and only generated code is
1674// executed in the simulator. Since the host is typically IA32 we will not
1675// get the correct MIPS-like behaviour on unaligned accesses.
1676
1677// TODO(plind): refactor this messy debug code when we do unaligned access.
1678void Simulator::DieOrDebug() {
1679 if (1) { // Flag for this was removed.
1680 MipsDebugger dbg(this);
1681 dbg.Debug();
1682 } else {
1683 base::OS::Abort();
1684 }
1685}
1686
1687
1688void Simulator::TraceRegWr(int64_t value) {
1689 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01001690 SNPrintF(trace_buf_, "%016" PRIx64 " ", value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691 }
1692}
1693
1694
1695// TODO(plind): consider making icount_ printing a flag option.
1696void Simulator::TraceMemRd(int64_t addr, int64_t value) {
1697 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01001698 SNPrintF(trace_buf_,
1699 "%016" PRIx64 " <-- [%016" PRIx64 " ] (%" PRId64 " )", value,
1700 addr, icount_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 }
1702}
1703
1704
1705void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
1706 if (::v8::internal::FLAG_trace_sim) {
1707 switch (t) {
1708 case BYTE:
Ben Murdochc5610432016-08-08 18:44:38 +01001709 SNPrintF(trace_buf_, " %02x --> [%016" PRIx64 " ]",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 static_cast<int8_t>(value), addr);
1711 break;
1712 case HALF:
Ben Murdochc5610432016-08-08 18:44:38 +01001713 SNPrintF(trace_buf_, " %04x --> [%016" PRIx64 " ]",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 static_cast<int16_t>(value), addr);
1715 break;
1716 case WORD:
Ben Murdochc5610432016-08-08 18:44:38 +01001717 SNPrintF(trace_buf_, " %08x --> [%016" PRIx64 " ]",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 static_cast<int32_t>(value), addr);
1719 break;
1720 case DWORD:
Ben Murdochc5610432016-08-08 18:44:38 +01001721 SNPrintF(trace_buf_,
1722 "%016" PRIx64 " --> [%016" PRIx64 " ] (%" PRId64 " )",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001723 value, addr, icount_);
1724 break;
1725 }
1726 }
1727}
1728
1729
1730// TODO(plind): sign-extend and zero-extend not implmented properly
1731// on all the ReadXX functions, I don't think re-interpret cast does it.
1732int32_t Simulator::ReadW(int64_t addr, Instruction* instr) {
1733 if (addr >=0 && addr < 0x400) {
1734 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001735 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1736 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 addr, reinterpret_cast<intptr_t>(instr));
1738 DieOrDebug();
1739 }
Ben Murdochc5610432016-08-08 18:44:38 +01001740 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001741 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1742 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1743 return *ptr;
1744 }
Ben Murdochc5610432016-08-08 18:44:38 +01001745 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001746 reinterpret_cast<intptr_t>(instr));
1747 DieOrDebug();
1748 return 0;
1749}
1750
1751
1752uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) {
1753 if (addr >=0 && addr < 0x400) {
1754 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001755 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1756 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001757 addr, reinterpret_cast<intptr_t>(instr));
1758 DieOrDebug();
1759 }
Ben Murdochc5610432016-08-08 18:44:38 +01001760 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001761 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1762 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1763 return *ptr;
1764 }
Ben Murdochc5610432016-08-08 18:44:38 +01001765 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766 reinterpret_cast<intptr_t>(instr));
1767 DieOrDebug();
1768 return 0;
1769}
1770
1771
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 if (addr >= 0 && addr < 0x400) {
1774 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001775 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1776 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777 addr, reinterpret_cast<intptr_t>(instr));
1778 DieOrDebug();
1779 }
Ben Murdochc5610432016-08-08 18:44:38 +01001780 if ((addr & 0x3) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001781 TraceMemWr(addr, value, WORD);
1782 int* ptr = reinterpret_cast<int*>(addr);
1783 *ptr = value;
1784 return;
1785 }
Ben Murdochc5610432016-08-08 18:44:38 +01001786 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001787 reinterpret_cast<intptr_t>(instr));
1788 DieOrDebug();
1789}
1790
1791
1792int64_t Simulator::Read2W(int64_t addr, Instruction* instr) {
1793 if (addr >=0 && addr < 0x400) {
1794 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001795 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1796 " \n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 addr, reinterpret_cast<intptr_t>(instr));
1798 DieOrDebug();
1799 }
Ben Murdochc5610432016-08-08 18:44:38 +01001800 if ((addr & kPointerAlignmentMask) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1802 TraceMemRd(addr, *ptr);
1803 return *ptr;
1804 }
Ben Murdochc5610432016-08-08 18:44:38 +01001805 PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001806 reinterpret_cast<intptr_t>(instr));
1807 DieOrDebug();
1808 return 0;
1809}
1810
1811
1812void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) {
1813 if (addr >= 0 && addr < 0x400) {
1814 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001815 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1816 "\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001817 addr, reinterpret_cast<intptr_t>(instr));
1818 DieOrDebug();
1819 }
Ben Murdochc5610432016-08-08 18:44:38 +01001820 if ((addr & kPointerAlignmentMask) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001821 TraceMemWr(addr, value, DWORD);
1822 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1823 *ptr = value;
1824 return;
1825 }
Ben Murdochc5610432016-08-08 18:44:38 +01001826 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001827 reinterpret_cast<intptr_t>(instr));
1828 DieOrDebug();
1829}
1830
1831
1832double Simulator::ReadD(int64_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001833 if ((addr & kDoubleAlignmentMask) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001834 double* ptr = reinterpret_cast<double*>(addr);
1835 return *ptr;
1836 }
Ben Murdochc5610432016-08-08 18:44:38 +01001837 PrintF("Unaligned (double) read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
1838 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839 base::OS::Abort();
1840 return 0;
1841}
1842
1843
1844void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001845 if ((addr & kDoubleAlignmentMask) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001846 double* ptr = reinterpret_cast<double*>(addr);
1847 *ptr = value;
1848 return;
1849 }
Ben Murdochc5610432016-08-08 18:44:38 +01001850 PrintF("Unaligned (double) write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
1851 "\n",
1852 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001853 DieOrDebug();
1854}
1855
1856
1857uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001858 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001859 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1860 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1861 return *ptr;
1862 }
Ben Murdochc5610432016-08-08 18:44:38 +01001863 PrintF("Unaligned unsigned halfword read at 0x%08" PRIx64
1864 " , pc=0x%08" V8PRIxPTR "\n",
1865 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001866 DieOrDebug();
1867 return 0;
1868}
1869
1870
1871int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001872 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001873 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1874 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1875 return *ptr;
1876 }
Ben Murdochc5610432016-08-08 18:44:38 +01001877 PrintF("Unaligned signed halfword read at 0x%08" PRIx64
1878 " , pc=0x%08" V8PRIxPTR "\n",
1879 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001880 DieOrDebug();
1881 return 0;
1882}
1883
1884
1885void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001886 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001887 TraceMemWr(addr, value, HALF);
1888 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1889 *ptr = value;
1890 return;
1891 }
Ben Murdochc5610432016-08-08 18:44:38 +01001892 PrintF("Unaligned unsigned halfword write at 0x%08" PRIx64
1893 " , pc=0x%08" V8PRIxPTR "\n",
1894 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895 DieOrDebug();
1896}
1897
1898
1899void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001900 if ((addr & 1) == 0 || kArchVariant == kMips64r6) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001901 TraceMemWr(addr, value, HALF);
1902 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1903 *ptr = value;
1904 return;
1905 }
Ben Murdochc5610432016-08-08 18:44:38 +01001906 PrintF("Unaligned halfword write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR
1907 "\n",
1908 addr, reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 DieOrDebug();
1910}
1911
1912
1913uint32_t Simulator::ReadBU(int64_t addr) {
1914 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1915 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1916 return *ptr & 0xff;
1917}
1918
1919
1920int32_t Simulator::ReadB(int64_t addr) {
1921 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1922 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1923 return *ptr;
1924}
1925
1926
1927void Simulator::WriteB(int64_t addr, uint8_t value) {
1928 TraceMemWr(addr, value, BYTE);
1929 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1930 *ptr = value;
1931}
1932
1933
1934void Simulator::WriteB(int64_t addr, int8_t value) {
1935 TraceMemWr(addr, value, BYTE);
1936 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1937 *ptr = value;
1938}
1939
1940
1941// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001942uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1943 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1944 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1945 if (GetCurrentStackPosition() < c_limit) {
1946 return reinterpret_cast<uintptr_t>(get_sp());
1947 }
1948
1949 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1950 // to prevent overrunning the stack when pushing values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951 return reinterpret_cast<uintptr_t>(stack_) + 1024;
1952}
1953
1954
1955// Unsupported instructions use Format to print an error and stop execution.
1956void Simulator::Format(Instruction* instr, const char* format) {
Ben Murdochc5610432016-08-08 18:44:38 +01001957 PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001958 reinterpret_cast<intptr_t>(instr), format);
1959 UNIMPLEMENTED_MIPS();
1960}
1961
1962
1963// Calls into the V8 runtime are based on this very simple interface.
1964// Note: To be able to return two values from some calls the code in runtime.cc
1965// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1966// 64-bit value. With the code below we assume that all runtime calls return
1967// 64 bits of result. If they don't, the v1 result register contains a bogus
1968// value, which is fine because it is caller-saved.
1969
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001970typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
1971 int64_t arg1,
1972 int64_t arg2,
1973 int64_t arg3,
1974 int64_t arg4,
1975 int64_t arg5);
1976
Ben Murdoch097c5b22016-05-18 11:27:45 +01001977typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int64_t arg0, int64_t arg1,
1978 int64_t arg2, int64_t arg3,
1979 int64_t arg4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001980
1981// These prototypes handle the four types of FP calls.
1982typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1983typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1984typedef double (*SimulatorRuntimeFPCall)(double darg0);
1985typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1986
1987// This signature supports direct call in to API function native callback
1988// (refer to InvocationCallback in v8.h).
1989typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
1990typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1);
1991
1992// This signature supports direct call to accessor getter callback.
1993typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
1994typedef void (*SimulatorRuntimeProfilingGetterCall)(
1995 int64_t arg0, int64_t arg1, void* arg2);
1996
1997// Software interrupt instructions are used by the simulator to call into the
1998// C-based V8 runtime. They are also used for debugging with simulator.
1999void Simulator::SoftwareInterrupt(Instruction* instr) {
2000 // There are several instructions that could get us here,
2001 // the break_ instruction, or several variants of traps. All
2002 // Are "SPECIAL" class opcode, and are distinuished by function.
2003 int32_t func = instr->FunctionFieldRaw();
2004 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
2005 // We first check if we met a call_rt_redirected.
2006 if (instr->InstructionBits() == rtCallRedirInstr) {
2007 Redirection* redirection = Redirection::FromSwiInstruction(instr);
2008 int64_t arg0 = get_register(a0);
2009 int64_t arg1 = get_register(a1);
2010 int64_t arg2 = get_register(a2);
2011 int64_t arg3 = get_register(a3);
2012 int64_t arg4, arg5;
2013
Ben Murdoch097c5b22016-05-18 11:27:45 +01002014 arg4 = get_register(a4); // Abi n64 register a4.
2015 arg5 = get_register(a5); // Abi n64 register a5.
2016
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002017 bool fp_call =
2018 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2019 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2020 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2021 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2022
2023 if (!IsMipsSoftFloatABI) {
2024 // With the hard floating point calling convention, double
2025 // arguments are passed in FPU registers. Fetch the arguments
2026 // from there and call the builtin using soft floating point
2027 // convention.
2028 switch (redirection->type()) {
2029 case ExternalReference::BUILTIN_FP_FP_CALL:
2030 case ExternalReference::BUILTIN_COMPARE_CALL:
2031 arg0 = get_fpu_register(f12);
2032 arg1 = get_fpu_register(f13);
2033 arg2 = get_fpu_register(f14);
2034 arg3 = get_fpu_register(f15);
2035 break;
2036 case ExternalReference::BUILTIN_FP_CALL:
2037 arg0 = get_fpu_register(f12);
2038 arg1 = get_fpu_register(f13);
2039 break;
2040 case ExternalReference::BUILTIN_FP_INT_CALL:
2041 arg0 = get_fpu_register(f12);
2042 arg1 = get_fpu_register(f13);
2043 arg2 = get_register(a2);
2044 break;
2045 default:
2046 break;
2047 }
2048 }
2049
2050 // This is dodgy but it works because the C entry stubs are never moved.
2051 // See comment in codegen-arm.cc and bug 1242173.
2052 int64_t saved_ra = get_register(ra);
2053
2054 intptr_t external =
2055 reinterpret_cast<intptr_t>(redirection->external_function());
2056
2057 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2058 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2059 // simulator. Soft-float has additional abstraction of ExternalReference,
2060 // to support serialization.
2061 if (fp_call) {
2062 double dval0, dval1; // one or two double parameters
2063 int32_t ival; // zero or one integer parameters
2064 int64_t iresult = 0; // integer return value
2065 double dresult = 0; // double return value
2066 GetFpArgs(&dval0, &dval1, &ival);
2067 SimulatorRuntimeCall generic_target =
2068 reinterpret_cast<SimulatorRuntimeCall>(external);
2069 if (::v8::internal::FLAG_trace_sim) {
2070 switch (redirection->type()) {
2071 case ExternalReference::BUILTIN_FP_FP_CALL:
2072 case ExternalReference::BUILTIN_COMPARE_CALL:
2073 PrintF("Call to host function at %p with args %f, %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002074 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2075 dval1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002076 break;
2077 case ExternalReference::BUILTIN_FP_CALL:
2078 PrintF("Call to host function at %p with arg %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002079 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002080 break;
2081 case ExternalReference::BUILTIN_FP_INT_CALL:
2082 PrintF("Call to host function at %p with args %f, %d",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002083 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2084 ival);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002085 break;
2086 default:
2087 UNREACHABLE();
2088 break;
2089 }
2090 }
2091 switch (redirection->type()) {
2092 case ExternalReference::BUILTIN_COMPARE_CALL: {
2093 SimulatorRuntimeCompareCall target =
2094 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2095 iresult = target(dval0, dval1);
2096 set_register(v0, static_cast<int64_t>(iresult));
2097 // set_register(v1, static_cast<int64_t>(iresult >> 32));
2098 break;
2099 }
2100 case ExternalReference::BUILTIN_FP_FP_CALL: {
2101 SimulatorRuntimeFPFPCall target =
2102 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2103 dresult = target(dval0, dval1);
2104 SetFpResult(dresult);
2105 break;
2106 }
2107 case ExternalReference::BUILTIN_FP_CALL: {
2108 SimulatorRuntimeFPCall target =
2109 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2110 dresult = target(dval0);
2111 SetFpResult(dresult);
2112 break;
2113 }
2114 case ExternalReference::BUILTIN_FP_INT_CALL: {
2115 SimulatorRuntimeFPIntCall target =
2116 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2117 dresult = target(dval0, ival);
2118 SetFpResult(dresult);
2119 break;
2120 }
2121 default:
2122 UNREACHABLE();
2123 break;
2124 }
2125 if (::v8::internal::FLAG_trace_sim) {
2126 switch (redirection->type()) {
2127 case ExternalReference::BUILTIN_COMPARE_CALL:
2128 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2129 break;
2130 case ExternalReference::BUILTIN_FP_FP_CALL:
2131 case ExternalReference::BUILTIN_FP_CALL:
2132 case ExternalReference::BUILTIN_FP_INT_CALL:
2133 PrintF("Returned %f\n", dresult);
2134 break;
2135 default:
2136 UNREACHABLE();
2137 break;
2138 }
2139 }
2140 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2141 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01002142 PrintF("Call to host function at %p args %08" PRIx64 " \n",
2143 reinterpret_cast<void*>(external), arg0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002144 }
2145 SimulatorRuntimeDirectApiCall target =
2146 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2147 target(arg0);
2148 } else if (
2149 redirection->type() == ExternalReference::PROFILING_API_CALL) {
2150 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01002151 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2152 " \n",
2153 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002154 }
2155 SimulatorRuntimeProfilingApiCall target =
2156 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2157 target(arg0, Redirection::ReverseRedirection(arg1));
2158 } else if (
2159 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2160 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01002161 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2162 " \n",
2163 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002164 }
2165 SimulatorRuntimeDirectGetterCall target =
2166 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2167 target(arg0, arg1);
2168 } else if (
2169 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2170 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01002171 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2172 " %08" PRIx64 " \n",
2173 reinterpret_cast<void*>(external), arg0, arg1, arg2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002174 }
2175 SimulatorRuntimeProfilingGetterCall target =
2176 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2177 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002178 } else if (redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE) {
2179 // builtin call returning ObjectTriple.
2180 SimulatorRuntimeTripleCall target =
2181 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
2182 if (::v8::internal::FLAG_trace_sim) {
2183 PrintF(
2184 "Call to host triple returning runtime function %p "
2185 "args %016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", %016" PRIx64
2186 ", %016" PRIx64 "\n",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002187 static_cast<void*>(FUNCTION_ADDR(target)), arg1, arg2, arg3, arg4,
2188 arg5);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002189 }
2190 // arg0 is a hidden argument pointing to the return location, so don't
2191 // pass it to the target function.
2192 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
2193 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002194 PrintF("Returned { %p, %p, %p }\n", static_cast<void*>(result.x),
2195 static_cast<void*>(result.y), static_cast<void*>(result.z));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002196 }
2197 // Return is passed back in address pointed to by hidden first argument.
2198 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
2199 *sim_result = result;
2200 set_register(v0, arg0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002201 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002202 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2203 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002204 SimulatorRuntimeCall target =
2205 reinterpret_cast<SimulatorRuntimeCall>(external);
2206 if (::v8::internal::FLAG_trace_sim) {
2207 PrintF(
2208 "Call to host function at %p "
Ben Murdochc5610432016-08-08 18:44:38 +01002209 "args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2210 " , %08" PRIx64 " , %08" PRIx64 " \n",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002211 static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
2212 arg4, arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002213 }
2214 // int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2215 // set_register(v0, static_cast<int32_t>(result));
2216 // set_register(v1, static_cast<int32_t>(result >> 32));
2217 ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2218 set_register(v0, (int64_t)(result.x));
2219 set_register(v1, (int64_t)(result.y));
2220 }
2221 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01002222 PrintF("Returned %08" PRIx64 " : %08" PRIx64 " \n", get_register(v1),
2223 get_register(v0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002224 }
2225 set_register(ra, saved_ra);
2226 set_pc(get_register(ra));
2227
2228 } else if (func == BREAK && code <= kMaxStopCode) {
2229 if (IsWatchpoint(code)) {
2230 PrintWatchpoint(code);
2231 } else {
2232 IncreaseStopCounter(code);
2233 HandleStop(code, instr);
2234 }
2235 } else {
2236 // All remaining break_ codes, and all traps are handled here.
2237 MipsDebugger dbg(this);
2238 dbg.Debug();
2239 }
2240}
2241
2242
2243// Stop helper functions.
2244bool Simulator::IsWatchpoint(uint64_t code) {
2245 return (code <= kMaxWatchpointCode);
2246}
2247
2248
2249void Simulator::PrintWatchpoint(uint64_t code) {
2250 MipsDebugger dbg(this);
2251 ++break_count_;
Ben Murdochc5610432016-08-08 18:44:38 +01002252 PrintF("\n---- break %" PRId64 " marker: %3d (instr count: %8" PRId64
2253 " ) ----------"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254 "----------------------------------",
2255 code, break_count_, icount_);
2256 dbg.PrintAllRegs(); // Print registers and continue running.
2257}
2258
2259
2260void Simulator::HandleStop(uint64_t code, Instruction* instr) {
2261 // Stop if it is enabled, otherwise go on jumping over the stop
2262 // and the message address.
2263 if (IsEnabledStop(code)) {
2264 MipsDebugger dbg(this);
2265 dbg.Stop(instr);
2266 } else {
2267 set_pc(get_pc() + 2 * Instruction::kInstrSize);
2268 }
2269}
2270
2271
2272bool Simulator::IsStopInstruction(Instruction* instr) {
2273 int32_t func = instr->FunctionFieldRaw();
2274 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2275 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2276}
2277
2278
2279bool Simulator::IsEnabledStop(uint64_t code) {
2280 DCHECK(code <= kMaxStopCode);
2281 DCHECK(code > kMaxWatchpointCode);
2282 return !(watched_stops_[code].count & kStopDisabledBit);
2283}
2284
2285
2286void Simulator::EnableStop(uint64_t code) {
2287 if (!IsEnabledStop(code)) {
2288 watched_stops_[code].count &= ~kStopDisabledBit;
2289 }
2290}
2291
2292
2293void Simulator::DisableStop(uint64_t code) {
2294 if (IsEnabledStop(code)) {
2295 watched_stops_[code].count |= kStopDisabledBit;
2296 }
2297}
2298
2299
2300void Simulator::IncreaseStopCounter(uint64_t code) {
2301 DCHECK(code <= kMaxStopCode);
2302 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Ben Murdochc5610432016-08-08 18:44:38 +01002303 PrintF("Stop counter for code %" PRId64
2304 " has overflowed.\n"
2305 "Enabling this code and reseting the counter to 0.\n",
2306 code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307 watched_stops_[code].count = 0;
2308 EnableStop(code);
2309 } else {
2310 watched_stops_[code].count++;
2311 }
2312}
2313
2314
2315// Print a stop status.
2316void Simulator::PrintStopInfo(uint64_t code) {
2317 if (code <= kMaxWatchpointCode) {
2318 PrintF("That is a watchpoint, not a stop.\n");
2319 return;
2320 } else if (code > kMaxStopCode) {
2321 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2322 return;
2323 }
2324 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2325 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2326 // Don't print the state of unused breakpoints.
2327 if (count != 0) {
2328 if (watched_stops_[code].desc) {
Ben Murdochc5610432016-08-08 18:44:38 +01002329 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002330 code, code, state, count, watched_stops_[code].desc);
2331 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002332 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i\n", code,
2333 code, state, count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002334 }
2335 }
2336}
2337
2338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002339void Simulator::SignalException(Exception e) {
2340 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2341 static_cast<int>(e));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002342}
2343
Ben Murdoch097c5b22016-05-18 11:27:45 +01002344// Min/Max template functions for Double and Single arguments.
2345
2346template <typename T>
2347static T FPAbs(T a);
2348
2349template <>
2350double FPAbs<double>(double a) {
2351 return fabs(a);
2352}
2353
2354template <>
2355float FPAbs<float>(float a) {
2356 return fabsf(a);
2357}
2358
2359template <typename T>
2360static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2361 if (std::isnan(a) && std::isnan(b)) {
2362 result = a;
2363 } else if (std::isnan(a)) {
2364 result = b;
2365 } else if (std::isnan(b)) {
2366 result = a;
2367 } else if (b == a) {
2368 // Handle -0.0 == 0.0 case.
2369 // std::signbit() returns int 0 or 1 so substracting MaxMinKind::kMax
2370 // negates the result.
2371 result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2372 } else {
2373 return false;
2374 }
2375 return true;
2376}
2377
2378template <typename T>
2379static T FPUMin(T a, T b) {
2380 T result;
2381 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2382 return result;
2383 } else {
2384 return b < a ? b : a;
2385 }
2386}
2387
2388template <typename T>
2389static T FPUMax(T a, T b) {
2390 T result;
2391 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2392 return result;
2393 } else {
2394 return b > a ? b : a;
2395 }
2396}
2397
2398template <typename T>
2399static T FPUMinA(T a, T b) {
2400 T result;
2401 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2402 if (FPAbs(a) < FPAbs(b)) {
2403 result = a;
2404 } else if (FPAbs(b) < FPAbs(a)) {
2405 result = b;
2406 } else {
2407 result = a < b ? a : b;
2408 }
2409 }
2410 return result;
2411}
2412
2413template <typename T>
2414static T FPUMaxA(T a, T b) {
2415 T result;
2416 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2417 if (FPAbs(a) > FPAbs(b)) {
2418 result = a;
2419 } else if (FPAbs(b) > FPAbs(a)) {
2420 result = b;
2421 } else {
2422 result = a > b ? a : b;
2423 }
2424 }
2425 return result;
2426}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002427
2428// Handle execution based on instruction types.
2429
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002430void Simulator::DecodeTypeRegisterSRsType() {
2431 float fs, ft, fd;
2432 fs = get_fpu_register_float(fs_reg());
2433 ft = get_fpu_register_float(ft_reg());
2434 fd = get_fpu_register_float(fd_reg());
2435 int32_t ft_int = bit_cast<int32_t>(ft);
2436 int32_t fd_int = bit_cast<int32_t>(fd);
2437 uint32_t cc, fcsr_cc;
2438 cc = get_instr()->FCccValue();
2439 fcsr_cc = get_fcsr_condition_bit(cc);
2440 switch (get_instr()->FunctionFieldRaw()) {
2441 case RINT: {
2442 DCHECK(kArchVariant == kMips64r6);
2443 float result, temp_result;
2444 double temp;
2445 float upper = std::ceil(fs);
2446 float lower = std::floor(fs);
2447 switch (get_fcsr_rounding_mode()) {
2448 case kRoundToNearest:
2449 if (upper - fs < fs - lower) {
2450 result = upper;
2451 } else if (upper - fs > fs - lower) {
2452 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002453 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002454 temp_result = upper / 2;
2455 float reminder = modf(temp_result, &temp);
2456 if (reminder == 0) {
2457 result = upper;
2458 } else {
2459 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002460 }
2461 }
2462 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002463 case kRoundToZero:
2464 result = (fs > 0 ? lower : upper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002465 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466 case kRoundToPlusInf:
2467 result = upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002468 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002469 case kRoundToMinusInf:
2470 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002471 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002472 }
2473 set_fpu_register_float(fd_reg(), result);
2474 if (result != fs) {
2475 set_fcsr_bit(kFCSRInexactFlagBit, true);
2476 }
2477 break;
2478 }
2479 case ADD_S:
2480 set_fpu_register_float(fd_reg(), fs + ft);
2481 break;
2482 case SUB_S:
2483 set_fpu_register_float(fd_reg(), fs - ft);
2484 break;
2485 case MUL_S:
2486 set_fpu_register_float(fd_reg(), fs * ft);
2487 break;
2488 case DIV_S:
2489 set_fpu_register_float(fd_reg(), fs / ft);
2490 break;
2491 case ABS_S:
2492 set_fpu_register_float(fd_reg(), fabs(fs));
2493 break;
2494 case MOV_S:
2495 set_fpu_register_float(fd_reg(), fs);
2496 break;
2497 case NEG_S:
2498 set_fpu_register_float(fd_reg(), -fs);
2499 break;
2500 case SQRT_S:
2501 lazily_initialize_fast_sqrt(isolate_);
2502 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
2503 break;
2504 case RSQRT_S: {
2505 lazily_initialize_fast_sqrt(isolate_);
2506 float result = 1.0 / fast_sqrt(fs, isolate_);
2507 set_fpu_register_float(fd_reg(), result);
2508 break;
2509 }
2510 case RECIP_S: {
2511 float result = 1.0 / fs;
2512 set_fpu_register_float(fd_reg(), result);
2513 break;
2514 }
2515 case C_F_D:
2516 set_fcsr_bit(fcsr_cc, false);
2517 break;
2518 case C_UN_D:
2519 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2520 break;
2521 case C_EQ_D:
2522 set_fcsr_bit(fcsr_cc, (fs == ft));
2523 break;
2524 case C_UEQ_D:
2525 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2526 break;
2527 case C_OLT_D:
2528 set_fcsr_bit(fcsr_cc, (fs < ft));
2529 break;
2530 case C_ULT_D:
2531 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2532 break;
2533 case C_OLE_D:
2534 set_fcsr_bit(fcsr_cc, (fs <= ft));
2535 break;
2536 case C_ULE_D:
2537 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2538 break;
2539 case CVT_D_S:
2540 set_fpu_register_double(fd_reg(), static_cast<double>(fs));
2541 break;
2542 case CLASS_S: { // Mips64r6 instruction
2543 // Convert float input to uint32_t for easier bit manipulation
2544 uint32_t classed = bit_cast<uint32_t>(fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002546 // Extracting sign, exponent and mantissa from the input float
2547 uint32_t sign = (classed >> 31) & 1;
2548 uint32_t exponent = (classed >> 23) & 0x000000ff;
2549 uint32_t mantissa = classed & 0x007fffff;
2550 uint32_t result;
2551 float fResult;
2552
2553 // Setting flags if input float is negative infinity,
2554 // positive infinity, negative zero or positive zero
2555 bool negInf = (classed == 0xFF800000);
2556 bool posInf = (classed == 0x7F800000);
2557 bool negZero = (classed == 0x80000000);
2558 bool posZero = (classed == 0x00000000);
2559
2560 bool signalingNan;
2561 bool quietNan;
2562 bool negSubnorm;
2563 bool posSubnorm;
2564 bool negNorm;
2565 bool posNorm;
2566
2567 // Setting flags if float is NaN
2568 signalingNan = false;
2569 quietNan = false;
2570 if (!negInf && !posInf && (exponent == 0xff)) {
2571 quietNan = ((mantissa & 0x00200000) == 0) &&
2572 ((mantissa & (0x00200000 - 1)) == 0);
2573 signalingNan = !quietNan;
2574 }
2575
2576 // Setting flags if float is subnormal number
2577 posSubnorm = false;
2578 negSubnorm = false;
2579 if ((exponent == 0) && (mantissa != 0)) {
2580 DCHECK(sign == 0 || sign == 1);
2581 posSubnorm = (sign == 0);
2582 negSubnorm = (sign == 1);
2583 }
2584
2585 // Setting flags if float is normal number
2586 posNorm = false;
2587 negNorm = false;
2588 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2589 !quietNan && !negZero && !posZero) {
2590 DCHECK(sign == 0 || sign == 1);
2591 posNorm = (sign == 0);
2592 negNorm = (sign == 1);
2593 }
2594
2595 // Calculating result according to description of CLASS.S instruction
2596 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2597 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2598 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2599
2600 DCHECK(result != 0);
2601
2602 fResult = bit_cast<float>(result);
2603 set_fpu_register_float(fd_reg(), fResult);
2604
2605 break;
2606 }
2607 case CVT_L_S: {
2608 float rounded;
2609 int64_t result;
2610 round64_according_to_fcsr(fs, rounded, result, fs);
2611 set_fpu_register(fd_reg(), result);
2612 if (set_fcsr_round64_error(fs, rounded)) {
2613 set_fpu_register_invalid_result64(fs, rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002614 }
2615 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002616 }
2617 case CVT_W_S: {
2618 float rounded;
2619 int32_t result;
2620 round_according_to_fcsr(fs, rounded, result, fs);
2621 set_fpu_register_word(fd_reg(), result);
2622 if (set_fcsr_round_error(fs, rounded)) {
2623 set_fpu_register_word_invalid_result(fs, rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002624 }
2625 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 }
2627 case TRUNC_W_S: { // Truncate single to word (round towards 0).
2628 float rounded = trunc(fs);
2629 int32_t result = static_cast<int32_t>(rounded);
2630 set_fpu_register_word(fd_reg(), result);
2631 if (set_fcsr_round_error(fs, rounded)) {
2632 set_fpu_register_word_invalid_result(fs, rounded);
2633 }
2634 } break;
2635 case TRUNC_L_S: { // Mips64r2 instruction.
2636 float rounded = trunc(fs);
2637 int64_t result = static_cast<int64_t>(rounded);
2638 set_fpu_register(fd_reg(), result);
2639 if (set_fcsr_round64_error(fs, rounded)) {
2640 set_fpu_register_invalid_result64(fs, rounded);
2641 }
2642 break;
2643 }
2644 case ROUND_W_S: {
2645 float rounded = std::floor(fs + 0.5);
2646 int32_t result = static_cast<int32_t>(rounded);
2647 if ((result & 1) != 0 && result - fs == 0.5) {
2648 // If the number is halfway between two integers,
2649 // round to the even one.
2650 result--;
2651 }
2652 set_fpu_register_word(fd_reg(), result);
2653 if (set_fcsr_round_error(fs, rounded)) {
2654 set_fpu_register_word_invalid_result(fs, rounded);
2655 }
2656 break;
2657 }
2658 case ROUND_L_S: { // Mips64r2 instruction.
2659 float rounded = std::floor(fs + 0.5);
2660 int64_t result = static_cast<int64_t>(rounded);
2661 if ((result & 1) != 0 && result - fs == 0.5) {
2662 // If the number is halfway between two integers,
2663 // round to the even one.
2664 result--;
2665 }
2666 int64_t i64 = static_cast<int64_t>(result);
2667 set_fpu_register(fd_reg(), i64);
2668 if (set_fcsr_round64_error(fs, rounded)) {
2669 set_fpu_register_invalid_result64(fs, rounded);
2670 }
2671 break;
2672 }
2673 case FLOOR_L_S: { // Mips64r2 instruction.
2674 float rounded = floor(fs);
2675 int64_t result = static_cast<int64_t>(rounded);
2676 set_fpu_register(fd_reg(), result);
2677 if (set_fcsr_round64_error(fs, rounded)) {
2678 set_fpu_register_invalid_result64(fs, rounded);
2679 }
2680 break;
2681 }
2682 case FLOOR_W_S: // Round double to word towards negative infinity.
2683 {
2684 float rounded = std::floor(fs);
2685 int32_t result = static_cast<int32_t>(rounded);
2686 set_fpu_register_word(fd_reg(), result);
2687 if (set_fcsr_round_error(fs, rounded)) {
2688 set_fpu_register_word_invalid_result(fs, rounded);
2689 }
2690 } break;
2691 case CEIL_W_S: // Round double to word towards positive infinity.
2692 {
2693 float rounded = std::ceil(fs);
2694 int32_t result = static_cast<int32_t>(rounded);
2695 set_fpu_register_word(fd_reg(), result);
2696 if (set_fcsr_round_error(fs, rounded)) {
2697 set_fpu_register_invalid_result(fs, rounded);
2698 }
2699 } break;
2700 case CEIL_L_S: { // Mips64r2 instruction.
2701 float rounded = ceil(fs);
2702 int64_t result = static_cast<int64_t>(rounded);
2703 set_fpu_register(fd_reg(), result);
2704 if (set_fcsr_round64_error(fs, rounded)) {
2705 set_fpu_register_invalid_result64(fs, rounded);
2706 }
2707 break;
2708 }
2709 case MINA:
2710 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002711 set_fpu_register_float(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002712 break;
2713 case MAXA:
2714 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002715 set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002716 break;
2717 case MIN:
2718 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002719 set_fpu_register_float(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002720 break;
2721 case MAX:
2722 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002723 set_fpu_register_float(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002724 break;
2725 case SEL:
2726 DCHECK(kArchVariant == kMips64r6);
2727 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2728 break;
2729 case SELEQZ_C:
2730 DCHECK(kArchVariant == kMips64r6);
2731 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
2732 ? get_fpu_register_float(fs_reg())
2733 : 0.0);
2734 break;
2735 case SELNEZ_C:
2736 DCHECK(kArchVariant == kMips64r6);
2737 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
2738 ? get_fpu_register_float(fs_reg())
2739 : 0.0);
2740 break;
2741 case MOVZ_C: {
2742 DCHECK(kArchVariant == kMips64r2);
2743 if (rt() == 0) {
2744 set_fpu_register_float(fd_reg(), fs);
2745 }
2746 break;
2747 }
2748 case MOVN_C: {
2749 DCHECK(kArchVariant == kMips64r2);
2750 if (rt() != 0) {
2751 set_fpu_register_float(fd_reg(), fs);
2752 }
2753 break;
2754 }
2755 case MOVF: {
2756 // Same function field for MOVT.D and MOVF.D
2757 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2758 ft_cc = get_fcsr_condition_bit(ft_cc);
2759
2760 if (get_instr()->Bit(16)) { // Read Tf bit.
2761 // MOVT.D
2762 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
2763 } else {
2764 // MOVF.D
2765 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
2766 }
2767 break;
2768 }
2769 default:
2770 // TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
2771 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
2772 UNREACHABLE();
2773 }
2774}
2775
2776
2777void Simulator::DecodeTypeRegisterDRsType() {
2778 double ft, fs, fd;
2779 uint32_t cc, fcsr_cc;
2780 fs = get_fpu_register_double(fs_reg());
2781 ft = (get_instr()->FunctionFieldRaw() != MOVF)
2782 ? get_fpu_register_double(ft_reg())
2783 : 0.0;
2784 fd = get_fpu_register_double(fd_reg());
2785 cc = get_instr()->FCccValue();
2786 fcsr_cc = get_fcsr_condition_bit(cc);
2787 int64_t ft_int = bit_cast<int64_t>(ft);
2788 int64_t fd_int = bit_cast<int64_t>(fd);
2789 switch (get_instr()->FunctionFieldRaw()) {
2790 case RINT: {
2791 DCHECK(kArchVariant == kMips64r6);
2792 double result, temp, temp_result;
2793 double upper = std::ceil(fs);
2794 double lower = std::floor(fs);
2795 switch (get_fcsr_rounding_mode()) {
2796 case kRoundToNearest:
2797 if (upper - fs < fs - lower) {
2798 result = upper;
2799 } else if (upper - fs > fs - lower) {
2800 result = lower;
2801 } else {
2802 temp_result = upper / 2;
2803 double reminder = modf(temp_result, &temp);
2804 if (reminder == 0) {
2805 result = upper;
2806 } else {
2807 result = lower;
2808 }
2809 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002810 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002811 case kRoundToZero:
2812 result = (fs > 0 ? lower : upper);
2813 break;
2814 case kRoundToPlusInf:
2815 result = upper;
2816 break;
2817 case kRoundToMinusInf:
2818 result = lower;
2819 break;
2820 }
2821 set_fpu_register_double(fd_reg(), result);
2822 if (result != fs) {
2823 set_fcsr_bit(kFCSRInexactFlagBit, true);
2824 }
2825 break;
2826 }
2827 case SEL:
2828 DCHECK(kArchVariant == kMips64r6);
2829 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2830 break;
2831 case SELEQZ_C:
2832 DCHECK(kArchVariant == kMips64r6);
2833 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2834 break;
2835 case SELNEZ_C:
2836 DCHECK(kArchVariant == kMips64r6);
2837 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2838 break;
2839 case MOVZ_C: {
2840 DCHECK(kArchVariant == kMips64r2);
2841 if (rt() == 0) {
2842 set_fpu_register_double(fd_reg(), fs);
2843 }
2844 break;
2845 }
2846 case MOVN_C: {
2847 DCHECK(kArchVariant == kMips64r2);
2848 if (rt() != 0) {
2849 set_fpu_register_double(fd_reg(), fs);
2850 }
2851 break;
2852 }
2853 case MOVF: {
2854 // Same function field for MOVT.D and MOVF.D
2855 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2856 ft_cc = get_fcsr_condition_bit(ft_cc);
2857 if (get_instr()->Bit(16)) { // Read Tf bit.
2858 // MOVT.D
2859 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2860 } else {
2861 // MOVF.D
2862 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2863 }
2864 break;
2865 }
2866 case MINA:
2867 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002868 set_fpu_register_double(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002869 break;
2870 case MAXA:
2871 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002872 set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002873 break;
2874 case MIN:
2875 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002876 set_fpu_register_double(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002877 break;
2878 case MAX:
2879 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002880 set_fpu_register_double(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002881 break;
2882 case ADD_D:
2883 set_fpu_register_double(fd_reg(), fs + ft);
2884 break;
2885 case SUB_D:
2886 set_fpu_register_double(fd_reg(), fs - ft);
2887 break;
2888 case MUL_D:
2889 set_fpu_register_double(fd_reg(), fs * ft);
2890 break;
2891 case DIV_D:
2892 set_fpu_register_double(fd_reg(), fs / ft);
2893 break;
2894 case ABS_D:
2895 set_fpu_register_double(fd_reg(), fabs(fs));
2896 break;
2897 case MOV_D:
2898 set_fpu_register_double(fd_reg(), fs);
2899 break;
2900 case NEG_D:
2901 set_fpu_register_double(fd_reg(), -fs);
2902 break;
2903 case SQRT_D:
2904 lazily_initialize_fast_sqrt(isolate_);
2905 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
2906 break;
2907 case RSQRT_D: {
2908 lazily_initialize_fast_sqrt(isolate_);
2909 double result = 1.0 / fast_sqrt(fs, isolate_);
2910 set_fpu_register_double(fd_reg(), result);
2911 break;
2912 }
2913 case RECIP_D: {
2914 double result = 1.0 / fs;
2915 set_fpu_register_double(fd_reg(), result);
2916 break;
2917 }
2918 case C_UN_D:
2919 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2920 break;
2921 case C_EQ_D:
2922 set_fcsr_bit(fcsr_cc, (fs == ft));
2923 break;
2924 case C_UEQ_D:
2925 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2926 break;
2927 case C_OLT_D:
2928 set_fcsr_bit(fcsr_cc, (fs < ft));
2929 break;
2930 case C_ULT_D:
2931 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2932 break;
2933 case C_OLE_D:
2934 set_fcsr_bit(fcsr_cc, (fs <= ft));
2935 break;
2936 case C_ULE_D:
2937 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2938 break;
2939 case CVT_W_D: { // Convert double to word.
2940 double rounded;
2941 int32_t result;
2942 round_according_to_fcsr(fs, rounded, result, fs);
2943 set_fpu_register_word(fd_reg(), result);
2944 if (set_fcsr_round_error(fs, rounded)) {
2945 set_fpu_register_word_invalid_result(fs, rounded);
2946 }
2947 break;
2948 }
2949 case ROUND_W_D: // Round double to word (round half to even).
2950 {
2951 double rounded = std::floor(fs + 0.5);
2952 int32_t result = static_cast<int32_t>(rounded);
2953 if ((result & 1) != 0 && result - fs == 0.5) {
2954 // If the number is halfway between two integers,
2955 // round to the even one.
2956 result--;
2957 }
2958 set_fpu_register_word(fd_reg(), result);
2959 if (set_fcsr_round_error(fs, rounded)) {
2960 set_fpu_register_invalid_result(fs, rounded);
2961 }
2962 } break;
2963 case TRUNC_W_D: // Truncate double to word (round towards 0).
2964 {
2965 double rounded = trunc(fs);
2966 int32_t result = static_cast<int32_t>(rounded);
2967 set_fpu_register_word(fd_reg(), result);
2968 if (set_fcsr_round_error(fs, rounded)) {
2969 set_fpu_register_invalid_result(fs, rounded);
2970 }
2971 } break;
2972 case FLOOR_W_D: // Round double to word towards negative infinity.
2973 {
2974 double rounded = std::floor(fs);
2975 int32_t result = static_cast<int32_t>(rounded);
2976 set_fpu_register_word(fd_reg(), result);
2977 if (set_fcsr_round_error(fs, rounded)) {
2978 set_fpu_register_invalid_result(fs, rounded);
2979 }
2980 } break;
2981 case CEIL_W_D: // Round double to word towards positive infinity.
2982 {
2983 double rounded = std::ceil(fs);
2984 int32_t result = static_cast<int32_t>(rounded);
2985 set_fpu_register_word(fd_reg(), result);
2986 if (set_fcsr_round_error(fs, rounded)) {
2987 set_fpu_register_invalid_result(fs, rounded);
2988 }
2989 } break;
2990 case CVT_S_D: // Convert double to float (single).
2991 set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2992 break;
2993 case CVT_L_D: { // Mips64r2: Truncate double to 64-bit long-word.
2994 double rounded;
2995 int64_t result;
2996 round64_according_to_fcsr(fs, rounded, result, fs);
2997 set_fpu_register(fd_reg(), result);
2998 if (set_fcsr_round64_error(fs, rounded)) {
2999 set_fpu_register_invalid_result64(fs, rounded);
3000 }
3001 break;
3002 }
3003 case ROUND_L_D: { // Mips64r2 instruction.
3004 double rounded = std::floor(fs + 0.5);
3005 int64_t result = static_cast<int64_t>(rounded);
3006 if ((result & 1) != 0 && result - fs == 0.5) {
3007 // If the number is halfway between two integers,
3008 // round to the even one.
3009 result--;
3010 }
3011 int64_t i64 = static_cast<int64_t>(result);
3012 set_fpu_register(fd_reg(), i64);
3013 if (set_fcsr_round64_error(fs, rounded)) {
3014 set_fpu_register_invalid_result64(fs, rounded);
3015 }
3016 break;
3017 }
3018 case TRUNC_L_D: { // Mips64r2 instruction.
3019 double rounded = trunc(fs);
3020 int64_t result = static_cast<int64_t>(rounded);
3021 set_fpu_register(fd_reg(), result);
3022 if (set_fcsr_round64_error(fs, rounded)) {
3023 set_fpu_register_invalid_result64(fs, rounded);
3024 }
3025 break;
3026 }
3027 case FLOOR_L_D: { // Mips64r2 instruction.
3028 double rounded = floor(fs);
3029 int64_t result = static_cast<int64_t>(rounded);
3030 set_fpu_register(fd_reg(), result);
3031 if (set_fcsr_round64_error(fs, rounded)) {
3032 set_fpu_register_invalid_result64(fs, rounded);
3033 }
3034 break;
3035 }
3036 case CEIL_L_D: { // Mips64r2 instruction.
3037 double rounded = ceil(fs);
3038 int64_t result = static_cast<int64_t>(rounded);
3039 set_fpu_register(fd_reg(), result);
3040 if (set_fcsr_round64_error(fs, rounded)) {
3041 set_fpu_register_invalid_result64(fs, rounded);
3042 }
3043 break;
3044 }
3045 case CLASS_D: { // Mips64r6 instruction
3046 // Convert double input to uint64_t for easier bit manipulation
3047 uint64_t classed = bit_cast<uint64_t>(fs);
3048
3049 // Extracting sign, exponent and mantissa from the input double
3050 uint32_t sign = (classed >> 63) & 1;
3051 uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
3052 uint64_t mantissa = classed & 0x000fffffffffffff;
3053 uint64_t result;
3054 double dResult;
3055
3056 // Setting flags if input double is negative infinity,
3057 // positive infinity, negative zero or positive zero
3058 bool negInf = (classed == 0xFFF0000000000000);
3059 bool posInf = (classed == 0x7FF0000000000000);
3060 bool negZero = (classed == 0x8000000000000000);
3061 bool posZero = (classed == 0x0000000000000000);
3062
3063 bool signalingNan;
3064 bool quietNan;
3065 bool negSubnorm;
3066 bool posSubnorm;
3067 bool negNorm;
3068 bool posNorm;
3069
3070 // Setting flags if double is NaN
3071 signalingNan = false;
3072 quietNan = false;
3073 if (!negInf && !posInf && exponent == 0x7ff) {
3074 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
3075 ((mantissa & (0x0008000000000000 - 1)) == 0);
3076 signalingNan = !quietNan;
3077 }
3078
3079 // Setting flags if double is subnormal number
3080 posSubnorm = false;
3081 negSubnorm = false;
3082 if ((exponent == 0) && (mantissa != 0)) {
3083 DCHECK(sign == 0 || sign == 1);
3084 posSubnorm = (sign == 0);
3085 negSubnorm = (sign == 1);
3086 }
3087
3088 // Setting flags if double is normal number
3089 posNorm = false;
3090 negNorm = false;
3091 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3092 !quietNan && !negZero && !posZero) {
3093 DCHECK(sign == 0 || sign == 1);
3094 posNorm = (sign == 0);
3095 negNorm = (sign == 1);
3096 }
3097
3098 // Calculating result according to description of CLASS.D instruction
3099 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3100 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3101 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3102
3103 DCHECK(result != 0);
3104
3105 dResult = bit_cast<double>(result);
3106 set_fpu_register_double(fd_reg(), dResult);
3107
3108 break;
3109 }
3110 case C_F_D: {
3111 set_fcsr_bit(fcsr_cc, false);
3112 break;
3113 }
3114 default:
3115 UNREACHABLE();
3116 }
3117}
3118
3119
3120void Simulator::DecodeTypeRegisterWRsType() {
3121 float fs = get_fpu_register_float(fs_reg());
3122 float ft = get_fpu_register_float(ft_reg());
3123 int64_t alu_out = 0x12345678;
3124 switch (get_instr()->FunctionFieldRaw()) {
3125 case CVT_S_W: // Convert word to float (single).
3126 alu_out = get_fpu_register_signed_word(fs_reg());
3127 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
3128 break;
3129 case CVT_D_W: // Convert word to double.
3130 alu_out = get_fpu_register_signed_word(fs_reg());
3131 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
3132 break;
3133 case CMP_AF:
3134 set_fpu_register_word(fd_reg(), 0);
3135 break;
3136 case CMP_UN:
3137 if (std::isnan(fs) || std::isnan(ft)) {
3138 set_fpu_register_word(fd_reg(), -1);
3139 } else {
3140 set_fpu_register_word(fd_reg(), 0);
3141 }
3142 break;
3143 case CMP_EQ:
3144 if (fs == ft) {
3145 set_fpu_register_word(fd_reg(), -1);
3146 } else {
3147 set_fpu_register_word(fd_reg(), 0);
3148 }
3149 break;
3150 case CMP_UEQ:
3151 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3152 set_fpu_register_word(fd_reg(), -1);
3153 } else {
3154 set_fpu_register_word(fd_reg(), 0);
3155 }
3156 break;
3157 case CMP_LT:
3158 if (fs < ft) {
3159 set_fpu_register_word(fd_reg(), -1);
3160 } else {
3161 set_fpu_register_word(fd_reg(), 0);
3162 }
3163 break;
3164 case CMP_ULT:
3165 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3166 set_fpu_register_word(fd_reg(), -1);
3167 } else {
3168 set_fpu_register_word(fd_reg(), 0);
3169 }
3170 break;
3171 case CMP_LE:
3172 if (fs <= ft) {
3173 set_fpu_register_word(fd_reg(), -1);
3174 } else {
3175 set_fpu_register_word(fd_reg(), 0);
3176 }
3177 break;
3178 case CMP_ULE:
3179 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3180 set_fpu_register_word(fd_reg(), -1);
3181 } else {
3182 set_fpu_register_word(fd_reg(), 0);
3183 }
3184 break;
3185 case CMP_OR:
3186 if (!std::isnan(fs) && !std::isnan(ft)) {
3187 set_fpu_register_word(fd_reg(), -1);
3188 } else {
3189 set_fpu_register_word(fd_reg(), 0);
3190 }
3191 break;
3192 case CMP_UNE:
3193 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3194 set_fpu_register_word(fd_reg(), -1);
3195 } else {
3196 set_fpu_register_word(fd_reg(), 0);
3197 }
3198 break;
3199 case CMP_NE:
3200 if (fs != ft) {
3201 set_fpu_register_word(fd_reg(), -1);
3202 } else {
3203 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003204 }
3205 break;
3206 default:
3207 UNREACHABLE();
3208 }
3209}
3210
3211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003212void Simulator::DecodeTypeRegisterLRsType() {
3213 double fs = get_fpu_register_double(fs_reg());
3214 double ft = get_fpu_register_double(ft_reg());
3215 int64_t i64;
3216 switch (get_instr()->FunctionFieldRaw()) {
3217 case CVT_D_L: // Mips32r2 instruction.
3218 i64 = get_fpu_register(fs_reg());
3219 set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3220 break;
3221 case CVT_S_L:
3222 i64 = get_fpu_register(fs_reg());
3223 set_fpu_register_float(fd_reg(), static_cast<float>(i64));
3224 break;
3225 case CMP_AF:
3226 set_fpu_register(fd_reg(), 0);
3227 break;
3228 case CMP_UN:
3229 if (std::isnan(fs) || std::isnan(ft)) {
3230 set_fpu_register(fd_reg(), -1);
3231 } else {
3232 set_fpu_register(fd_reg(), 0);
3233 }
3234 break;
3235 case CMP_EQ:
3236 if (fs == ft) {
3237 set_fpu_register(fd_reg(), -1);
3238 } else {
3239 set_fpu_register(fd_reg(), 0);
3240 }
3241 break;
3242 case CMP_UEQ:
3243 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3244 set_fpu_register(fd_reg(), -1);
3245 } else {
3246 set_fpu_register(fd_reg(), 0);
3247 }
3248 break;
3249 case CMP_LT:
3250 if (fs < ft) {
3251 set_fpu_register(fd_reg(), -1);
3252 } else {
3253 set_fpu_register(fd_reg(), 0);
3254 }
3255 break;
3256 case CMP_ULT:
3257 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3258 set_fpu_register(fd_reg(), -1);
3259 } else {
3260 set_fpu_register(fd_reg(), 0);
3261 }
3262 break;
3263 case CMP_LE:
3264 if (fs <= ft) {
3265 set_fpu_register(fd_reg(), -1);
3266 } else {
3267 set_fpu_register(fd_reg(), 0);
3268 }
3269 break;
3270 case CMP_ULE:
3271 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3272 set_fpu_register(fd_reg(), -1);
3273 } else {
3274 set_fpu_register(fd_reg(), 0);
3275 }
3276 break;
3277 case CMP_OR:
3278 if (!std::isnan(fs) && !std::isnan(ft)) {
3279 set_fpu_register(fd_reg(), -1);
3280 } else {
3281 set_fpu_register(fd_reg(), 0);
3282 }
3283 break;
3284 case CMP_UNE:
3285 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3286 set_fpu_register(fd_reg(), -1);
3287 } else {
3288 set_fpu_register(fd_reg(), 0);
3289 }
3290 break;
3291 case CMP_NE:
3292 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3293 set_fpu_register(fd_reg(), -1);
3294 } else {
3295 set_fpu_register(fd_reg(), 0);
3296 }
3297 break;
3298 default:
3299 UNREACHABLE();
3300 }
3301}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003302
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003304void Simulator::DecodeTypeRegisterCOP1() {
3305 switch (get_instr()->RsFieldRaw()) {
3306 case BC1: // Branch on coprocessor condition.
3307 case BC1EQZ:
3308 case BC1NEZ:
3309 UNREACHABLE();
3310 break;
3311 case CFC1:
3312 // At the moment only FCSR is supported.
3313 DCHECK(fs_reg() == kFCSRRegister);
3314 set_register(rt_reg(), FCSR_);
3315 break;
3316 case MFC1:
3317 set_register(rt_reg(),
3318 static_cast<int64_t>(get_fpu_register_word(fs_reg())));
3319 break;
3320 case DMFC1:
3321 set_register(rt_reg(), get_fpu_register(fs_reg()));
3322 break;
3323 case MFHC1:
3324 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3325 break;
3326 case CTC1: {
3327 // At the moment only FCSR is supported.
3328 DCHECK(fs_reg() == kFCSRRegister);
3329 uint32_t reg = static_cast<uint32_t>(rt());
3330 if (kArchVariant == kMips64r6) {
3331 FCSR_ = reg | kFCSRNaN2008FlagMask;
3332 } else {
3333 DCHECK(kArchVariant == kMips64r2);
3334 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3335 }
3336 break;
3337 }
3338 case MTC1:
3339 // Hardware writes upper 32-bits to zero on mtc1.
3340 set_fpu_register_hi_word(fs_reg(), 0);
3341 set_fpu_register_word(fs_reg(), static_cast<int32_t>(rt()));
3342 break;
3343 case DMTC1:
3344 set_fpu_register(fs_reg(), rt());
3345 break;
3346 case MTHC1:
3347 set_fpu_register_hi_word(fs_reg(), static_cast<int32_t>(rt()));
3348 break;
3349 case S:
3350 DecodeTypeRegisterSRsType();
3351 break;
3352 case D:
3353 DecodeTypeRegisterDRsType();
3354 break;
3355 case W:
3356 DecodeTypeRegisterWRsType();
3357 break;
3358 case L:
3359 DecodeTypeRegisterLRsType();
3360 break;
3361 default:
3362 UNREACHABLE();
3363 }
3364}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003366
3367void Simulator::DecodeTypeRegisterCOP1X() {
3368 switch (get_instr()->FunctionFieldRaw()) {
3369 case MADD_D:
3370 double fr, ft, fs;
3371 fr = get_fpu_register_double(fr_reg());
3372 fs = get_fpu_register_double(fs_reg());
3373 ft = get_fpu_register_double(ft_reg());
3374 set_fpu_register_double(fd_reg(), fs * ft + fr);
3375 break;
3376 default:
3377 UNREACHABLE();
3378 }
3379}
3380
3381
3382void Simulator::DecodeTypeRegisterSPECIAL() {
3383 int64_t i64hilo;
3384 uint64_t u64hilo;
3385 int64_t alu_out;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003386 bool do_interrupt = false;
3387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003388 switch (get_instr()->FunctionFieldRaw()) {
3389 case SELEQZ_S:
3390 DCHECK(kArchVariant == kMips64r6);
3391 set_register(rd_reg(), rt() == 0 ? rs() : 0);
3392 break;
3393 case SELNEZ_S:
3394 DCHECK(kArchVariant == kMips64r6);
3395 set_register(rd_reg(), rt() != 0 ? rs() : 0);
3396 break;
3397 case JR: {
3398 int64_t next_pc = rs();
3399 int64_t current_pc = get_pc();
3400 Instruction* branch_delay_instr =
3401 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3402 BranchDelayInstructionDecode(branch_delay_instr);
3403 set_pc(next_pc);
3404 pc_modified_ = true;
3405 break;
3406 }
3407 case JALR: {
3408 int64_t next_pc = rs();
3409 int64_t current_pc = get_pc();
3410 int32_t return_addr_reg = rd_reg();
3411 Instruction* branch_delay_instr =
3412 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3413 BranchDelayInstructionDecode(branch_delay_instr);
3414 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3415 set_pc(next_pc);
3416 pc_modified_ = true;
3417 break;
3418 }
3419 case SLL:
3420 SetResult(rd_reg(), static_cast<int32_t>(rt()) << sa());
3421 break;
3422 case DSLL:
3423 SetResult(rd_reg(), rt() << sa());
3424 break;
3425 case DSLL32:
3426 SetResult(rd_reg(), rt() << sa() << 32);
3427 break;
3428 case SRL:
3429 if (rs_reg() == 0) {
3430 // Regular logical right shift of a word by a fixed number of
3431 // bits instruction. RS field is always equal to 0.
3432 // Sign-extend the 32-bit result.
3433 alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u()) >> sa());
Ben Murdochc5610432016-08-08 18:44:38 +01003434 } else if (rs_reg() == 1) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003435 // Logical right-rotate of a word by a fixed number of bits. This
3436 // is special case of SRL instruction, added in MIPS32 Release 2.
3437 // RS field is equal to 00001.
3438 alu_out = static_cast<int32_t>(
3439 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3440 static_cast<const uint32_t>(sa())));
Ben Murdochc5610432016-08-08 18:44:38 +01003441 } else {
3442 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003443 }
3444 SetResult(rd_reg(), alu_out);
3445 break;
3446 case DSRL:
Ben Murdochc5610432016-08-08 18:44:38 +01003447 if (rs_reg() == 0) {
3448 // Regular logical right shift of a word by a fixed number of
3449 // bits instruction. RS field is always equal to 0.
3450 // Sign-extend the 64-bit result.
3451 alu_out = static_cast<int64_t>(rt_u() >> sa());
3452 } else if (rs_reg() == 1) {
3453 // Logical right-rotate of a word by a fixed number of bits. This
3454 // is special case of SRL instruction, added in MIPS32 Release 2.
3455 // RS field is equal to 00001.
3456 alu_out = static_cast<int64_t>(base::bits::RotateRight64(rt_u(), sa()));
3457 } else {
3458 UNREACHABLE();
3459 }
3460 SetResult(rd_reg(), alu_out);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003461 break;
3462 case DSRL32:
Ben Murdochc5610432016-08-08 18:44:38 +01003463 if (rs_reg() == 0) {
3464 // Regular logical right shift of a word by a fixed number of
3465 // bits instruction. RS field is always equal to 0.
3466 // Sign-extend the 64-bit result.
3467 alu_out = static_cast<int64_t>(rt_u() >> sa() >> 32);
3468 } else if (rs_reg() == 1) {
3469 // Logical right-rotate of a word by a fixed number of bits. This
3470 // is special case of SRL instruction, added in MIPS32 Release 2.
3471 // RS field is equal to 00001.
3472 alu_out =
3473 static_cast<int64_t>(base::bits::RotateRight64(rt_u(), sa() + 32));
3474 } else {
3475 UNREACHABLE();
3476 }
3477 SetResult(rd_reg(), alu_out);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003478 break;
3479 case SRA:
3480 SetResult(rd_reg(), (int32_t)rt() >> sa());
3481 break;
3482 case DSRA:
3483 SetResult(rd_reg(), rt() >> sa());
3484 break;
3485 case DSRA32:
3486 SetResult(rd_reg(), rt() >> sa() >> 32);
3487 break;
3488 case SLLV:
3489 SetResult(rd_reg(), (int32_t)rt() << rs());
3490 break;
3491 case DSLLV:
3492 SetResult(rd_reg(), rt() << rs());
3493 break;
3494 case SRLV:
3495 if (sa() == 0) {
3496 // Regular logical right-shift of a word by a variable number of
3497 // bits instruction. SA field is always equal to 0.
3498 alu_out = static_cast<int32_t>((uint32_t)rt_u() >> rs());
3499 } else {
3500 // Logical right-rotate of a word by a variable number of bits.
3501 // This is special case od SRLV instruction, added in MIPS32
3502 // Release 2. SA field is equal to 00001.
3503 alu_out = static_cast<int32_t>(
3504 base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()),
3505 static_cast<const uint32_t>(rs_u())));
3506 }
3507 SetResult(rd_reg(), alu_out);
3508 break;
3509 case DSRLV:
3510 if (sa() == 0) {
3511 // Regular logical right-shift of a word by a variable number of
3512 // bits instruction. SA field is always equal to 0.
Ben Murdochc5610432016-08-08 18:44:38 +01003513 alu_out = static_cast<int64_t>(rt_u() >> rs());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003514 } else {
3515 // Logical right-rotate of a word by a variable number of bits.
3516 // This is special case od SRLV instruction, added in MIPS32
3517 // Release 2. SA field is equal to 00001.
Ben Murdochc5610432016-08-08 18:44:38 +01003518 alu_out =
3519 static_cast<int64_t>(base::bits::RotateRight64(rt_u(), rs_u()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003520 }
3521 SetResult(rd_reg(), alu_out);
3522 break;
3523 case SRAV:
3524 SetResult(rd_reg(), (int32_t)rt() >> rs());
3525 break;
3526 case DSRAV:
3527 SetResult(rd_reg(), rt() >> rs());
3528 break;
3529 case LSA: {
3530 DCHECK(kArchVariant == kMips64r6);
3531 int8_t sa = lsa_sa() + 1;
3532 int32_t _rt = static_cast<int32_t>(rt());
3533 int32_t _rs = static_cast<int32_t>(rs());
3534 int32_t res = _rs << sa;
3535 res += _rt;
3536 SetResult(rd_reg(), static_cast<int64_t>(res));
3537 break;
3538 }
3539 case DLSA:
3540 DCHECK(kArchVariant == kMips64r6);
3541 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3542 break;
3543 case MFHI: // MFHI == CLZ on R6.
3544 if (kArchVariant != kMips64r6) {
3545 DCHECK(sa() == 0);
3546 alu_out = get_register(HI);
3547 } else {
3548 // MIPS spec: If no bits were set in GPR rs(), the result written to
3549 // GPR rd() is 32.
3550 DCHECK(sa() == 1);
3551 alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u()));
3552 }
3553 SetResult(rd_reg(), alu_out);
3554 break;
3555 case MFLO: // MFLO == DCLZ on R6.
3556 if (kArchVariant != kMips64r6) {
3557 DCHECK(sa() == 0);
3558 alu_out = get_register(LO);
3559 } else {
3560 // MIPS spec: If no bits were set in GPR rs(), the result written to
3561 // GPR rd() is 64.
3562 DCHECK(sa() == 1);
3563 alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rs_u()));
3564 }
3565 SetResult(rd_reg(), alu_out);
3566 break;
3567 // Instructions using HI and LO registers.
3568 case MULT: { // MULT == D_MUL_MUH.
3569 int32_t rs_lo = static_cast<int32_t>(rs());
3570 int32_t rt_lo = static_cast<int32_t>(rt());
3571 i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
3572 if (kArchVariant != kMips64r6) {
3573 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3574 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3575 } else {
3576 switch (sa()) {
3577 case MUL_OP:
3578 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3579 break;
3580 case MUH_OP:
3581 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3582 break;
3583 default:
3584 UNIMPLEMENTED_MIPS();
3585 break;
3586 }
3587 }
3588 break;
3589 }
3590 case MULTU:
3591 u64hilo = static_cast<uint64_t>(rs_u() & 0xffffffff) *
3592 static_cast<uint64_t>(rt_u() & 0xffffffff);
3593 if (kArchVariant != kMips64r6) {
3594 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3595 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3596 } else {
3597 switch (sa()) {
3598 case MUL_OP:
3599 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3600 break;
3601 case MUH_OP:
3602 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3603 break;
3604 default:
3605 UNIMPLEMENTED_MIPS();
3606 break;
3607 }
3608 }
3609 break;
3610 case DMULT: // DMULT == D_MUL_MUH.
3611 if (kArchVariant != kMips64r6) {
3612 set_register(LO, rs() * rt());
3613 set_register(HI, MultiplyHighSigned(rs(), rt()));
3614 } else {
3615 switch (sa()) {
3616 case MUL_OP:
3617 set_register(rd_reg(), rs() * rt());
3618 break;
3619 case MUH_OP:
3620 set_register(rd_reg(), MultiplyHighSigned(rs(), rt()));
3621 break;
3622 default:
3623 UNIMPLEMENTED_MIPS();
3624 break;
3625 }
3626 }
3627 break;
3628 case DMULTU:
3629 UNIMPLEMENTED_MIPS();
3630 break;
3631 case DIV:
3632 case DDIV: {
3633 const int64_t int_min_value =
3634 get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN;
3635 switch (kArchVariant) {
3636 case kMips64r2:
3637 // Divide by zero and overflow was not checked in the
3638 // configuration step - div and divu do not raise exceptions. On
3639 // division by 0 the result will be UNPREDICTABLE. On overflow
3640 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3641 if (rs() == int_min_value && rt() == -1) {
3642 set_register(LO, int_min_value);
3643 set_register(HI, 0);
3644 } else if (rt() != 0) {
3645 set_register(LO, rs() / rt());
3646 set_register(HI, rs() % rt());
3647 }
3648 break;
3649 case kMips64r6:
3650 switch (sa()) {
3651 case DIV_OP:
3652 if (rs() == int_min_value && rt() == -1) {
3653 set_register(rd_reg(), int_min_value);
3654 } else if (rt() != 0) {
3655 set_register(rd_reg(), rs() / rt());
3656 }
3657 break;
3658 case MOD_OP:
3659 if (rs() == int_min_value && rt() == -1) {
3660 set_register(rd_reg(), 0);
3661 } else if (rt() != 0) {
3662 set_register(rd_reg(), rs() % rt());
3663 }
3664 break;
3665 default:
3666 UNIMPLEMENTED_MIPS();
3667 break;
3668 }
3669 break;
3670 default:
3671 break;
3672 }
3673 break;
3674 }
3675 case DIVU:
3676 switch (kArchVariant) {
3677 case kMips64r6: {
3678 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
3679 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
3680 switch (get_instr()->SaValue()) {
3681 case DIV_OP:
3682 if (rt_u_32 != 0) {
3683 set_register(rd_reg(), rs_u_32 / rt_u_32);
3684 }
3685 break;
3686 case MOD_OP:
3687 if (rt_u() != 0) {
3688 set_register(rd_reg(), rs_u_32 % rt_u_32);
3689 }
3690 break;
3691 default:
3692 UNIMPLEMENTED_MIPS();
3693 break;
3694 }
3695 } break;
3696 default: {
3697 if (rt_u() != 0) {
3698 uint32_t rt_u_32 = static_cast<uint32_t>(rt_u());
3699 uint32_t rs_u_32 = static_cast<uint32_t>(rs_u());
3700 set_register(LO, rs_u_32 / rt_u_32);
3701 set_register(HI, rs_u_32 % rt_u_32);
3702 }
3703 }
3704 }
3705 break;
3706 case DDIVU:
3707 switch (kArchVariant) {
3708 case kMips64r6: {
3709 switch (get_instr()->SaValue()) {
3710 case DIV_OP:
3711 if (rt_u() != 0) {
3712 set_register(rd_reg(), rs_u() / rt_u());
3713 }
3714 break;
3715 case MOD_OP:
3716 if (rt_u() != 0) {
3717 set_register(rd_reg(), rs_u() % rt_u());
3718 }
3719 break;
3720 default:
3721 UNIMPLEMENTED_MIPS();
3722 break;
3723 }
3724 } break;
3725 default: {
3726 if (rt_u() != 0) {
3727 set_register(LO, rs_u() / rt_u());
3728 set_register(HI, rs_u() % rt_u());
3729 }
3730 }
3731 }
3732 break;
3733 case ADD:
3734 case DADD:
3735 if (HaveSameSign(rs(), rt())) {
3736 if (rs() > 0) {
3737 if (rs() > (Registers::kMaxValue - rt())) {
3738 SignalException(kIntegerOverflow);
3739 }
3740 } else if (rs() < 0) {
3741 if (rs() < (Registers::kMinValue - rt())) {
3742 SignalException(kIntegerUnderflow);
3743 }
3744 }
3745 }
3746 SetResult(rd_reg(), rs() + rt());
3747 break;
3748 case ADDU: {
3749 int32_t alu32_out = static_cast<int32_t>(rs() + rt());
3750 // Sign-extend result of 32bit operation into 64bit register.
3751 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3752 break;
3753 }
3754 case DADDU:
3755 SetResult(rd_reg(), rs() + rt());
3756 break;
3757 case SUB:
3758 case DSUB:
3759 if (!HaveSameSign(rs(), rt())) {
3760 if (rs() > 0) {
3761 if (rs() > (Registers::kMaxValue + rt())) {
3762 SignalException(kIntegerOverflow);
3763 }
3764 } else if (rs() < 0) {
3765 if (rs() < (Registers::kMinValue + rt())) {
3766 SignalException(kIntegerUnderflow);
3767 }
3768 }
3769 }
3770 SetResult(rd_reg(), rs() - rt());
3771 break;
3772 case SUBU: {
3773 int32_t alu32_out = static_cast<int32_t>(rs() - rt());
3774 // Sign-extend result of 32bit operation into 64bit register.
3775 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3776 break;
3777 }
3778 case DSUBU:
3779 SetResult(rd_reg(), rs() - rt());
3780 break;
3781 case AND:
3782 SetResult(rd_reg(), rs() & rt());
3783 break;
3784 case OR:
3785 SetResult(rd_reg(), rs() | rt());
3786 break;
3787 case XOR:
3788 SetResult(rd_reg(), rs() ^ rt());
3789 break;
3790 case NOR:
3791 SetResult(rd_reg(), ~(rs() | rt()));
3792 break;
3793 case SLT:
3794 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3795 break;
3796 case SLTU:
3797 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3798 break;
3799 // Break and trap instructions.
3800 case BREAK:
3801 do_interrupt = true;
3802 break;
3803 case TGE:
3804 do_interrupt = rs() >= rt();
3805 break;
3806 case TGEU:
3807 do_interrupt = rs_u() >= rt_u();
3808 break;
3809 case TLT:
3810 do_interrupt = rs() < rt();
3811 break;
3812 case TLTU:
3813 do_interrupt = rs_u() < rt_u();
3814 break;
3815 case TEQ:
3816 do_interrupt = rs() == rt();
3817 break;
3818 case TNE:
3819 do_interrupt = rs() != rt();
3820 break;
Ben Murdochc5610432016-08-08 18:44:38 +01003821 case SYNC:
3822 // TODO(palfia): Ignore sync instruction for now.
3823 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003824 // Conditional moves.
3825 case MOVN:
3826 if (rt()) {
3827 SetResult(rd_reg(), rs());
3828 }
3829 break;
3830 case MOVCI: {
3831 uint32_t cc = get_instr()->FBccValue();
3832 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3833 if (get_instr()->Bit(16)) { // Read Tf bit.
3834 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3835 } else {
3836 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3837 }
3838 break;
3839 }
3840 case MOVZ:
3841 if (!rt()) {
3842 SetResult(rd_reg(), rs());
3843 }
3844 break;
3845 default:
3846 UNREACHABLE();
3847 }
3848 if (do_interrupt) {
3849 SoftwareInterrupt(get_instr());
3850 }
3851}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003852
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003853
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003854void Simulator::DecodeTypeRegisterSPECIAL2() {
3855 int64_t alu_out;
3856 switch (get_instr()->FunctionFieldRaw()) {
3857 case MUL:
3858 alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u());
3859 SetResult(rd_reg(), alu_out);
3860 // HI and LO are UNPREDICTABLE after the operation.
3861 set_register(LO, Unpredictable);
3862 set_register(HI, Unpredictable);
3863 break;
3864 case CLZ:
3865 // MIPS32 spec: If no bits were set in GPR rs(), the result written to
3866 // GPR rd is 32.
3867 alu_out = base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u()));
3868 SetResult(rd_reg(), alu_out);
3869 break;
3870 case DCLZ:
3871 // MIPS64 spec: If no bits were set in GPR rs(), the result written to
3872 // GPR rd is 64.
3873 alu_out = base::bits::CountLeadingZeros64(static_cast<uint64_t>(rs_u()));
3874 SetResult(rd_reg(), alu_out);
3875 break;
3876 default:
3877 alu_out = 0x12345678;
3878 UNREACHABLE();
3879 }
3880}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003881
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003882
3883void Simulator::DecodeTypeRegisterSPECIAL3() {
3884 int64_t alu_out;
3885 switch (get_instr()->FunctionFieldRaw()) {
3886 case INS: { // Mips64r2 instruction.
3887 // Interpret rd field as 5-bit msb of insert.
3888 uint16_t msb = rd_reg();
3889 // Interpret sa field as 5-bit lsb of insert.
3890 uint16_t lsb = sa();
3891 uint16_t size = msb - lsb + 1;
3892 uint64_t mask = (1ULL << size) - 1;
3893 alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) |
3894 ((rs_u() & mask) << lsb));
3895 SetResult(rt_reg(), alu_out);
3896 break;
3897 }
3898 case DINS: { // Mips64r2 instruction.
3899 // Interpret rd field as 5-bit msb of insert.
3900 uint16_t msb = rd_reg();
3901 // Interpret sa field as 5-bit lsb of insert.
3902 uint16_t lsb = sa();
3903 uint16_t size = msb - lsb + 1;
3904 uint64_t mask = (1ULL << size) - 1;
3905 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3906 SetResult(rt_reg(), alu_out);
3907 break;
3908 }
3909 case EXT: { // Mips64r2 instruction.
3910 // Interpret rd field as 5-bit msb of extract.
3911 uint16_t msb = rd_reg();
3912 // Interpret sa field as 5-bit lsb of extract.
3913 uint16_t lsb = sa();
3914 uint16_t size = msb + 1;
3915 uint64_t mask = (1ULL << size) - 1;
3916 alu_out = static_cast<int32_t>((rs_u() & (mask << lsb)) >> lsb);
3917 SetResult(rt_reg(), alu_out);
3918 break;
3919 }
3920 case DEXT: { // Mips64r2 instruction.
3921 // Interpret rd field as 5-bit msb of extract.
3922 uint16_t msb = rd_reg();
3923 // Interpret sa field as 5-bit lsb of extract.
3924 uint16_t lsb = sa();
3925 uint16_t size = msb + 1;
3926 uint64_t mask = (1ULL << size) - 1;
3927 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3928 SetResult(rt_reg(), alu_out);
3929 break;
3930 }
3931 case DEXTM: {
3932 // Interpret rd field as 5-bit msb of extract.
3933 uint16_t msb = rd_reg();
3934 // Interpret sa field as 5-bit lsb of extract.
3935 uint16_t lsb = sa();
3936 uint16_t size = msb + 33;
3937 uint64_t mask = (1ULL << size) - 1;
3938 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3939 SetResult(rt_reg(), alu_out);
3940 break;
3941 }
3942 case DEXTU: {
3943 // Interpret rd field as 5-bit msb of extract.
3944 uint16_t msb = rd_reg();
3945 // Interpret sa field as 5-bit lsb of extract.
3946 uint16_t lsb = sa() + 32;
3947 uint16_t size = msb + 1;
3948 uint64_t mask = (1ULL << size) - 1;
3949 alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb);
3950 SetResult(rt_reg(), alu_out);
3951 break;
3952 }
3953 case BSHFL: {
3954 int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
3955 switch (sa) {
3956 case BITSWAP: {
3957 uint32_t input = static_cast<uint32_t>(rt());
3958 uint32_t output = 0;
3959 uint8_t i_byte, o_byte;
3960
3961 // Reverse the bit in byte for each individual byte
3962 for (int i = 0; i < 4; i++) {
3963 output = output >> 8;
3964 i_byte = input & 0xff;
3965
3966 // Fast way to reverse bits in byte
3967 // Devised by Sean Anderson, July 13, 2001
3968 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3969 (i_byte * 0x8020LU & 0x88440LU)) *
3970 0x10101LU >>
3971 16);
3972
3973 output = output | (static_cast<uint32_t>(o_byte << 24));
3974 input = input >> 8;
3975 }
3976
3977 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
3978 break;
3979 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01003980 case SEB: {
3981 uint8_t input = static_cast<uint8_t>(rt());
3982 uint32_t output = input;
3983 uint32_t mask = 0x00000080;
3984
3985 // Extending sign
3986 if (mask & input) {
3987 output |= 0xFFFFFF00;
3988 }
3989
3990 alu_out = static_cast<int32_t>(output);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003991 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01003992 }
3993 case SEH: {
3994 uint16_t input = static_cast<uint16_t>(rt());
3995 uint32_t output = input;
3996 uint32_t mask = 0x00008000;
3997
3998 // Extending sign
3999 if (mask & input) {
4000 output |= 0xFFFF0000;
4001 }
4002
4003 alu_out = static_cast<int32_t>(output);
4004 break;
4005 }
4006 case WSBH: {
4007 uint32_t input = static_cast<uint32_t>(rt());
4008 uint64_t output = 0;
4009
4010 uint32_t mask = 0xFF000000;
4011 for (int i = 0; i < 4; i++) {
4012 uint32_t tmp = mask & input;
4013 if (i % 2 == 0) {
4014 tmp = tmp >> 8;
4015 } else {
4016 tmp = tmp << 8;
4017 }
4018 output = output | tmp;
4019 mask = mask >> 8;
4020 }
4021 mask = 0x80000000;
4022
4023 // Extending sign
4024 if (mask & output) {
4025 output |= 0xFFFFFFFF00000000;
4026 }
4027
4028 alu_out = static_cast<int64_t>(output);
4029 break;
4030 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004031 default: {
4032 const uint8_t bp2 = get_instr()->Bp2Value();
4033 sa >>= kBp2Bits;
4034 switch (sa) {
4035 case ALIGN: {
4036 if (bp2 == 0) {
4037 alu_out = static_cast<int32_t>(rt());
4038 } else {
4039 uint64_t rt_hi = rt() << (8 * bp2);
4040 uint64_t rs_lo = rs() >> (8 * (4 - bp2));
4041 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
4042 }
4043 break;
4044 }
4045 default:
4046 alu_out = 0x12345678;
4047 UNREACHABLE();
4048 break;
4049 }
4050 break;
4051 }
4052 }
4053 SetResult(rd_reg(), alu_out);
4054 break;
4055 }
4056 case DBSHFL: {
4057 int32_t sa = get_instr()->SaFieldRaw() >> kSaShift;
4058 switch (sa) {
4059 case DBITSWAP: {
4060 switch (sa) {
4061 case DBITSWAP_SA: { // Mips64r6
4062 uint64_t input = static_cast<uint64_t>(rt());
4063 uint64_t output = 0;
4064 uint8_t i_byte, o_byte;
4065
4066 // Reverse the bit in byte for each individual byte
4067 for (int i = 0; i < 8; i++) {
4068 output = output >> 8;
4069 i_byte = input & 0xff;
4070
4071 // Fast way to reverse bits in byte
4072 // Devised by Sean Anderson, July 13, 2001
4073 o_byte =
4074 static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4075 (i_byte * 0x8020LU & 0x88440LU)) *
4076 0x10101LU >>
4077 16);
4078
4079 output = output | ((static_cast<uint64_t>(o_byte) << 56));
4080 input = input >> 8;
4081 }
4082
4083 alu_out = static_cast<int64_t>(output);
4084 break;
4085 }
4086 }
4087 break;
4088 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01004089 case DSBH: {
4090 uint64_t input = static_cast<uint64_t>(rt());
4091 uint64_t output = 0;
4092
4093 uint64_t mask = 0xFF00000000000000;
4094 for (int i = 0; i < 8; i++) {
4095 uint64_t tmp = mask & input;
4096 if (i % 2 == 0)
4097 tmp = tmp >> 8;
4098 else
4099 tmp = tmp << 8;
4100
4101 output = output | tmp;
4102 mask = mask >> 8;
4103 }
4104
4105 alu_out = static_cast<int64_t>(output);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004106 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01004107 }
4108 case DSHD: {
4109 uint64_t input = static_cast<uint64_t>(rt());
4110 uint64_t output = 0;
4111
4112 uint64_t mask = 0xFFFF000000000000;
4113 for (int i = 0; i < 4; i++) {
4114 uint64_t tmp = mask & input;
4115 if (i == 0)
4116 tmp = tmp >> 48;
4117 else if (i == 1)
4118 tmp = tmp >> 16;
4119 else if (i == 2)
4120 tmp = tmp << 16;
4121 else
4122 tmp = tmp << 48;
4123 output = output | tmp;
4124 mask = mask >> 16;
4125 }
4126
4127 alu_out = static_cast<int64_t>(output);
4128 break;
4129 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004130 default: {
4131 const uint8_t bp3 = get_instr()->Bp3Value();
4132 sa >>= kBp3Bits;
4133 switch (sa) {
4134 case DALIGN: {
4135 if (bp3 == 0) {
4136 alu_out = static_cast<int64_t>(rt());
4137 } else {
4138 uint64_t rt_hi = rt() << (8 * bp3);
4139 uint64_t rs_lo = rs() >> (8 * (8 - bp3));
4140 alu_out = static_cast<int64_t>(rt_hi | rs_lo);
4141 }
4142 break;
4143 }
4144 default:
4145 alu_out = 0x12345678;
4146 UNREACHABLE();
4147 break;
4148 }
4149 break;
4150 }
4151 }
4152 SetResult(rd_reg(), alu_out);
4153 break;
4154 }
4155 default:
4156 UNREACHABLE();
4157 }
4158}
4159
4160
4161void Simulator::DecodeTypeRegister(Instruction* instr) {
4162 set_instr(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004163
4164 // ---------- Execution.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004165 switch (instr->OpcodeFieldRaw()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004166 case COP1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004167 DecodeTypeRegisterCOP1();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004168 break;
4169 case COP1X:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004170 DecodeTypeRegisterCOP1X();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004171 break;
4172 case SPECIAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004173 DecodeTypeRegisterSPECIAL();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004174 break;
4175 case SPECIAL2:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004176 DecodeTypeRegisterSPECIAL2();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004177 break;
4178 case SPECIAL3:
Ben Murdoch61f157c2016-09-16 13:49:30 +01004179 DecodeTypeRegisterSPECIAL3();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004180 break;
4181 // Unimplemented opcodes raised an error in the configuration step before,
4182 // so we can use the default here to set the destination register in common
4183 // cases.
4184 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004185 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004186 }
4187}
4188
4189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004190// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004191void Simulator::DecodeTypeImmediate(Instruction* instr) {
4192 // Instruction fields.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004193 Opcode op = instr->OpcodeFieldRaw();
4194 int32_t rs_reg = instr->RsValue();
4195 int64_t rs = get_register(instr->RsValue());
4196 uint64_t rs_u = static_cast<uint64_t>(rs);
4197 int32_t rt_reg = instr->RtValue(); // Destination register.
4198 int64_t rt = get_register(rt_reg);
4199 int16_t imm16 = instr->Imm16Value();
4200 int32_t imm18 = instr->Imm18Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004202 int32_t ft_reg = instr->FtValue(); // Destination register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004203
4204 // Zero extended immediate.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004205 uint64_t oe_imm16 = 0xffff & imm16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004206 // Sign extended immediate.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004207 int64_t se_imm16 = imm16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004208 int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004209
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004210 // Next pc.
4211 int64_t next_pc = bad_ra;
4212
4213 // Used for conditional branch instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004214 bool execute_branch_delay_instruction = false;
4215
4216 // Used for arithmetic instructions.
4217 int64_t alu_out = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004218
4219 // Used for memory instructions.
4220 int64_t addr = 0x0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004221 // Alignment for 32-bit integers used in LWL, LWR, etc.
4222 const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
Ben Murdochc5610432016-08-08 18:44:38 +01004223 // Alignment for 64-bit integers used in LDL, LDR, etc.
4224 const int kInt64AlignmentMask = sizeof(uint64_t) - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004225
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004226 // Branch instructions common part.
4227 auto BranchAndLinkHelper = [this, instr, &next_pc,
4228 &execute_branch_delay_instruction](
4229 bool do_branch) {
4230 execute_branch_delay_instruction = true;
4231 int64_t current_pc = get_pc();
4232 if (do_branch) {
4233 int16_t imm16 = instr->Imm16Value();
4234 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4235 set_register(31, current_pc + 2 * Instruction::kInstrSize);
4236 } else {
4237 next_pc = current_pc + 2 * Instruction::kInstrSize;
4238 }
4239 };
4240
4241 auto BranchHelper = [this, instr, &next_pc,
4242 &execute_branch_delay_instruction](bool do_branch) {
4243 execute_branch_delay_instruction = true;
4244 int64_t current_pc = get_pc();
4245 if (do_branch) {
4246 int16_t imm16 = instr->Imm16Value();
4247 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
4248 } else {
4249 next_pc = current_pc + 2 * Instruction::kInstrSize;
4250 }
4251 };
4252
4253 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
4254 int bits) {
4255 int64_t current_pc = get_pc();
4256 CheckForbiddenSlot(current_pc);
4257 if (do_branch) {
4258 int32_t imm = instr->ImmValue(bits);
4259 imm <<= 32 - bits;
4260 imm >>= 32 - bits;
4261 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
4262 set_register(31, current_pc + Instruction::kInstrSize);
4263 }
4264 };
4265
4266 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
4267 int64_t current_pc = get_pc();
4268 CheckForbiddenSlot(current_pc);
4269 if (do_branch) {
4270 int32_t imm = instr->ImmValue(bits);
4271 imm <<= 32 - bits;
4272 imm >>= 32 - bits;
4273 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
4274 }
4275 };
4276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004277 switch (op) {
4278 // ------------- COP1. Coprocessor instructions.
4279 case COP1:
4280 switch (instr->RsFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004281 case BC1: { // Branch on coprocessor condition.
4282 uint32_t cc = instr->FBccValue();
4283 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4284 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
4285 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
4286 BranchHelper(do_branch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004287 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004288 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004289 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004290 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004291 break;
4292 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004293 BranchHelper(get_fpu_register(ft_reg) & 0x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004294 break;
4295 default:
4296 UNREACHABLE();
4297 }
4298 break;
4299 // ------------- REGIMM class.
4300 case REGIMM:
4301 switch (instr->RtFieldRaw()) {
4302 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004303 BranchHelper(rs < 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004304 break;
4305 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004306 BranchHelper(rs >= 0);
4307 break;
4308 case BLTZAL:
4309 BranchAndLinkHelper(rs < 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004310 break;
4311 case BGEZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004312 BranchAndLinkHelper(rs >= 0);
4313 break;
4314 case DAHI:
4315 SetResult(rs_reg, rs + (se_imm16 << 32));
4316 break;
4317 case DATI:
4318 SetResult(rs_reg, rs + (se_imm16 << 48));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004319 break;
4320 default:
4321 UNREACHABLE();
4322 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004323 break; // case REGIMM.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004324 // ------------- Branch instructions.
4325 // When comparing to zero, the encoding of rt field is always 0, so we don't
4326 // need to replace rt with zero.
4327 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004328 BranchHelper(rs == rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004329 break;
4330 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004331 BranchHelper(rs != rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004332 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004333 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4334 if (kArchVariant == kMips64r6) {
4335 if (rt_reg != 0) {
4336 if (rs_reg == 0) { // BLEZALC
4337 BranchAndLinkCompactHelper(rt <= 0, 16);
4338 } else {
4339 if (rs_reg == rt_reg) { // BGEZALC
4340 BranchAndLinkCompactHelper(rt >= 0, 16);
4341 } else { // BGEUC
4342 BranchCompactHelper(
4343 static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16);
4344 }
4345 }
4346 } else { // BLEZ
4347 BranchHelper(rs <= 0);
4348 }
4349 } else { // BLEZ
4350 BranchHelper(rs <= 0);
4351 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004352 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004353 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4354 if (kArchVariant == kMips64r6) {
4355 if (rt_reg != 0) {
4356 if (rs_reg == 0) { // BGTZALC
4357 BranchAndLinkCompactHelper(rt > 0, 16);
4358 } else {
4359 if (rt_reg == rs_reg) { // BLTZALC
4360 BranchAndLinkCompactHelper(rt < 0, 16);
4361 } else { // BLTUC
4362 BranchCompactHelper(
4363 static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16);
4364 }
4365 }
4366 } else { // BGTZ
4367 BranchHelper(rs > 0);
4368 }
4369 } else { // BGTZ
4370 BranchHelper(rs > 0);
4371 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004372 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004373 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4374 if (kArchVariant == kMips64r6) {
4375 if (rt_reg != 0) {
4376 if (rs_reg == 0) { // BLEZC
4377 BranchCompactHelper(rt <= 0, 16);
4378 } else {
4379 if (rs_reg == rt_reg) { // BGEZC
4380 BranchCompactHelper(rt >= 0, 16);
4381 } else { // BGEC/BLEC
4382 BranchCompactHelper(rs >= rt, 16);
4383 }
4384 }
4385 }
4386 } else { // BLEZL
4387 BranchAndLinkHelper(rs <= 0);
4388 }
4389 break;
4390 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4391 if (kArchVariant == kMips64r6) {
4392 if (rt_reg != 0) {
4393 if (rs_reg == 0) { // BGTZC
4394 BranchCompactHelper(rt > 0, 16);
4395 } else {
4396 if (rs_reg == rt_reg) { // BLTZC
4397 BranchCompactHelper(rt < 0, 16);
4398 } else { // BLTC/BGTC
4399 BranchCompactHelper(rs < rt, 16);
4400 }
4401 }
4402 }
4403 } else { // BGTZL
4404 BranchAndLinkHelper(rs > 0);
4405 }
4406 break;
4407 case POP66: // BEQZC, JIC
4408 if (rs_reg != 0) { // BEQZC
4409 BranchCompactHelper(rs == 0, 21);
4410 } else { // JIC
4411 next_pc = rt + imm16;
4412 }
4413 break;
4414 case POP76: // BNEZC, JIALC
4415 if (rs_reg != 0) { // BNEZC
4416 BranchCompactHelper(rs != 0, 21);
4417 } else { // JIALC
4418 int64_t current_pc = get_pc();
4419 set_register(31, current_pc + Instruction::kInstrSize);
4420 next_pc = rt + imm16;
4421 }
4422 break;
4423 case BC:
4424 BranchCompactHelper(true, 26);
4425 break;
4426 case BALC:
4427 BranchAndLinkCompactHelper(true, 26);
4428 break;
4429 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4430 if (kArchVariant == kMips64r6) {
4431 if (rs_reg >= rt_reg) { // BOVC
Ben Murdochda12d292016-06-02 14:46:10 +01004432 bool condition = !is_int32(rs) || !is_int32(rt) || !is_int32(rs + rt);
4433 BranchCompactHelper(condition, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004434 } else {
4435 if (rs_reg == 0) { // BEQZALC
4436 BranchAndLinkCompactHelper(rt == 0, 16);
4437 } else { // BEQC
4438 BranchCompactHelper(rt == rs, 16);
4439 }
4440 }
4441 } else { // ADDI
4442 if (HaveSameSign(rs, se_imm16)) {
4443 if (rs > 0) {
4444 if (rs <= Registers::kMaxValue - se_imm16) {
4445 SignalException(kIntegerOverflow);
4446 }
4447 } else if (rs < 0) {
4448 if (rs >= Registers::kMinValue - se_imm16) {
4449 SignalException(kIntegerUnderflow);
4450 }
4451 }
4452 }
4453 SetResult(rt_reg, rs + se_imm16);
4454 }
4455 break;
4456 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4457 if (kArchVariant == kMips64r6) {
4458 if (rs_reg >= rt_reg) { // BNVC
Ben Murdochda12d292016-06-02 14:46:10 +01004459 bool condition = is_int32(rs) && is_int32(rt) && is_int32(rs + rt);
4460 BranchCompactHelper(condition, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004461 } else {
4462 if (rs_reg == 0) { // BNEZALC
4463 BranchAndLinkCompactHelper(rt != 0, 16);
4464 } else { // BNEC
4465 BranchCompactHelper(rt != rs, 16);
4466 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004467 }
4468 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004469 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004470 // ------------- Arithmetic instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004471 case ADDIU: {
Ben Murdochc5610432016-08-08 18:44:38 +01004472 DCHECK(is_int32(rs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004473 int32_t alu32_out = static_cast<int32_t>(rs + se_imm16);
4474 // Sign-extend result of 32bit operation into 64bit register.
4475 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004476 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004477 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004478 case DADDIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004479 SetResult(rt_reg, rs + se_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004480 break;
4481 case SLTI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004482 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004483 break;
4484 case SLTIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004485 SetResult(rt_reg, rs_u < static_cast<uint64_t>(se_imm16) ? 1 : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004486 break;
4487 case ANDI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004488 SetResult(rt_reg, rs & oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004489 break;
4490 case ORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004491 SetResult(rt_reg, rs | oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004492 break;
4493 case XORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004494 SetResult(rt_reg, rs ^ oe_imm16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004495 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004496 case LUI:
4497 if (rs_reg != 0) {
4498 // AUI instruction.
4499 DCHECK(kArchVariant == kMips64r6);
4500 int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16));
4501 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
4502 } else {
4503 // LUI instruction.
4504 int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004505 // Sign-extend result of 32bit operation into 64bit register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004506 SetResult(rt_reg, static_cast<int64_t>(alu32_out));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004507 }
4508 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004509 case DAUI:
4510 DCHECK(kArchVariant == kMips64r6);
4511 DCHECK(rs_reg != 0);
4512 SetResult(rt_reg, rs + (se_imm16 << 16));
4513 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004514 // ------------- Memory instructions.
4515 case LB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004516 set_register(rt_reg, ReadB(rs + se_imm16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004517 break;
4518 case LH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004519 set_register(rt_reg, ReadH(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004520 break;
4521 case LWL: {
4522 // al_offset is offset of the effective address within an aligned word.
4523 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4524 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4525 uint32_t mask = (1 << byte_shift * 8) - 1;
4526 addr = rs + se_imm16 - al_offset;
Ben Murdochc5610432016-08-08 18:44:38 +01004527 int32_t val = ReadW(addr, instr);
4528 val <<= byte_shift * 8;
4529 val |= rt & mask;
4530 set_register(rt_reg, static_cast<int64_t>(val));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004531 break;
4532 }
4533 case LW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004534 set_register(rt_reg, ReadW(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004535 break;
4536 case LWU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004537 set_register(rt_reg, ReadWU(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004538 break;
4539 case LD:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004540 set_register(rt_reg, Read2W(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004541 break;
4542 case LBU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004543 set_register(rt_reg, ReadBU(rs + se_imm16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004544 break;
4545 case LHU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004546 set_register(rt_reg, ReadHU(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004547 break;
4548 case LWR: {
4549 // al_offset is offset of the effective address within an aligned word.
4550 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4551 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4552 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4553 addr = rs + se_imm16 - al_offset;
4554 alu_out = ReadW(addr, instr);
4555 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4556 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004557 set_register(rt_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004558 break;
4559 }
Ben Murdochc5610432016-08-08 18:44:38 +01004560 case LDL: {
4561 // al_offset is offset of the effective address within an aligned word.
4562 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
4563 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
4564 uint64_t mask = (1UL << byte_shift * 8) - 1;
4565 addr = rs + se_imm16 - al_offset;
4566 alu_out = Read2W(addr, instr);
4567 alu_out <<= byte_shift * 8;
4568 alu_out |= rt & mask;
4569 set_register(rt_reg, alu_out);
4570 break;
4571 }
4572 case LDR: {
4573 // al_offset is offset of the effective address within an aligned word.
4574 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
4575 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
4576 uint64_t mask = al_offset ? (~0UL << (byte_shift + 1) * 8) : 0UL;
4577 addr = rs + se_imm16 - al_offset;
4578 alu_out = Read2W(addr, instr);
4579 alu_out = alu_out >> al_offset * 8;
4580 alu_out |= rt & mask;
4581 set_register(rt_reg, alu_out);
4582 break;
4583 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004584 case SB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004585 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004586 break;
4587 case SH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004588 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004589 break;
4590 case SWL: {
4591 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4592 uint8_t byte_shift = kInt32AlignmentMask - al_offset;
4593 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4594 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004595 uint64_t mem_value = ReadW(addr, instr) & mask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004596 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004597 WriteW(addr, static_cast<int32_t>(mem_value), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004598 break;
4599 }
4600 case SW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004601 WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr);
4602 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004603 case SD:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004604 Write2W(rs + se_imm16, rt, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004605 break;
4606 case SWR: {
4607 uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
4608 uint32_t mask = (1 << al_offset * 8) - 1;
4609 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004610 uint64_t mem_value = ReadW(addr, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004611 mem_value = (rt << al_offset * 8) | (mem_value & mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004612 WriteW(addr, static_cast<int32_t>(mem_value), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004613 break;
4614 }
Ben Murdochc5610432016-08-08 18:44:38 +01004615 case SDL: {
4616 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
4617 uint8_t byte_shift = kInt64AlignmentMask - al_offset;
4618 uint64_t mask = byte_shift ? (~0UL << (al_offset + 1) * 8) : 0;
4619 addr = rs + se_imm16 - al_offset;
4620 uint64_t mem_value = Read2W(addr, instr) & mask;
4621 mem_value |= rt >> byte_shift * 8;
4622 Write2W(addr, mem_value, instr);
4623 break;
4624 }
4625 case SDR: {
4626 uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask;
4627 uint64_t mask = (1UL << al_offset * 8) - 1;
4628 addr = rs + se_imm16 - al_offset;
4629 uint64_t mem_value = Read2W(addr, instr);
4630 mem_value = (rt << al_offset * 8) | (mem_value & mask);
4631 Write2W(addr, mem_value, instr);
4632 break;
4633 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004634 case LWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004635 set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
4636 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004637 break;
4638 case LDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004639 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004640 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004641 case SWC1: {
4642 int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg));
4643 WriteW(rs + se_imm16, alu_out_32, instr);
4644 break;
4645 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004646 case SDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004647 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004648 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004649 // ------------- PC-Relative instructions.
4650 case PCREL: {
4651 // rt field: checking 5-bits.
4652 int32_t imm21 = instr->Imm21Value();
4653 int64_t current_pc = get_pc();
4654 uint8_t rt = (imm21 >> kImm16Bits);
4655 switch (rt) {
4656 case ALUIPC:
4657 addr = current_pc + (se_imm16 << 16);
4658 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4659 break;
4660 case AUIPC:
4661 alu_out = current_pc + (se_imm16 << 16);
4662 break;
4663 default: {
4664 int32_t imm19 = instr->Imm19Value();
4665 // rt field: checking the most significant 3-bits.
4666 rt = (imm21 >> kImm18Bits);
4667 switch (rt) {
4668 case LDPC:
4669 addr =
4670 (current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
4671 alu_out = Read2W(addr, instr);
4672 break;
4673 default: {
4674 // rt field: checking the most significant 2-bits.
4675 rt = (imm21 >> kImm19Bits);
4676 switch (rt) {
4677 case LWUPC: {
4678 // Set sign.
4679 imm19 <<= (kOpcodeBits + kRsBits + 2);
4680 imm19 >>= (kOpcodeBits + kRsBits + 2);
4681 addr = current_pc + (imm19 << 2);
4682 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4683 alu_out = *ptr;
4684 break;
4685 }
4686 case LWPC: {
4687 // Set sign.
4688 imm19 <<= (kOpcodeBits + kRsBits + 2);
4689 imm19 >>= (kOpcodeBits + kRsBits + 2);
4690 addr = current_pc + (imm19 << 2);
4691 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
4692 alu_out = *ptr;
4693 break;
4694 }
4695 case ADDIUPC: {
4696 int64_t se_imm19 =
4697 imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
4698 alu_out = current_pc + (se_imm19 << 2);
4699 break;
4700 }
4701 default:
4702 UNREACHABLE();
4703 break;
4704 }
4705 break;
4706 }
4707 }
4708 break;
4709 }
4710 }
4711 set_register(rs_reg, alu_out);
4712 break;
4713 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004714 default:
4715 UNREACHABLE();
4716 }
4717
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004718 if (execute_branch_delay_instruction) {
4719 // Execute branch delay slot
4720 // We don't check for end_sim_pc. First it should not be met as the current
4721 // pc is valid. Secondly a jump should always execute its branch delay slot.
4722 Instruction* branch_delay_instr =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004723 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004724 BranchDelayInstructionDecode(branch_delay_instr);
4725 }
4726
4727 // If needed update pc after the branch delay execution.
4728 if (next_pc != bad_ra) {
4729 set_pc(next_pc);
4730 }
4731}
4732
4733
4734// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
4735void Simulator::DecodeTypeJump(Instruction* instr) {
4736 // Get current pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004737 int64_t current_pc = get_pc();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004738 // Get unchanged bits of pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004739 int64_t pc_high_bits = current_pc & 0xfffffffff0000000;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004740 // Next pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004741 int64_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004742
4743 // Execute branch delay slot.
4744 // We don't check for end_sim_pc. First it should not be met as the current pc
4745 // is valid. Secondly a jump should always execute its branch delay slot.
4746 Instruction* branch_delay_instr =
4747 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
4748 BranchDelayInstructionDecode(branch_delay_instr);
4749
4750 // Update pc and ra if necessary.
4751 // Do this after the branch delay execution.
4752 if (instr->IsLinkingInstruction()) {
4753 set_register(31, current_pc + 2 * Instruction::kInstrSize);
4754 }
4755 set_pc(next_pc);
4756 pc_modified_ = true;
4757}
4758
4759
4760// Executes the current instruction.
4761void Simulator::InstructionDecode(Instruction* instr) {
4762 if (v8::internal::FLAG_check_icache) {
4763 CheckICache(isolate_->simulator_i_cache(), instr);
4764 }
4765 pc_modified_ = false;
4766
4767 v8::internal::EmbeddedVector<char, 256> buffer;
4768
4769 if (::v8::internal::FLAG_trace_sim) {
4770 SNPrintF(trace_buf_, " ");
4771 disasm::NameConverter converter;
4772 disasm::Disassembler dasm(converter);
4773 // Use a reasonably large buffer.
4774 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
4775 }
4776
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004777 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004778 case Instruction::kRegisterType:
4779 DecodeTypeRegister(instr);
4780 break;
4781 case Instruction::kImmediateType:
4782 DecodeTypeImmediate(instr);
4783 break;
4784 case Instruction::kJumpType:
4785 DecodeTypeJump(instr);
4786 break;
4787 default:
4788 UNSUPPORTED();
4789 }
4790
4791 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01004792 PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
4793 reinterpret_cast<intptr_t>(instr), buffer.start(),
4794 trace_buf_.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004795 }
4796
4797 if (!pc_modified_) {
4798 set_register(pc, reinterpret_cast<int64_t>(instr) +
4799 Instruction::kInstrSize);
4800 }
4801}
4802
4803
4804
4805void Simulator::Execute() {
4806 // Get the PC to simulate. Cannot use the accessor here as we need the
4807 // raw PC value and not the one used as input to arithmetic instructions.
4808 int64_t program_counter = get_pc();
4809 if (::v8::internal::FLAG_stop_sim_at == 0) {
4810 // Fast version of the dispatch loop without checking whether the simulator
4811 // should be stopping at a particular executed instruction.
4812 while (program_counter != end_sim_pc) {
4813 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4814 icount_++;
4815 InstructionDecode(instr);
4816 program_counter = get_pc();
4817 }
4818 } else {
4819 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4820 // we reach the particular instuction count.
4821 while (program_counter != end_sim_pc) {
4822 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4823 icount_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004824 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004825 MipsDebugger dbg(this);
4826 dbg.Debug();
4827 } else {
4828 InstructionDecode(instr);
4829 }
4830 program_counter = get_pc();
4831 }
4832 }
4833}
4834
4835
4836void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004837 // Adjust JS-based stack limit to C-based stack limit.
4838 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4839
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004840 // Prepare to execute the code at entry.
4841 set_register(pc, reinterpret_cast<int64_t>(entry));
4842 // Put down marker for end of simulation. The simulator will stop simulation
4843 // when the PC reaches this value. By saving the "end simulation" value into
4844 // the LR the simulation stops when returning to this call point.
4845 set_register(ra, end_sim_pc);
4846
4847 // Remember the values of callee-saved registers.
4848 // The code below assumes that r9 is not used as sb (static base) in
4849 // simulator code and therefore is regarded as a callee-saved register.
4850 int64_t s0_val = get_register(s0);
4851 int64_t s1_val = get_register(s1);
4852 int64_t s2_val = get_register(s2);
4853 int64_t s3_val = get_register(s3);
4854 int64_t s4_val = get_register(s4);
4855 int64_t s5_val = get_register(s5);
4856 int64_t s6_val = get_register(s6);
4857 int64_t s7_val = get_register(s7);
4858 int64_t gp_val = get_register(gp);
4859 int64_t sp_val = get_register(sp);
4860 int64_t fp_val = get_register(fp);
4861
4862 // Set up the callee-saved registers with a known value. To be able to check
4863 // that they are preserved properly across JS execution.
4864 int64_t callee_saved_value = icount_;
4865 set_register(s0, callee_saved_value);
4866 set_register(s1, callee_saved_value);
4867 set_register(s2, callee_saved_value);
4868 set_register(s3, callee_saved_value);
4869 set_register(s4, callee_saved_value);
4870 set_register(s5, callee_saved_value);
4871 set_register(s6, callee_saved_value);
4872 set_register(s7, callee_saved_value);
4873 set_register(gp, callee_saved_value);
4874 set_register(fp, callee_saved_value);
4875
4876 // Start the simulation.
4877 Execute();
4878
4879 // Check that the callee-saved registers have been preserved.
4880 CHECK_EQ(callee_saved_value, get_register(s0));
4881 CHECK_EQ(callee_saved_value, get_register(s1));
4882 CHECK_EQ(callee_saved_value, get_register(s2));
4883 CHECK_EQ(callee_saved_value, get_register(s3));
4884 CHECK_EQ(callee_saved_value, get_register(s4));
4885 CHECK_EQ(callee_saved_value, get_register(s5));
4886 CHECK_EQ(callee_saved_value, get_register(s6));
4887 CHECK_EQ(callee_saved_value, get_register(s7));
4888 CHECK_EQ(callee_saved_value, get_register(gp));
4889 CHECK_EQ(callee_saved_value, get_register(fp));
4890
4891 // Restore callee-saved registers with the original value.
4892 set_register(s0, s0_val);
4893 set_register(s1, s1_val);
4894 set_register(s2, s2_val);
4895 set_register(s3, s3_val);
4896 set_register(s4, s4_val);
4897 set_register(s5, s5_val);
4898 set_register(s6, s6_val);
4899 set_register(s7, s7_val);
4900 set_register(gp, gp_val);
4901 set_register(sp, sp_val);
4902 set_register(fp, fp_val);
4903}
4904
4905
4906int64_t Simulator::Call(byte* entry, int argument_count, ...) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004907 const int kRegisterPassedArguments = 8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004908 va_list parameters;
4909 va_start(parameters, argument_count);
4910 // Set up arguments.
4911
4912 // First four arguments passed in registers in both ABI's.
4913 DCHECK(argument_count >= 4);
4914 set_register(a0, va_arg(parameters, int64_t));
4915 set_register(a1, va_arg(parameters, int64_t));
4916 set_register(a2, va_arg(parameters, int64_t));
4917 set_register(a3, va_arg(parameters, int64_t));
4918
Ben Murdoch097c5b22016-05-18 11:27:45 +01004919 // Up to eight arguments passed in registers in N64 ABI.
4920 // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this.
4921 if (argument_count >= 5) set_register(a4, va_arg(parameters, int64_t));
4922 if (argument_count >= 6) set_register(a5, va_arg(parameters, int64_t));
4923 if (argument_count >= 7) set_register(a6, va_arg(parameters, int64_t));
4924 if (argument_count >= 8) set_register(a7, va_arg(parameters, int64_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004925
4926 // Remaining arguments passed on stack.
4927 int64_t original_stack = get_register(sp);
4928 // Compute position of stack on entry to generated code.
4929 int stack_args_count = (argument_count > kRegisterPassedArguments) ?
4930 (argument_count - kRegisterPassedArguments) : 0;
4931 int stack_args_size = stack_args_count * sizeof(int64_t) + kCArgsSlotsSize;
4932 int64_t entry_stack = original_stack - stack_args_size;
4933
4934 if (base::OS::ActivationFrameAlignment() != 0) {
4935 entry_stack &= -base::OS::ActivationFrameAlignment();
4936 }
4937 // Store remaining arguments on stack, from low to high memory.
4938 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4939 for (int i = kRegisterPassedArguments; i < argument_count; i++) {
4940 int stack_index = i - kRegisterPassedArguments + kCArgSlotCount;
4941 stack_argument[stack_index] = va_arg(parameters, int64_t);
4942 }
4943 va_end(parameters);
4944 set_register(sp, entry_stack);
4945
4946 CallInternal(entry);
4947
4948 // Pop stack passed arguments.
4949 CHECK_EQ(entry_stack, get_register(sp));
4950 set_register(sp, original_stack);
4951
4952 int64_t result = get_register(v0);
4953 return result;
4954}
4955
4956
4957double Simulator::CallFP(byte* entry, double d0, double d1) {
4958 if (!IsMipsSoftFloatABI) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004959 const FPURegister fparg2 = f13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004960 set_fpu_register_double(f12, d0);
4961 set_fpu_register_double(fparg2, d1);
4962 } else {
4963 int buffer[2];
4964 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4965 memcpy(buffer, &d0, sizeof(d0));
4966 set_dw_register(a0, buffer);
4967 memcpy(buffer, &d1, sizeof(d1));
4968 set_dw_register(a2, buffer);
4969 }
4970 CallInternal(entry);
4971 if (!IsMipsSoftFloatABI) {
4972 return get_fpu_register_double(f0);
4973 } else {
4974 return get_double_from_register_pair(v0);
4975 }
4976}
4977
4978
4979uintptr_t Simulator::PushAddress(uintptr_t address) {
4980 int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
4981 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4982 *stack_slot = address;
4983 set_register(sp, new_sp);
4984 return new_sp;
4985}
4986
4987
4988uintptr_t Simulator::PopAddress() {
4989 int64_t current_sp = get_register(sp);
4990 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4991 uintptr_t address = *stack_slot;
4992 set_register(sp, current_sp + sizeof(uintptr_t));
4993 return address;
4994}
4995
4996
4997#undef UNSUPPORTED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004998} // namespace internal
4999} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005000
5001#endif // USE_SIMULATOR
5002
5003#endif // V8_TARGET_ARCH_MIPS64