v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
simulator-loong64.cc
Go to the documentation of this file.
1// Copyright 2021 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
6
7// Only build the simulator if not compiling for real LOONG64 hardware.
8#if defined(USE_SIMULATOR)
9
10#include <limits.h>
11#include <stdarg.h>
12#include <stdlib.h>
13
14#include <cmath>
15
16#include "src/base/bits.h"
19#include "src/base/strings.h"
20#include "src/base/vector.h"
27#include "src/utils/ostreams.h"
28
29#if V8_ENABLE_WEBASSEMBLY
31#endif // V8_ENABLE_WEBASSEMBLY
32
33namespace v8 {
34namespace internal {
35
36DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
37 Simulator::GlobalMonitor::Get)
38
39// #define PRINT_SIM_LOG
40
41// Util functions.
42inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); }
43
44uint32_t get_fcsr_condition_bit(uint32_t cc) {
45 if (cc == 0) {
46 return 23;
47 } else {
48 return 24 + cc;
49 }
50}
51
52#ifdef PRINT_SIM_LOG
53inline void printf_instr(const char* _Format, ...) {
54 va_list varList;
55 va_start(varList, _Format);
56 vprintf(_Format, varList);
57 va_end(varList);
58}
59#else
60#define printf_instr(...)
61#endif
62
63// This macro provides a platform independent use of sscanf. The reason for
64// SScanF not being implemented in a platform independent was through
65// ::v8::internal::OS in the same way as base::SNPrintF is that the Windows C
66// Run-Time Library does not provide vsscanf.
67#define SScanF sscanf
68
69// The Loong64Debugger class is used by the simulator while debugging simulated
70// code.
71class Loong64Debugger {
72 public:
73 explicit Loong64Debugger(Simulator* sim) : sim_(sim) {}
74
75 void Stop(Instruction* instr);
76 void Debug();
77 // Print all registers with a nice formatting.
78 void PrintAllRegs();
79 void PrintAllRegsIncludingFPU();
80
81 private:
82 // We set the breakpoint code to 0xFFFF to easily recognize it.
83 static const Instr kBreakpointInstr = BREAK | 0xFFFF;
84 static const Instr kNopInstr = 0x0;
85
86 Simulator* sim_;
87
88 int64_t GetRegisterValue(int regnum);
89 int64_t GetFPURegisterValue(int regnum);
90 float GetFPURegisterValueFloat(int regnum);
91 double GetFPURegisterValueDouble(int regnum);
92 bool GetValue(const char* desc, int64_t* value);
93
94 // Set or delete a breakpoint. Returns true if successful.
95 bool SetBreakpoint(Instruction* breakpc);
96 bool DeleteBreakpoint(Instruction* breakpc);
97
98 // Undo and redo all breakpoints. This is needed to bracket disassembly and
99 // execution to skip past breakpoints when run from the debugger.
100 void UndoBreakpoints();
101 void RedoBreakpoints();
102};
103
104inline void UNSUPPORTED() { printf("Sim: Unsupported instruction.\n"); }
105
106void Loong64Debugger::Stop(Instruction* instr) {
107 // Get the stop code.
108 uint32_t code = instr->Bits(25, 6);
109 PrintF("Simulator hit (%u)\n", code);
110 Debug();
111}
112
113int64_t Loong64Debugger::GetRegisterValue(int regnum) {
114 if (regnum == kNumSimuRegisters) {
115 return sim_->get_pc();
116 } else {
117 return sim_->get_register(regnum);
118 }
119}
120
121int64_t Loong64Debugger::GetFPURegisterValue(int regnum) {
122 if (regnum == kNumFPURegisters) {
123 return sim_->get_pc();
124 } else {
125 return sim_->get_fpu_register(regnum);
126 }
127}
128
129float Loong64Debugger::GetFPURegisterValueFloat(int regnum) {
130 if (regnum == kNumFPURegisters) {
131 return sim_->get_pc();
132 } else {
133 return sim_->get_fpu_register_float(regnum);
134 }
135}
136
137double Loong64Debugger::GetFPURegisterValueDouble(int regnum) {
138 if (regnum == kNumFPURegisters) {
139 return sim_->get_pc();
140 } else {
141 return sim_->get_fpu_register_double(regnum);
142 }
143}
144
145bool Loong64Debugger::GetValue(const char* desc, int64_t* value) {
146 int regnum = Registers::Number(desc);
147 int fpuregnum = FPURegisters::Number(desc);
148
149 if (regnum != kInvalidRegister) {
150 *value = GetRegisterValue(regnum);
151 return true;
152 } else if (fpuregnum != kInvalidFPURegister) {
153 *value = GetFPURegisterValue(fpuregnum);
154 return true;
155 } else if (strncmp(desc, "0x", 2) == 0) {
156 return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<uint64_t*>(value)) ==
157 1;
158 } else {
159 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
160 }
161}
162
163bool Loong64Debugger::SetBreakpoint(Instruction* breakpc) {
164 // Check if a breakpoint can be set. If not return without any side-effects.
165 if (sim_->break_pc_ != nullptr) {
166 return false;
167 }
168
169 // Set the breakpoint.
170 sim_->break_pc_ = breakpc;
171 sim_->break_instr_ = breakpc->InstructionBits();
172 // Not setting the breakpoint instruction in the code itself. It will be set
173 // when the debugger shell continues.
174 return true;
175}
176
177bool Loong64Debugger::DeleteBreakpoint(Instruction* breakpc) {
178 if (sim_->break_pc_ != nullptr) {
179 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
180 }
181
182 sim_->break_pc_ = nullptr;
183 sim_->break_instr_ = 0;
184 return true;
185}
186
187void Loong64Debugger::UndoBreakpoints() {
188 if (sim_->break_pc_ != nullptr) {
189 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
190 }
191}
192
193void Loong64Debugger::RedoBreakpoints() {
194 if (sim_->break_pc_ != nullptr) {
195 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
196 }
197}
198
199void Loong64Debugger::PrintAllRegs() {
200#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
201
202 PrintF("\n");
203 // at, v0, a0.
204 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64
205 "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n",
206 REG_INFO(1), REG_INFO(2), REG_INFO(4));
207 // v1, a1.
208 PrintF("%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
209 " %14" PRId64 " \n",
210 "", REG_INFO(3), REG_INFO(5));
211 // a2.
212 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
213 REG_INFO(6));
214 // a3.
215 PrintF("%34s\t%34s\t%3s: 0x%016" PRIx64 " %14" PRId64 " \n", "", "",
216 REG_INFO(7));
217 PrintF("\n");
218 // a4-t3, s0-s7
219 for (int i = 0; i < 8; i++) {
220 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
221 " %14" PRId64 " \n",
222 REG_INFO(8 + i), REG_INFO(16 + i));
223 }
224 PrintF("\n");
225 // t8, k0, LO.
226 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
227 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
228 REG_INFO(24), REG_INFO(26), REG_INFO(32));
229 // t9, k1, HI.
230 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
231 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
232 REG_INFO(25), REG_INFO(27), REG_INFO(33));
233 // sp, fp, gp.
234 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
235 " %14" PRId64 " \t%3s: 0x%016" PRIx64 " %14" PRId64 " \n",
236 REG_INFO(29), REG_INFO(30), REG_INFO(28));
237 // pc.
238 PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64
239 " %14" PRId64 " \n",
240 REG_INFO(31), REG_INFO(34));
241
242#undef REG_INFO
243}
244
245void Loong64Debugger::PrintAllRegsIncludingFPU() {
246#define FPU_REG_INFO(n) \
247 FPURegisters::Name(n), GetFPURegisterValue(n), GetFPURegisterValueDouble(n)
248
249 PrintAllRegs();
250
251 PrintF("\n\n");
252 // f0, f1, f2, ... f31.
253 // TODO(plind): consider printing 2 columns for space efficiency.
254 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(0));
255 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(1));
256 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(2));
257 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(3));
258 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(4));
259 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(5));
260 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(6));
261 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(7));
262 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(8));
263 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(9));
264 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(10));
265 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(11));
266 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(12));
267 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(13));
268 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(14));
269 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(15));
270 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(16));
271 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(17));
272 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(18));
273 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(19));
274 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(20));
275 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(21));
276 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(22));
277 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(23));
278 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(24));
279 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(25));
280 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(26));
281 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(27));
282 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(28));
283 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(29));
284 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(30));
285 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", FPU_REG_INFO(31));
286
287#undef FPU_REG_INFO
288}
289
290void Loong64Debugger::Debug() {
291 if (v8_flags.correctness_fuzzer_suppressions) {
292 PrintF("Debugger disabled for differential fuzzing.\n");
293 return;
294 }
295 intptr_t last_pc = -1;
296 bool done = false;
297
298#define COMMAND_SIZE 63
299#define ARG_SIZE 255
300
301#define STR(a) #a
302#define XSTR(a) STR(a)
303
304 char cmd[COMMAND_SIZE + 1];
305 char arg1[ARG_SIZE + 1];
306 char arg2[ARG_SIZE + 1];
307 char* argv[3] = {cmd, arg1, arg2};
308
309 // Make sure to have a proper terminating character if reaching the limit.
310 cmd[COMMAND_SIZE] = 0;
311 arg1[ARG_SIZE] = 0;
312 arg2[ARG_SIZE] = 0;
313
314 // Undo all set breakpoints while running in the debugger shell. This will
315 // make them invisible to all commands.
316 UndoBreakpoints();
317
318 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
319 if (last_pc != sim_->get_pc()) {
320 disasm::NameConverter converter;
321 disasm::Disassembler dasm(converter);
322 // Use a reasonably large buffer.
324 dasm.InstructionDecode(buffer,
325 reinterpret_cast<uint8_t*>(sim_->get_pc()));
326 PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.begin());
327 last_pc = sim_->get_pc();
328 }
329 char* line = ReadLine("sim> ");
330 if (line == nullptr) {
331 break;
332 } else {
333 char* last_input = sim_->last_debugger_input();
334 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
335 line = last_input;
336 } else {
337 // Ownership is transferred to sim_;
338 sim_->set_last_debugger_input(line);
339 }
340 // Use sscanf to parse the individual parts of the command line. At the
341 // moment no command expects more than two parameters.
342 int argc = SScanF(line,
343 "%" XSTR(COMMAND_SIZE) "s "
344 "%" XSTR(ARG_SIZE) "s "
345 "%" XSTR(ARG_SIZE) "s",
346 cmd, arg1, arg2);
347 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
348 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
349 if (!(instr->IsTrap()) ||
351 sim_->InstructionDecode(
352 reinterpret_cast<Instruction*>(sim_->get_pc()));
353 } else {
354 // Allow si to jump over generated breakpoints.
355 PrintF("/!\\ Jumping over generated breakpoint.\n");
356 sim_->set_pc(sim_->get_pc() + kInstrSize);
357 }
358 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
359 // Execute the one instruction we broke at with breakpoints disabled.
360 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
361 // Leave the debugger shell.
362 done = true;
363 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
364 if (argc == 2) {
365 int64_t value;
366 double dvalue;
367 if (strcmp(arg1, "all") == 0) {
368 PrintAllRegs();
369 } else if (strcmp(arg1, "allf") == 0) {
370 PrintAllRegsIncludingFPU();
371 } else {
372 int regnum = Registers::Number(arg1);
373 int fpuregnum = FPURegisters::Number(arg1);
374
375 if (regnum != kInvalidRegister) {
376 value = GetRegisterValue(regnum);
377 PrintF("%s: 0x%08" PRIx64 " %" PRId64 " \n", arg1, value,
378 value);
379 } else if (fpuregnum != kInvalidFPURegister) {
380 value = GetFPURegisterValue(fpuregnum);
381 dvalue = GetFPURegisterValueDouble(fpuregnum);
382 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n",
383 FPURegisters::Name(fpuregnum), value, dvalue);
384 } else {
385 PrintF("%s unrecognized\n", arg1);
386 }
387 }
388 } else {
389 if (argc == 3) {
390 if (strcmp(arg2, "single") == 0) {
391 int64_t value;
392 float fvalue;
393 int fpuregnum = FPURegisters::Number(arg1);
394
395 if (fpuregnum != kInvalidFPURegister) {
396 value = GetFPURegisterValue(fpuregnum);
397 value &= 0xFFFFFFFFUL;
398 fvalue = GetFPURegisterValueFloat(fpuregnum);
399 PrintF("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue);
400 } else {
401 PrintF("%s unrecognized\n", arg1);
402 }
403 } else {
404 PrintF("print <fpu register> single\n");
405 }
406 } else {
407 PrintF("print <register> or print <fpu register> single\n");
408 }
409 }
410 } else if ((strcmp(cmd, "po") == 0) ||
411 (strcmp(cmd, "printobject") == 0)) {
412 if (argc == 2) {
413 int64_t value;
414 StdoutStream os;
415 if (GetValue(arg1, &value)) {
416 Tagged<Object> obj(value);
417 os << arg1 << ": \n";
418#ifdef DEBUG
419 Print(obj, os);
420 os << "\n";
421#else
422 os << Brief(obj) << "\n";
423#endif
424 } else {
425 os << arg1 << " unrecognized\n";
426 }
427 } else {
428 PrintF("printobject <value>\n");
429 }
430 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
431 strcmp(cmd, "dump") == 0) {
432 int64_t* cur = nullptr;
433 int64_t* end = nullptr;
434 int next_arg = 1;
435
436 if (strcmp(cmd, "stack") == 0) {
437 cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
438 } else { // Command "mem".
439 int64_t value;
440 if (!GetValue(arg1, &value)) {
441 PrintF("%s unrecognized\n", arg1);
442 continue;
443 }
444 cur = reinterpret_cast<int64_t*>(value);
445 next_arg++;
446 }
447
448 int64_t words;
449 if (argc == next_arg) {
450 words = 10;
451 } else {
452 if (!GetValue(argv[next_arg], &words)) {
453 words = 10;
454 }
455 }
456 end = cur + words;
457
458 bool skip_obj_print = (strcmp(cmd, "dump") == 0);
459 while (cur < end) {
460 PrintF(" 0x%012" PRIxPTR " : 0x%016" PRIx64 " %14" PRId64 " ",
461 reinterpret_cast<intptr_t>(cur), *cur, *cur);
462 Tagged<Object> obj(*cur);
463 Heap* current_heap = sim_->isolate_->heap();
464 if (!skip_obj_print) {
465 if (IsSmi(obj) ||
466 IsValidHeapObject(current_heap, Cast<HeapObject>(obj))) {
467 PrintF(" (");
468 if (IsSmi(obj)) {
469 PrintF("smi %d", Smi::ToInt(obj));
470 } else {
471 ShortPrint(obj);
472 }
473 PrintF(")");
474 }
475 }
476 PrintF("\n");
477 cur++;
478 }
479
480 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
481 (strcmp(cmd, "di") == 0)) {
482 disasm::NameConverter converter;
483 disasm::Disassembler dasm(converter);
484 // Use a reasonably large buffer.
486
487 uint8_t* cur = nullptr;
488 uint8_t* end = nullptr;
489
490 if (argc == 1) {
491 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
492 end = cur + (10 * kInstrSize);
493 } else if (argc == 2) {
494 int regnum = Registers::Number(arg1);
495 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
496 // The argument is an address or a register name.
497 int64_t value;
498 if (GetValue(arg1, &value)) {
499 cur = reinterpret_cast<uint8_t*>(value);
500 // Disassemble 10 instructions at <arg1>.
501 end = cur + (10 * kInstrSize);
502 }
503 } else {
504 // The argument is the number of instructions.
505 int64_t value;
506 if (GetValue(arg1, &value)) {
507 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
508 // Disassemble <arg1> instructions.
509 end = cur + (value * kInstrSize);
510 }
511 }
512 } else {
513 int64_t value1;
514 int64_t value2;
515 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
516 cur = reinterpret_cast<uint8_t*>(value1);
517 end = cur + (value2 * kInstrSize);
518 }
519 }
520
521 while (cur < end) {
522 dasm.InstructionDecode(buffer, cur);
523 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
524 buffer.begin());
525 cur += kInstrSize;
526 }
527 } else if (strcmp(cmd, "gdb") == 0) {
528 PrintF("relinquishing control to gdb\n");
530 PrintF("regaining control from gdb\n");
531 } else if (strcmp(cmd, "break") == 0) {
532 if (argc == 2) {
533 int64_t value;
534 if (GetValue(arg1, &value)) {
535 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
536 PrintF("setting breakpoint failed\n");
537 }
538 } else {
539 PrintF("%s unrecognized\n", arg1);
540 }
541 } else {
542 PrintF("break <address>\n");
543 }
544 } else if (strcmp(cmd, "del") == 0) {
545 if (!DeleteBreakpoint(nullptr)) {
546 PrintF("deleting breakpoint failed\n");
547 }
548 } else if (strcmp(cmd, "flags") == 0) {
549 PrintF("No flags on LOONG64 !\n");
550 } else if (strcmp(cmd, "stop") == 0) {
551 int64_t value;
552 intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
553 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
554 Instruction* msg_address =
555 reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
556 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
557 // Remove the current stop.
558 if (sim_->IsStopInstruction(stop_instr)) {
559 stop_instr->SetInstructionBits(kNopInstr);
560 msg_address->SetInstructionBits(kNopInstr);
561 } else {
562 PrintF("Not at debugger stop.\n");
563 }
564 } else if (argc == 3) {
565 // Print information about all/the specified breakpoint(s).
566 if (strcmp(arg1, "info") == 0) {
567 if (strcmp(arg2, "all") == 0) {
568 PrintF("Stop information:\n");
569 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
570 i++) {
571 sim_->PrintStopInfo(i);
572 }
573 } else if (GetValue(arg2, &value)) {
574 sim_->PrintStopInfo(value);
575 } else {
576 PrintF("Unrecognized argument.\n");
577 }
578 } else if (strcmp(arg1, "enable") == 0) {
579 // Enable all/the specified breakpoint(s).
580 if (strcmp(arg2, "all") == 0) {
581 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
582 i++) {
583 sim_->EnableStop(i);
584 }
585 } else if (GetValue(arg2, &value)) {
586 sim_->EnableStop(value);
587 } else {
588 PrintF("Unrecognized argument.\n");
589 }
590 } else if (strcmp(arg1, "disable") == 0) {
591 // Disable all/the specified breakpoint(s).
592 if (strcmp(arg2, "all") == 0) {
593 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
594 i++) {
595 sim_->DisableStop(i);
596 }
597 } else if (GetValue(arg2, &value)) {
598 sim_->DisableStop(value);
599 } else {
600 PrintF("Unrecognized argument.\n");
601 }
602 }
603 } else {
604 PrintF("Wrong usage. Use help command for more information.\n");
605 }
606 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
607 // Print registers and disassemble.
608 PrintAllRegs();
609 PrintF("\n");
610
611 disasm::NameConverter converter;
612 disasm::Disassembler dasm(converter);
613 // Use a reasonably large buffer.
615
616 uint8_t* cur = nullptr;
617 uint8_t* end = nullptr;
618
619 if (argc == 1) {
620 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
621 end = cur + (10 * kInstrSize);
622 } else if (argc == 2) {
623 int64_t value;
624 if (GetValue(arg1, &value)) {
625 cur = reinterpret_cast<uint8_t*>(value);
626 // no length parameter passed, assume 10 instructions
627 end = cur + (10 * kInstrSize);
628 }
629 } else {
630 int64_t value1;
631 int64_t value2;
632 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
633 cur = reinterpret_cast<uint8_t*>(value1);
634 end = cur + (value2 * kInstrSize);
635 }
636 }
637
638 while (cur < end) {
639 dasm.InstructionDecode(buffer, cur);
640 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
641 buffer.begin());
642 cur += kInstrSize;
643 }
644 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
645 PrintF("cont\n");
646 PrintF(" continue execution (alias 'c')\n");
647 PrintF("stepi\n");
648 PrintF(" step one instruction (alias 'si')\n");
649 PrintF("print <register>\n");
650 PrintF(" print register content (alias 'p')\n");
651 PrintF(" use register name 'all' to print all registers\n");
652 PrintF("printobject <register>\n");
653 PrintF(" print an object from a register (alias 'po')\n");
654 PrintF("stack [<words>]\n");
655 PrintF(" dump stack content, default dump 10 words)\n");
656 PrintF("mem <address> [<words>]\n");
657 PrintF(" dump memory content, default dump 10 words)\n");
658 PrintF("dump [<words>]\n");
659 PrintF(
660 " dump memory content without pretty printing JS objects, default "
661 "dump 10 words)\n");
662 PrintF("flags\n");
663 PrintF(" print flags\n");
664 PrintF("disasm [<instructions>]\n");
665 PrintF("disasm [<address/register>]\n");
666 PrintF("disasm [[<address/register>] <instructions>]\n");
667 PrintF(" disassemble code, default is 10 instructions\n");
668 PrintF(" from pc (alias 'di')\n");
669 PrintF("gdb\n");
670 PrintF(" enter gdb\n");
671 PrintF("break <address>\n");
672 PrintF(" set a break point on the address\n");
673 PrintF("del\n");
674 PrintF(" delete the breakpoint\n");
675 PrintF("stop feature:\n");
676 PrintF(" Description:\n");
677 PrintF(" Stops are debug instructions inserted by\n");
678 PrintF(" the Assembler::stop() function.\n");
679 PrintF(" When hitting a stop, the Simulator will\n");
680 PrintF(" stop and give control to the Debugger.\n");
681 PrintF(" All stop codes are watched:\n");
682 PrintF(" - They can be enabled / disabled: the Simulator\n");
683 PrintF(" will / won't stop when hitting them.\n");
684 PrintF(" - The Simulator keeps track of how many times they \n");
685 PrintF(" are met. (See the info command.) Going over a\n");
686 PrintF(" disabled stop still increases its counter. \n");
687 PrintF(" Commands:\n");
688 PrintF(" stop info all/<code> : print infos about number <code>\n");
689 PrintF(" or all stop(s).\n");
690 PrintF(" stop enable/disable all/<code> : enables / disables\n");
691 PrintF(" all or number <code> stop(s)\n");
692 PrintF(" stop unstop\n");
693 PrintF(" ignore the stop instruction at the current location\n");
694 PrintF(" from now on\n");
695 } else {
696 PrintF("Unknown command: %s\n", cmd);
697 }
698 }
699 }
700
701 // Add all the breakpoints back to stop execution and enter the debugger
702 // shell when hit.
703 RedoBreakpoints();
704
705#undef COMMAND_SIZE
706#undef ARG_SIZE
707
708#undef STR
709#undef XSTR
710}
711
712bool Simulator::ICacheMatch(void* one, void* two) {
713 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
714 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
715 return one == two;
716}
717
718static uint32_t ICacheHash(void* key) {
719 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
720}
721
722static bool AllOnOnePage(uintptr_t start, size_t size) {
723 intptr_t start_page = (start & ~CachePage::kPageMask);
724 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
725 return start_page == end_page;
726}
727
728void Simulator::set_last_debugger_input(char* input) {
729 DeleteArray(last_debugger_input_);
730 last_debugger_input_ = input;
731}
732
733void Simulator::SetRedirectInstruction(Instruction* instruction) {
734 instruction->SetInstructionBits(rtCallRedirInstr);
735}
736
737void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
738 void* start_addr, size_t size) {
739 int64_t start = reinterpret_cast<int64_t>(start_addr);
740 int64_t intra_line = (start & CachePage::kLineMask);
741 start -= intra_line;
742 size += intra_line;
743 size = ((size - 1) | CachePage::kLineMask) + 1;
744 int offset = (start & CachePage::kPageMask);
745 while (!AllOnOnePage(start, size - 1)) {
746 int bytes_to_flush = CachePage::kPageSize - offset;
747 FlushOnePage(i_cache, start, bytes_to_flush);
748 start += bytes_to_flush;
749 size -= bytes_to_flush;
750 DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
751 offset = 0;
752 }
753 if (size != 0) {
754 FlushOnePage(i_cache, start, size);
755 }
756}
757
758CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
759 void* page) {
760 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
761 if (entry->value == nullptr) {
762 CachePage* new_page = new CachePage();
763 entry->value = new_page;
764 }
765 return reinterpret_cast<CachePage*>(entry->value);
766}
767
768// Flush from start up to and not including start + size.
769void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
770 intptr_t start, size_t size) {
771 DCHECK_LE(size, CachePage::kPageSize);
772 DCHECK(AllOnOnePage(start, size - 1));
773 DCHECK_EQ(start & CachePage::kLineMask, 0);
774 DCHECK_EQ(size & CachePage::kLineMask, 0);
775 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
776 int offset = (start & CachePage::kPageMask);
777 CachePage* cache_page = GetCachePage(i_cache, page);
778 char* valid_bytemap = cache_page->ValidityByte(offset);
779 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
780}
781
782void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
783 Instruction* instr) {
784 int64_t address = reinterpret_cast<int64_t>(instr);
785 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
786 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
787 int offset = (address & CachePage::kPageMask);
788 CachePage* cache_page = GetCachePage(i_cache, page);
789 char* cache_valid_byte = cache_page->ValidityByte(offset);
790 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
791 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
792 if (cache_hit) {
793 // Check that the data in memory matches the contents of the I-cache.
794 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
795 cache_page->CachedData(offset), kInstrSize));
796 } else {
797 // Cache miss. Load memory into the cache.
798 memcpy(cached_line, line, CachePage::kLineLength);
799 *cache_valid_byte = CachePage::LINE_VALID;
800 }
801}
802
803Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
804 // Set up simulator support first. Some of this information is needed to
805 // setup the architecture state.
806 size_t stack_size = AllocatedStackSize();
807 stack_ = reinterpret_cast<uintptr_t>(new uint8_t[stack_size]);
808 stack_limit_ = stack_ + kStackProtectionSize;
809 pc_modified_ = false;
810 icount_ = 0;
811 break_count_ = 0;
812 break_pc_ = nullptr;
813 break_instr_ = 0;
814
815 // Set up architecture state.
816 // All registers are initialized to zero to start with.
817 for (int i = 0; i < kNumSimuRegisters; i++) {
818 registers_[i] = 0;
819 }
820 for (int i = 0; i < kNumFPURegisters; i++) {
821 FPUregisters_[i] = 0;
822 }
823 for (int i = 0; i < kNumCFRegisters; i++) {
824 CFregisters_[i] = 0;
825 }
826
827 FCSR_ = 0;
828
829 // The sp is initialized to point to the bottom (high address) of the
830 // allocated stack area. To be safe in potential stack underflows we leave
831 // some buffer below.
832 registers_[sp] = StackBase();
833 // The ra and pc are initialized to a known bad value that will cause an
834 // access violation if the simulator ever tries to execute it.
835 registers_[pc] = bad_ra;
836 registers_[ra] = bad_ra;
837
838 last_debugger_input_ = nullptr;
839}
840
841Simulator::~Simulator() {
842 GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
843 delete[] reinterpret_cast<uint8_t*>(stack_);
844}
845
846// Get the active Simulator for the current thread.
847Simulator* Simulator::current(Isolate* isolate) {
849 isolate->FindOrAllocatePerThreadDataForThisThread();
850 DCHECK_NOT_NULL(isolate_data);
851
852 Simulator* sim = isolate_data->simulator();
853 if (sim == nullptr) {
854 // TODO(146): delete the simulator object when a thread/isolate goes away.
855 sim = new Simulator(isolate);
856 isolate_data->set_simulator(sim);
857 }
858 return sim;
859}
860
861#define FloatPoint_Covert_F32(func) \
862 float Simulator::func(float value) { \
863 float result = std::func(value); \
864 if (std::isnan(result)) { \
865 uint32_t q_nan, nan; \
866 nan = *reinterpret_cast<uint32_t*>(&result); \
867 q_nan = nan | 0x400000; \
868 *reinterpret_cast<uint32_t*>(&result) = q_nan; \
869 } \
870 return result; \
871 }
872#define FloatPoint_Covert_F64(func) \
873 FloatPoint_Covert_F32(func) \
874 double Simulator::func(double value) { \
875 double result = std::func(value); \
876 if (std::isnan(result)) { \
877 uint64_t q_nan, nan; \
878 nan = *reinterpret_cast<uint64_t*>(&value); \
879 q_nan = nan | 0x8000000000000; \
880 *reinterpret_cast<uint64_t*>(&result) = q_nan; \
881 } \
882 return result; \
883 }
884
885FloatPoint_Covert_F64(ceil)
886FloatPoint_Covert_F64(floor)
887FloatPoint_Covert_F64(trunc)
888#undef FloatPoint_Covert_F32
889#undef FloatPoint_Covert_F64
890
891// Sets the register in the architecture state. It will also deal with updating
892// Simulator internal state for special registers such as PC.
893void Simulator::set_register(int reg, int64_t value) {
894 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
895 if (reg == pc) {
896 pc_modified_ = true;
897 }
898
899 // Zero register always holds 0.
900 registers_[reg] = (reg == 0) ? 0 : value;
901}
902
903void Simulator::set_dw_register(int reg, const int* dbl) {
904 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
905 registers_[reg] = dbl[1];
906 registers_[reg] = registers_[reg] << 32;
907 registers_[reg] += dbl[0];
908}
909
910void Simulator::set_fpu_register(int fpureg, int64_t value) {
911 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
912 FPUregisters_[fpureg] = value;
913}
914
915void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
916 // Set ONLY lower 32-bits, leaving upper bits untouched.
917 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
918 int32_t* pword;
919 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
920
921 *pword = value;
922}
923
924void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
925 // Set ONLY upper 32-bits, leaving lower bits untouched.
926 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
927 int32_t* phiword;
928 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
929
930 *phiword = value;
931}
932
933void Simulator::set_fpu_register_float(int fpureg, float value) {
934 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
935 memcpy(&FPUregisters_[fpureg], &value, sizeof(value));
936}
937
938void Simulator::set_fpu_register_double(int fpureg, double value) {
939 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
940 memcpy(&FPUregisters_[fpureg], &value, sizeof(value));
941}
942
943void Simulator::set_cf_register(int cfreg, bool value) {
944 DCHECK((cfreg >= 0) && (cfreg < kNumCFRegisters));
945 CFregisters_[cfreg] = value;
946}
947
948// Get the register from the architecture state. This function does handle
949// the special case of accessing the PC register.
950int64_t Simulator::get_register(int reg) const {
951 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
952 if (reg == 0)
953 return 0;
954 else
955 return registers_[reg];
956}
957
958double Simulator::get_double_from_register_pair(int reg) {
959 // TODO(plind): bad ABI stuff, refactor or remove.
960 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
961
962 double dm_val = 0.0;
963 // Read the bits from the unsigned integer register_[] array
964 // into the double precision floating point value and return it.
965 char buffer[sizeof(registers_[0])];
966 memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
967 memcpy(&dm_val, buffer, sizeof(registers_[0]));
968 return (dm_val);
969}
970
971int64_t Simulator::get_fpu_register(int fpureg) const {
972 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
973 return FPUregisters_[fpureg];
974}
975
976int32_t Simulator::get_fpu_register_word(int fpureg) const {
977 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
978 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
979}
980
981int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
982 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
983 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
984}
985
986int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
987 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
988 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xFFFFFFFF);
989}
990
991float Simulator::get_fpu_register_float(int fpureg) const {
992 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
993 return base::bit_cast<float>(get_fpu_register_word(fpureg));
994}
995
996double Simulator::get_fpu_register_double(int fpureg) const {
997 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
998 return base::bit_cast<double>(FPUregisters_[fpureg]);
999}
1000
1001bool Simulator::get_cf_register(int cfreg) const {
1002 DCHECK((cfreg >= 0) && (cfreg < kNumCFRegisters));
1003 return CFregisters_[cfreg];
1004}
1005
1006// Runtime FP routines take up to two double arguments and zero
1007// or one integer arguments. All are constructed here,
1008// from a0-a3 or fa0 and fa1 (n64).
1009void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1010 const int fparg2 = f1;
1011 *x = get_fpu_register_double(f0);
1012 *y = get_fpu_register_double(fparg2);
1013 *z = static_cast<int32_t>(get_register(a2));
1014}
1015
1016// The return value is either in v0/v1 or f0.
1017void Simulator::SetFpResult(const double& result) {
1018 set_fpu_register_double(0, result);
1019}
1020
1021// Helper functions for setting and testing the FCSR register's bits.
1022void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1023 if (value) {
1024 FCSR_ |= (1 << cc);
1025 } else {
1026 FCSR_ &= ~(1 << cc);
1027 }
1028}
1029
1030bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
1031
1032void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1033 FCSR_ |= mode & kFPURoundingModeMask;
1034}
1035
1036unsigned int Simulator::get_fcsr_rounding_mode() {
1037 return FCSR_ & kFPURoundingModeMask;
1038}
1039
1040// Sets the rounding error codes in FCSR based on the result of the rounding.
1041// Returns true if the operation was invalid.
1042bool Simulator::set_fcsr_round_error(double original, double rounded) {
1043 bool ret = false;
1044 double max_int32 = std::numeric_limits<int32_t>::max();
1045 double min_int32 = std::numeric_limits<int32_t>::min();
1046 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1047 set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1048 set_fcsr_bit(kFCSROverflowCauseBit, false);
1049 set_fcsr_bit(kFCSRInexactCauseBit, false);
1050
1051 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1052 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1053 ret = true;
1054 }
1055
1056 if (original != rounded) {
1057 set_fcsr_bit(kFCSRInexactCauseBit, true);
1058 }
1059
1060 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1061 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1062 ret = true;
1063 }
1064
1065 if (rounded > max_int32 || rounded < min_int32) {
1066 set_fcsr_bit(kFCSROverflowCauseBit, true);
1067 // The reference is not really clear but it seems this is required:
1068 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1069 ret = true;
1070 }
1071
1072 return ret;
1073}
1074
1075// Sets the rounding error codes in FCSR based on the result of the rounding.
1076// Returns true if the operation was invalid.
1077bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1078 bool ret = false;
1079 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1080 // loading the most accurate representation into max_int64, which is 2^63.
1081 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1082 double min_int64 = std::numeric_limits<int64_t>::min();
1083 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1084 set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1085 set_fcsr_bit(kFCSROverflowCauseBit, false);
1086 set_fcsr_bit(kFCSRInexactCauseBit, false);
1087
1088 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1089 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1090 ret = true;
1091 }
1092
1093 if (original != rounded) {
1094 set_fcsr_bit(kFCSRInexactCauseBit, true);
1095 }
1096
1097 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1098 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1099 ret = true;
1100 }
1101
1102 if (rounded >= max_int64 || rounded < min_int64) {
1103 set_fcsr_bit(kFCSROverflowCauseBit, true);
1104 // The reference is not really clear but it seems this is required:
1105 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1106 ret = true;
1107 }
1108
1109 return ret;
1110}
1111
1112// Sets the rounding error codes in FCSR based on the result of the rounding.
1113// Returns true if the operation was invalid.
1114bool Simulator::set_fcsr_round_error(float original, float rounded) {
1115 bool ret = false;
1116 double max_int32 = std::numeric_limits<int32_t>::max();
1117 double min_int32 = std::numeric_limits<int32_t>::min();
1118 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1119 set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1120 set_fcsr_bit(kFCSROverflowCauseBit, false);
1121 set_fcsr_bit(kFCSRInexactCauseBit, false);
1122
1123 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1124 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1125 ret = true;
1126 }
1127
1128 if (original != rounded) {
1129 set_fcsr_bit(kFCSRInexactCauseBit, true);
1130 }
1131
1132 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1133 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1134 ret = true;
1135 }
1136
1137 if (rounded > max_int32 || rounded < min_int32) {
1138 set_fcsr_bit(kFCSROverflowCauseBit, true);
1139 // The reference is not really clear but it seems this is required:
1140 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1141 ret = true;
1142 }
1143
1144 return ret;
1145}
1146
1147void Simulator::set_fpu_register_word_invalid_result(float original,
1148 float rounded) {
1149 double max_int32 = std::numeric_limits<int32_t>::max();
1150 double min_int32 = std::numeric_limits<int32_t>::min();
1151 if (std::isnan(original)) {
1152 set_fpu_register_word(fd_reg(), 0);
1153 } else if (rounded > max_int32) {
1154 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1155 } else if (rounded < min_int32) {
1156 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1157 } else {
1158 UNREACHABLE();
1159 }
1160}
1161
1162void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1163 double max_int32 = std::numeric_limits<int32_t>::max();
1164 double min_int32 = std::numeric_limits<int32_t>::min();
1165 if (std::isnan(original)) {
1166 set_fpu_register(fd_reg(), 0);
1167 } else if (rounded > max_int32) {
1168 set_fpu_register(fd_reg(), kFPUInvalidResult);
1169 } else if (rounded < min_int32) {
1170 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1171 } else {
1172 UNREACHABLE();
1173 }
1174}
1175
1176void Simulator::set_fpu_register_invalid_result64(float original,
1177 float rounded) {
1178 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1179 // loading the most accurate representation into max_int64, which is 2^63.
1180 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1181 double min_int64 = std::numeric_limits<int64_t>::min();
1182 if (std::isnan(original)) {
1183 set_fpu_register(fd_reg(), 0);
1184 } else if (rounded >= max_int64) {
1185 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1186 } else if (rounded < min_int64) {
1187 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1188 } else {
1189 UNREACHABLE();
1190 }
1191}
1192
1193void Simulator::set_fpu_register_word_invalid_result(double original,
1194 double rounded) {
1195 double max_int32 = std::numeric_limits<int32_t>::max();
1196 double min_int32 = std::numeric_limits<int32_t>::min();
1197 if (std::isnan(original)) {
1198 set_fpu_register_word(fd_reg(), 0);
1199 } else if (rounded > max_int32) {
1200 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1201 } else if (rounded < min_int32) {
1202 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1203 } else {
1204 UNREACHABLE();
1205 }
1206}
1207
1208void Simulator::set_fpu_register_invalid_result(double original,
1209 double rounded) {
1210 double max_int32 = std::numeric_limits<int32_t>::max();
1211 double min_int32 = std::numeric_limits<int32_t>::min();
1212 if (std::isnan(original)) {
1213 set_fpu_register(fd_reg(), 0);
1214 } else if (rounded > max_int32) {
1215 set_fpu_register(fd_reg(), kFPUInvalidResult);
1216 } else if (rounded < min_int32) {
1217 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1218 } else {
1219 UNREACHABLE();
1220 }
1221}
1222
1223void Simulator::set_fpu_register_invalid_result64(double original,
1224 double rounded) {
1225 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1226 // loading the most accurate representation into max_int64, which is 2^63.
1227 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1228 double min_int64 = std::numeric_limits<int64_t>::min();
1229 if (std::isnan(original)) {
1230 set_fpu_register(fd_reg(), 0);
1231 } else if (rounded >= max_int64) {
1232 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1233 } else if (rounded < min_int64) {
1234 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1235 } else {
1236 UNREACHABLE();
1237 }
1238}
1239
1240// Sets the rounding error codes in FCSR based on the result of the rounding.
1241// Returns true if the operation was invalid.
1242bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1243 bool ret = false;
1244 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1245 // loading the most accurate representation into max_int64, which is 2^63.
1246 double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1247 double min_int64 = std::numeric_limits<int64_t>::min();
1248 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
1249 set_fcsr_bit(kFCSRUnderflowCauseBit, false);
1250 set_fcsr_bit(kFCSROverflowCauseBit, false);
1251 set_fcsr_bit(kFCSRInexactCauseBit, false);
1252
1253 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1254 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1255 ret = true;
1256 }
1257
1258 if (original != rounded) {
1259 set_fcsr_bit(kFCSRInexactCauseBit, true);
1260 }
1261
1262 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1263 set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1264 ret = true;
1265 }
1266
1267 if (rounded >= max_int64 || rounded < min_int64) {
1268 set_fcsr_bit(kFCSROverflowCauseBit, true);
1269 // The reference is not really clear but it seems this is required:
1270 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1271 ret = true;
1272 }
1273
1274 return ret;
1275}
1276
1277// For ftint instructions only
1278void Simulator::round_according_to_fcsr(double toRound, double* rounded,
1279 int32_t* rounded_int) {
1280 // 0 RN (round to nearest): Round a result to the nearest
1281 // representable value; if the result is exactly halfway between
1282 // two representable values, round to zero.
1283
1284 // 1 RZ (round toward zero): Round a result to the closest
1285 // representable value whose absolute value is less than or
1286 // equal to the infinitely accurate result.
1287
1288 // 2 RP (round up, or toward +infinity): Round a result to the
1289 // next representable value up.
1290
1291 // 3 RN (round down, or toward −infinity): Round a result to
1292 // the next representable value down.
1293 // switch ((FCSR_ >> 8) & 3) {
1294 switch (FCSR_ & kFPURoundingModeMask) {
1295 case kRoundToNearest:
1296 *rounded = floor(toRound + 0.5);
1297 *rounded_int = static_cast<int32_t>(*rounded);
1298 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1299 // If the number is halfway between two integers,
1300 // round to the even one.
1301 *rounded_int -= 1;
1302 *rounded -= 1.;
1303 }
1304 break;
1305 case kRoundToZero:
1306 *rounded = trunc(toRound);
1307 *rounded_int = static_cast<int32_t>(*rounded);
1308 break;
1309 case kRoundToPlusInf:
1310 *rounded = ceil(toRound);
1311 *rounded_int = static_cast<int32_t>(*rounded);
1312 break;
1313 case kRoundToMinusInf:
1314 *rounded = floor(toRound);
1315 *rounded_int = static_cast<int32_t>(*rounded);
1316 break;
1317 }
1318}
1319
1320void Simulator::round64_according_to_fcsr(double toRound, double* rounded,
1321 int64_t* rounded_int) {
1322 // 0 RN (round to nearest): Round a result to the nearest
1323 // representable value; if the result is exactly halfway between
1324 // two representable values, round to zero.
1325
1326 // 1 RZ (round toward zero): Round a result to the closest
1327 // representable value whose absolute value is less than or.
1328 // equal to the infinitely accurate result.
1329
1330 // 2 RP (round up, or toward +infinity): Round a result to the
1331 // next representable value up.
1332
1333 // 3 RN (round down, or toward −infinity): Round a result to
1334 // the next representable value down.
1335 switch (FCSR_ & kFPURoundingModeMask) {
1336 case kRoundToNearest:
1337 *rounded = floor(toRound + 0.5);
1338 *rounded_int = static_cast<int64_t>(*rounded);
1339 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1340 // If the number is halfway between two integers,
1341 // round to the even one.
1342 *rounded_int -= 1;
1343 *rounded -= 1.;
1344 }
1345 break;
1346 case kRoundToZero:
1347 *rounded = trunc(toRound);
1348 *rounded_int = static_cast<int64_t>(*rounded);
1349 break;
1350 case kRoundToPlusInf:
1351 *rounded = ceil(toRound);
1352 *rounded_int = static_cast<int64_t>(*rounded);
1353 break;
1354 case kRoundToMinusInf:
1355 *rounded = floor(toRound);
1356 *rounded_int = static_cast<int64_t>(*rounded);
1357 break;
1358 }
1359}
1360
1361void Simulator::round_according_to_fcsr(float toRound, float* rounded,
1362 int32_t* rounded_int) {
1363 // 0 RN (round to nearest): Round a result to the nearest
1364 // representable value; if the result is exactly halfway between
1365 // two representable values, round to zero.
1366
1367 // 1 RZ (round toward zero): Round a result to the closest
1368 // representable value whose absolute value is less than or
1369 // equal to the infinitely accurate result.
1370
1371 // 2 RP (round up, or toward +infinity): Round a result to the
1372 // next representable value up.
1373
1374 // 3 RN (round down, or toward −infinity): Round a result to
1375 // the next representable value down.
1376 switch (FCSR_ & kFPURoundingModeMask) {
1377 case kRoundToNearest:
1378 *rounded = floor(toRound + 0.5);
1379 *rounded_int = static_cast<int32_t>(*rounded);
1380 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1381 // If the number is halfway between two integers,
1382 // round to the even one.
1383 *rounded_int -= 1;
1384 *rounded -= 1.f;
1385 }
1386 break;
1387 case kRoundToZero:
1388 *rounded = trunc(toRound);
1389 *rounded_int = static_cast<int32_t>(*rounded);
1390 break;
1391 case kRoundToPlusInf:
1392 *rounded = ceil(toRound);
1393 *rounded_int = static_cast<int32_t>(*rounded);
1394 break;
1395 case kRoundToMinusInf:
1396 *rounded = floor(toRound);
1397 *rounded_int = static_cast<int32_t>(*rounded);
1398 break;
1399 }
1400}
1401
1402void Simulator::round64_according_to_fcsr(float toRound, float* rounded,
1403 int64_t* rounded_int) {
1404 // 0 RN (round to nearest): Round a result to the nearest
1405 // representable value; if the result is exactly halfway between
1406 // two representable values, round to zero.
1407
1408 // 1 RZ (round toward zero): Round a result to the closest
1409 // representable value whose absolute value is less than or.
1410 // equal to the infinitely accurate result.
1411
1412 // 2 RP (round up, or toward +infinity): Round a result to the
1413 // next representable value up.
1414
1415 // 3 RN (round down, or toward −infinity): Round a result to
1416 // the next representable value down.
1417 switch (FCSR_ & kFPURoundingModeMask) {
1418 case kRoundToNearest:
1419 *rounded = floor(toRound + 0.5);
1420 *rounded_int = static_cast<int64_t>(*rounded);
1421 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1422 // If the number is halfway between two integers,
1423 // round to the even one.
1424 *rounded_int -= 1;
1425 *rounded -= 1.f;
1426 }
1427 break;
1428 case kRoundToZero:
1429 *rounded = trunc(toRound);
1430 *rounded_int = static_cast<int64_t>(*rounded);
1431 break;
1432 case kRoundToPlusInf:
1433 *rounded = ceil(toRound);
1434 *rounded_int = static_cast<int64_t>(*rounded);
1435 break;
1436 case kRoundToMinusInf:
1437 *rounded = floor(toRound);
1438 *rounded_int = static_cast<int64_t>(*rounded);
1439 break;
1440 }
1441}
1442
1443// Raw access to the PC register.
1444void Simulator::set_pc(int64_t value) {
1445 pc_modified_ = true;
1446 registers_[pc] = value;
1447}
1448
1449bool Simulator::has_bad_pc() const {
1450 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1451}
1452
1453// Raw access to the PC register without the special adjustment when reading.
1454int64_t Simulator::get_pc() const { return registers_[pc]; }
1455
1456// TODO(plind): refactor this messy debug code when we do unaligned access.
1457void Simulator::DieOrDebug() {
1458 if ((1)) { // Flag for this was removed.
1459 Loong64Debugger dbg(this);
1460 dbg.Debug();
1461 } else {
1462 base::OS::Abort();
1463 }
1464}
1465
1466void Simulator::TraceRegWr(int64_t value, TraceType t) {
1467 if (v8_flags.trace_sim) {
1468 union {
1469 int64_t fmt_int64;
1470 int32_t fmt_int32[2];
1471 float fmt_float[2];
1472 double fmt_double;
1473 } v;
1474 v.fmt_int64 = value;
1475
1476 switch (t) {
1477 case WORD:
1478 base::SNPrintF(trace_buf_,
1479 "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32
1480 " uint32:%" PRIu32,
1481 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]);
1482 break;
1483 case DWORD:
1484 base::SNPrintF(trace_buf_,
1485 "%016" PRIx64 " (%" PRId64 ") int64:%" PRId64
1486 " uint64:%" PRIu64,
1487 value, icount_, value, value);
1488 break;
1489 case FLOAT:
1490 base::SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") flt:%e",
1491 v.fmt_int64, icount_, v.fmt_float[0]);
1492 break;
1493 case DOUBLE:
1494 base::SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e",
1495 v.fmt_int64, icount_, v.fmt_double);
1496 break;
1497 case FLOAT_DOUBLE:
1498 base::SNPrintF(trace_buf_,
1499 "%016" PRIx64 " (%" PRId64 ") flt:%e dbl:%e",
1500 v.fmt_int64, icount_, v.fmt_float[0], v.fmt_double);
1501 break;
1502 case WORD_DWORD:
1503 base::SNPrintF(trace_buf_,
1504 "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32
1505 " uint32:%" PRIu32 " int64:%" PRId64 " uint64:%" PRIu64,
1506 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0],
1507 v.fmt_int64, v.fmt_int64);
1508 break;
1509 default:
1510 UNREACHABLE();
1511 }
1512 }
1513}
1514
1515// TODO(plind): consider making icount_ printing a flag option.
1516void Simulator::TraceMemRd(int64_t addr, int64_t value, TraceType t) {
1517 if (v8_flags.trace_sim) {
1518 union {
1519 int64_t fmt_int64;
1520 int32_t fmt_int32[2];
1521 float fmt_float[2];
1522 double fmt_double;
1523 } v;
1524 v.fmt_int64 = value;
1525
1526 switch (t) {
1527 case WORD:
1528 base::SNPrintF(trace_buf_,
1529 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1530 ") int32:%" PRId32 " uint32:%" PRIu32,
1531 v.fmt_int64, addr, icount_, v.fmt_int32[0],
1532 v.fmt_int32[0]);
1533 break;
1534 case DWORD:
1535 base::SNPrintF(trace_buf_,
1536 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1537 ") int64:%" PRId64 " uint64:%" PRIu64,
1538 value, addr, icount_, value, value);
1539 break;
1540 case FLOAT:
1541 base::SNPrintF(trace_buf_,
1542 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1543 ") flt:%e",
1544 v.fmt_int64, addr, icount_, v.fmt_float[0]);
1545 break;
1546 case DOUBLE:
1547 base::SNPrintF(trace_buf_,
1548 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1549 ") dbl:%e",
1550 v.fmt_int64, addr, icount_, v.fmt_double);
1551 break;
1552 case FLOAT_DOUBLE:
1553 base::SNPrintF(trace_buf_,
1554 "%016" PRIx64 " <-- [%016" PRIx64 "] (%" PRId64
1555 ") flt:%e dbl:%e",
1556 v.fmt_int64, addr, icount_, v.fmt_float[0],
1557 v.fmt_double);
1558 break;
1559 default:
1560 UNREACHABLE();
1561 }
1562 }
1563}
1564
1565void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
1566 if (v8_flags.trace_sim) {
1567 switch (t) {
1568 case BYTE:
1569 base::SNPrintF(trace_buf_,
1570 " %02" PRIx8 " --> [%016" PRIx64
1571 "] (%" PRId64 ")",
1572 static_cast<uint8_t>(value), addr, icount_);
1573 break;
1574 case HALF:
1575 base::SNPrintF(trace_buf_,
1576 " %04" PRIx16 " --> [%016" PRIx64
1577 "] (%" PRId64 ")",
1578 static_cast<uint16_t>(value), addr, icount_);
1579 break;
1580 case WORD:
1581 base::SNPrintF(trace_buf_,
1582 " %08" PRIx32 " --> [%016" PRIx64 "] (%" PRId64
1583 ")",
1584 static_cast<uint32_t>(value), addr, icount_);
1585 break;
1586 case DWORD:
1587 base::SNPrintF(trace_buf_,
1588 "%016" PRIx64 " --> [%016" PRIx64 "] (%" PRId64 " )",
1589 value, addr, icount_);
1590 break;
1591 default:
1592 UNREACHABLE();
1593 }
1594 }
1595}
1596
1597template <typename T>
1598void Simulator::TraceMemRd(int64_t addr, T value) {
1599 if (v8_flags.trace_sim) {
1600 switch (sizeof(T)) {
1601 case 1:
1602 base::SNPrintF(trace_buf_,
1603 "%08" PRIx8 " <-- [%08" PRIx64 "] (%" PRIu64
1604 ") int8:%" PRId8 " uint8:%" PRIu8,
1605 static_cast<uint8_t>(value), addr, icount_,
1606 static_cast<int8_t>(value), static_cast<uint8_t>(value));
1607 break;
1608 case 2:
1609 base::SNPrintF(trace_buf_,
1610 "%08" PRIx16 " <-- [%08" PRIx64 "] (%" PRIu64
1611 ") int16:%" PRId16 " uint16:%" PRIu16,
1612 static_cast<uint16_t>(value), addr, icount_,
1613 static_cast<int16_t>(value),
1614 static_cast<uint16_t>(value));
1615 break;
1616 case 4:
1617 base::SNPrintF(trace_buf_,
1618 "%08" PRIx32 " <-- [%08" PRIx64 "] (%" PRIu64
1619 ") int32:%" PRId32 " uint32:%" PRIu32,
1620 static_cast<uint32_t>(value), addr, icount_,
1621 static_cast<int32_t>(value),
1622 static_cast<uint32_t>(value));
1623 break;
1624 case 8:
1625 base::SNPrintF(trace_buf_,
1626 "%08" PRIx64 " <-- [%08" PRIx64 "] (%" PRIu64
1627 ") int64:%" PRId64 " uint64:%" PRIu64,
1628 static_cast<uint64_t>(value), addr, icount_,
1629 static_cast<int64_t>(value),
1630 static_cast<uint64_t>(value));
1631 break;
1632 default:
1633 UNREACHABLE();
1634 }
1635 }
1636}
1637
1638template <typename T>
1639void Simulator::TraceMemWr(int64_t addr, T value) {
1640 if (v8_flags.trace_sim) {
1641 switch (sizeof(T)) {
1642 case 1:
1643 base::SNPrintF(trace_buf_,
1644 " %02" PRIx8 " --> [%08" PRIx64 "] (%" PRIu64
1645 ")",
1646 static_cast<uint8_t>(value), addr, icount_);
1647 break;
1648 case 2:
1649 base::SNPrintF(trace_buf_,
1650 " %04" PRIx16 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1651 static_cast<uint16_t>(value), addr, icount_);
1652 break;
1653 case 4:
1654 base::SNPrintF(trace_buf_,
1655 "%08" PRIx32 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1656 static_cast<uint32_t>(value), addr, icount_);
1657 break;
1658 case 8:
1659 base::SNPrintF(trace_buf_,
1660 "%16" PRIx64 " --> [%08" PRIx64 "] (%" PRIu64 ")",
1661 static_cast<uint64_t>(value), addr, icount_);
1662 break;
1663 default:
1664 UNREACHABLE();
1665 }
1666 }
1667}
1668
1669bool Simulator::ProbeMemory(uintptr_t address, uintptr_t access_size) {
1670#if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
1671 uintptr_t last_accessed_byte = address + access_size - 1;
1672 uintptr_t current_pc = registers_[pc];
1673 uintptr_t landing_pad =
1674 trap_handler::ProbeMemory(last_accessed_byte, current_pc);
1675 if (!landing_pad) return true;
1676 set_pc(landing_pad);
1677 set_register(kWasmTrapHandlerFaultAddressRegister.code(), current_pc);
1678 return false;
1679#else
1680 return true;
1681#endif
1682}
1683
1684int32_t Simulator::ReadW(int64_t addr, Instruction* instr, TraceType t) {
1685 if (addr >= 0 && addr < 0x400) {
1686 // This has to be a nullptr-dereference, drop into debugger.
1687 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1688 " \n",
1689 addr, reinterpret_cast<intptr_t>(instr));
1690 DieOrDebug();
1691 }
1692
1693 {
1694 local_monitor_.NotifyLoad();
1695 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1696 TraceMemRd(addr, static_cast<int64_t>(*ptr), t);
1697 return *ptr;
1698 }
1699}
1700
1701uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) {
1702 if (addr >= 0 && addr < 0x400) {
1703 // This has to be a nullptr-dereference, drop into debugger.
1704 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1705 " \n",
1706 addr, reinterpret_cast<intptr_t>(instr));
1707 DieOrDebug();
1708 }
1709
1710 {
1711 local_monitor_.NotifyLoad();
1712 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1713 TraceMemRd(addr, static_cast<int64_t>(*ptr), WORD);
1714 return *ptr;
1715 }
1716}
1717
1718void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) {
1719 if (addr >= 0 && addr < 0x400) {
1720 // This has to be a nullptr-dereference, drop into debugger.
1721 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1722 " \n",
1723 addr, reinterpret_cast<intptr_t>(instr));
1724 DieOrDebug();
1725 }
1726
1727 {
1728 local_monitor_.NotifyStore();
1729 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1730 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1731 TraceMemWr(addr, value, WORD);
1732 int* ptr = reinterpret_cast<int*>(addr);
1733 *ptr = value;
1734 return;
1735 }
1736}
1737
1738void Simulator::WriteConditionalW(int64_t addr, int32_t value,
1739 Instruction* instr, int32_t* done) {
1740 if (addr >= 0 && addr < 0x400) {
1741 // This has to be a nullptr-dereference, drop into debugger.
1742 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1743 " \n",
1744 addr, reinterpret_cast<intptr_t>(instr));
1745 DieOrDebug();
1746 }
1747
1748 if ((addr & 0x3) == 0) {
1749 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1750 if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
1751 GlobalMonitor::Get()->NotifyStoreConditional_Locked(
1752 addr, &global_monitor_thread_)) {
1753 local_monitor_.NotifyStore();
1754 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1755 TraceMemWr(addr, value, WORD);
1756 int* ptr = reinterpret_cast<int*>(addr);
1757 *ptr = value;
1758 *done = 1;
1759 } else {
1760 *done = 0;
1761 }
1762 return;
1763 }
1764 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1765 reinterpret_cast<intptr_t>(instr));
1766 DieOrDebug();
1767}
1768
1769int64_t Simulator::Read2W(int64_t addr, Instruction* instr) {
1770 if (addr >= 0 && addr < 0x400) {
1771 // This has to be a nullptr-dereference, drop into debugger.
1772 PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1773 " \n",
1774 addr, reinterpret_cast<intptr_t>(instr));
1775 DieOrDebug();
1776 }
1777
1778 {
1779 local_monitor_.NotifyLoad();
1780 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1781 TraceMemRd(addr, *ptr);
1782 return *ptr;
1783 }
1784}
1785
1786void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) {
1787 if (addr >= 0 && addr < 0x400) {
1788 // This has to be a nullptr-dereference, drop into debugger.
1789 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1790 "\n",
1791 addr, reinterpret_cast<intptr_t>(instr));
1792 DieOrDebug();
1793 }
1794
1795 {
1796 local_monitor_.NotifyStore();
1797 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1798 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1799 TraceMemWr(addr, value, DWORD);
1800 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1801 *ptr = value;
1802 return;
1803 }
1804}
1805
1806void Simulator::WriteConditional2W(int64_t addr, int64_t value,
1807 Instruction* instr, int32_t* done) {
1808 if (addr >= 0 && addr < 0x400) {
1809 // This has to be a nullptr-dereference, drop into debugger.
1810 PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR
1811 "\n",
1812 addr, reinterpret_cast<intptr_t>(instr));
1813 DieOrDebug();
1814 }
1815
1816 if ((addr & kPointerAlignmentMask) == 0) {
1817 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1818 if (local_monitor_.NotifyStoreConditional(addr,
1819 TransactionSize::DoubleWord) &&
1820 GlobalMonitor::Get()->NotifyStoreConditional_Locked(
1821 addr, &global_monitor_thread_)) {
1822 local_monitor_.NotifyStore();
1823 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1824 TraceMemWr(addr, value, DWORD);
1825 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1826 *ptr = value;
1827 *done = 1;
1828 } else {
1829 *done = 0;
1830 }
1831 return;
1832 }
1833 PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
1834 reinterpret_cast<intptr_t>(instr));
1835 DieOrDebug();
1836}
1837
1838double Simulator::ReadD(int64_t addr, Instruction* instr) {
1839 local_monitor_.NotifyLoad();
1840 double* ptr = reinterpret_cast<double*>(addr);
1841 return *ptr;
1842}
1843
1844void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
1845 local_monitor_.NotifyStore();
1846 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1847 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1848 double* ptr = reinterpret_cast<double*>(addr);
1849 *ptr = value;
1850 return;
1851}
1852
1853uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
1854 local_monitor_.NotifyLoad();
1855 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1856 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1857 return *ptr;
1858}
1859
1860int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
1861 local_monitor_.NotifyLoad();
1862 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1863 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1864 return *ptr;
1865}
1866
1867void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
1868 local_monitor_.NotifyStore();
1869 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1870 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1871 TraceMemWr(addr, value, HALF);
1872 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1873 *ptr = value;
1874 return;
1875}
1876
1877void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
1878 local_monitor_.NotifyStore();
1879 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1880 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1881 TraceMemWr(addr, value, HALF);
1882 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1883 *ptr = value;
1884 return;
1885}
1886
1887uint32_t Simulator::ReadBU(int64_t addr) {
1888 local_monitor_.NotifyLoad();
1889 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1890 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1891 return *ptr & 0xFF;
1892}
1893
1894int32_t Simulator::ReadB(int64_t addr) {
1895 local_monitor_.NotifyLoad();
1896 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1897 TraceMemRd(addr, static_cast<int64_t>(*ptr));
1898 return *ptr;
1899}
1900
1901void Simulator::WriteB(int64_t addr, uint8_t value) {
1902 local_monitor_.NotifyStore();
1903 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1904 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1905 TraceMemWr(addr, value, BYTE);
1906 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1907 *ptr = value;
1908}
1909
1910void Simulator::WriteB(int64_t addr, int8_t value) {
1911 local_monitor_.NotifyStore();
1912 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1913 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1914 TraceMemWr(addr, value, BYTE);
1915 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1916 *ptr = value;
1917}
1918
1919template <typename T>
1920T Simulator::ReadMem(int64_t addr, Instruction* instr) {
1921 int alignment_mask = (1 << sizeof(T)) - 1;
1922 if ((addr & alignment_mask) == 0) {
1923 local_monitor_.NotifyLoad();
1924 T* ptr = reinterpret_cast<T*>(addr);
1925 TraceMemRd(addr, *ptr);
1926 return *ptr;
1927 }
1928 PrintF("Unaligned read of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
1929 "\n",
1930 sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
1931 base::OS::Abort();
1932 return 0;
1933}
1934
1935template <typename T>
1936void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) {
1937 int alignment_mask = (1 << sizeof(T)) - 1;
1938 if ((addr & alignment_mask) == 0) {
1939 local_monitor_.NotifyStore();
1940 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1941 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1942 T* ptr = reinterpret_cast<T*>(addr);
1943 *ptr = value;
1944 TraceMemWr(addr, value);
1945 return;
1946 }
1947 PrintF("Unaligned write of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
1948 "\n",
1949 sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
1950 base::OS::Abort();
1951}
1952
1953// Returns the limit of the stack area to enable checking for stack overflows.
1954uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1955 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1956 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1957 if (base::Stack::GetCurrentStackPosition() < c_limit) {
1958 return get_sp();
1959 }
1960
1961 // Otherwise the limit is the JS stack. Leave a safety margin
1962 // to prevent overrunning the stack when pushing values.
1963 return stack_limit_ + kAdditionalStackMargin;
1964}
1965
1966uintptr_t Simulator::StackBase() const {
1967 return reinterpret_cast<uintptr_t>(stack_) + UsableStackSize();
1968}
1969
1970base::Vector<uint8_t> Simulator::GetCentralStackView() const {
1971 // We do not add an additional safety margin as above in
1972 // Simulator::StackLimit, as users of this method are expected to add their
1973 // own margin.
1974 return base::VectorOf(
1975 reinterpret_cast<uint8_t*>(stack_) + kStackProtectionSize,
1976 UsableStackSize());
1977}
1978
1979// We touch the stack, which may or may not have been initialized properly. Msan
1980// reports here are not interesting.
1981DISABLE_MSAN void Simulator::IterateRegistersAndStack(
1982 ::heap::base::StackVisitor* visitor) {
1983 for (int i = 0; i < kNumSimuRegisters; ++i) {
1984 visitor->VisitPointer(reinterpret_cast<const void*>(get_register(i)));
1985 }
1986 for (const void* const* current =
1987 reinterpret_cast<const void* const*>(get_sp());
1989 const void* address = *current;
1990 if (address == nullptr) {
1991 continue;
1992 }
1993 visitor->VisitPointer(address);
1994 }
1995}
1996
1997// Unsupported instructions use Format to print an error and stop execution.
1998void Simulator::Format(Instruction* instr, const char* format) {
1999 PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n",
2000 reinterpret_cast<intptr_t>(instr), format);
2001 UNIMPLEMENTED();
2002}
2003
2004// Calls into the V8 runtime are based on this very simple interface.
2005// Note: To be able to return two values from some calls the code in runtime.cc
2006// uses the ObjectPair which is essentially two 32-bit values stuffed into a
2007// 64-bit value. With the code below we assume that all runtime calls return
2008// 64 bits of result. If they don't, the v1 result register contains a bogus
2009// value, which is fine because it is caller-saved.
2010
2011using SimulatorRuntimeCall = ObjectPair (*)(
2012 int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4,
2013 int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg9,
2014 int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13, int64_t arg14,
2015 int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18, int64_t arg19);
2016
2017// These prototypes handle the four types of FP calls.
2018using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
2019using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
2020using SimulatorRuntimeFPCall = double (*)(double darg0);
2021using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
2022using SimulatorRuntimeIntFPCall = int32_t (*)(double darg0);
2023// Define four args for future flexibility; at the time of this writing only
2024// one is ever used.
2025using SimulatorRuntimeFPTaggedCall = double (*)(int64_t arg0, int64_t arg1,
2026 int64_t arg2, int64_t arg3);
2027
2028// This signature supports direct call in to API function native callback
2029// (refer to InvocationCallback in v8.h).
2030using SimulatorRuntimeDirectApiCall = void (*)(int64_t arg0);
2031
2032// This signature supports direct call to accessor getter callback.
2033using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1);
2034
2035using MixedRuntimeCall_0 = AnyCType (*)();
2036
2037#define BRACKETS(ident, N) ident[N]
2038
2039#define REP_0(expr, FMT)
2040#define REP_1(expr, FMT) FMT(expr, 0)
2041#define REP_2(expr, FMT) REP_1(expr, FMT), FMT(expr, 1)
2042#define REP_3(expr, FMT) REP_2(expr, FMT), FMT(expr, 2)
2043#define REP_4(expr, FMT) REP_3(expr, FMT), FMT(expr, 3)
2044#define REP_5(expr, FMT) REP_4(expr, FMT), FMT(expr, 4)
2045#define REP_6(expr, FMT) REP_5(expr, FMT), FMT(expr, 5)
2046#define REP_7(expr, FMT) REP_6(expr, FMT), FMT(expr, 6)
2047#define REP_8(expr, FMT) REP_7(expr, FMT), FMT(expr, 7)
2048#define REP_9(expr, FMT) REP_8(expr, FMT), FMT(expr, 8)
2049#define REP_10(expr, FMT) REP_9(expr, FMT), FMT(expr, 9)
2050#define REP_11(expr, FMT) REP_10(expr, FMT), FMT(expr, 10)
2051#define REP_12(expr, FMT) REP_11(expr, FMT), FMT(expr, 11)
2052#define REP_13(expr, FMT) REP_12(expr, FMT), FMT(expr, 12)
2053#define REP_14(expr, FMT) REP_13(expr, FMT), FMT(expr, 13)
2054#define REP_15(expr, FMT) REP_14(expr, FMT), FMT(expr, 14)
2055#define REP_16(expr, FMT) REP_15(expr, FMT), FMT(expr, 15)
2056#define REP_17(expr, FMT) REP_16(expr, FMT), FMT(expr, 16)
2057#define REP_18(expr, FMT) REP_17(expr, FMT), FMT(expr, 17)
2058#define REP_19(expr, FMT) REP_18(expr, FMT), FMT(expr, 18)
2059#define REP_20(expr, FMT) REP_19(expr, FMT), FMT(expr, 19)
2060
2061#define GEN_MAX_PARAM_COUNT(V) \
2062 V(0) \
2063 V(1) \
2064 V(2) \
2065 V(3) \
2066 V(4) \
2067 V(5) \
2068 V(6) \
2069 V(7) \
2070 V(8) \
2071 V(9) \
2072 V(10) \
2073 V(11) \
2074 V(12) \
2075 V(13) \
2076 V(14) \
2077 V(15) \
2078 V(16) \
2079 V(17) \
2080 V(18) \
2081 V(19) \
2082 V(20)
2083
2084#define MIXED_RUNTIME_CALL(N) \
2085 using MixedRuntimeCall_##N = AnyCType (*)(REP_##N(AnyCType arg, CONCAT));
2086
2087GEN_MAX_PARAM_COUNT(MIXED_RUNTIME_CALL)
2088#undef MIXED_RUNTIME_CALL
2089
2090#define CALL_ARGS(N) REP_##N(args, BRACKETS)
2091#define CALL_TARGET_VARARG(N) \
2092 if (signature.ParameterCount() == N) { /* NOLINT */ \
2093 MixedRuntimeCall_##N target = \
2094 reinterpret_cast<MixedRuntimeCall_##N>(target_address); \
2095 result = target(CALL_ARGS(N)); \
2096 } else /* NOLINT */
2097
2098// Configuration for C calling convention (see c-linkage.cc).
2099#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
2100#define RETURN_REGISTER a0
2101#define FP_PARAM_REGISTERS f0, f1, f2, f3, f4, f5, f6, f7
2102#define FP_RETURN_REGISTER f0
2103
2104void Simulator::CallAnyCTypeFunction(Address target_address,
2105 const EncodedCSignature& signature) {
2106 const int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
2107 const double* double_stack_pointer =
2108 reinterpret_cast<double*>(get_register(sp));
2109
2110 const Register kParamRegisters[] = {PARAM_REGISTERS};
2111 const FPURegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
2112
2113 int num_gp_params = 0, num_fp_params = 0, num_stack_params = 0;
2114
2115 CHECK_LE(signature.ParameterCount(), kMaxCParameters);
2116 static_assert(sizeof(AnyCType) == 8, "AnyCType is assumed to be 64-bit.");
2117 AnyCType args[kMaxCParameters];
2118 for (int i = 0; i < signature.ParameterCount(); ++i) {
2119 if (signature.IsFloat(i)) {
2120 if (num_fp_params < 8) {
2121 args[i].double_value =
2122 get_fpu_register_double(kFPParamRegisters[num_fp_params++]);
2123 } else if (num_gp_params < 8) {
2124 args[i].int64_value = get_register(kParamRegisters[num_gp_params++]);
2125 } else {
2126 args[i].double_value = double_stack_pointer[num_stack_params++];
2127 }
2128 } else {
2129 if (num_gp_params < 8) {
2130 args[i].int64_value = get_register(kParamRegisters[num_gp_params++]);
2131 } else {
2132 args[i].int64_value = stack_pointer[num_stack_params++];
2133 }
2134 }
2135 }
2136 AnyCType result;
2137 GEN_MAX_PARAM_COUNT(CALL_TARGET_VARARG)
2138 /* else */ {
2139 UNREACHABLE();
2140 }
2141 static_assert(20 == kMaxCParameters,
2142 "If you've changed kMaxCParameters, please change the "
2143 "GEN_MAX_PARAM_COUNT macro.");
2144
2145#undef CALL_TARGET_VARARG
2146#undef CALL_ARGS
2147#undef GEN_MAX_PARAM_COUNT
2148
2149 if (signature.IsReturnFloat()) {
2150 set_fpu_register_double(FP_RETURN_REGISTER, result.double_value);
2151 } else {
2152 set_register(RETURN_REGISTER, result.int64_value);
2153 }
2154}
2155
2156#undef PARAM_REGISTERS
2157#undef RETURN_REGISTER
2158#undef FP_PARAM_REGISTERS
2159#undef FP_RETURN_REGISTER
2160
2161// Software interrupt instructions are used by the simulator to call into the
2162// C-based V8 runtime. They are also used for debugging with simulator.
2163void Simulator::SoftwareInterrupt() {
2164 int32_t opcode_hi15 = instr_.Bits(31, 17);
2165 CHECK_EQ(opcode_hi15, 0x15);
2166 uint32_t code = instr_.Bits(14, 0);
2167 // We first check if we met a call_rt_redirected.
2168 if (instr_.InstructionBits() == rtCallRedirInstr) {
2169 Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2170
2171 // This is dodgy but it works because the C entry stubs are never moved.
2172 int64_t saved_ra = get_register(ra);
2173 intptr_t external =
2174 reinterpret_cast<intptr_t>(redirection->external_function());
2175
2176 Address func_addr =
2177 reinterpret_cast<Address>(redirection->external_function());
2178 SimulatorData* simulator_data = isolate_->simulator_data();
2179 DCHECK_NOT_NULL(simulator_data);
2180 const EncodedCSignature& signature =
2181 simulator_data->GetSignatureForTarget(func_addr);
2182 if (signature.IsValid()) {
2183 CHECK_EQ(redirection->type(), ExternalReference::FAST_C_CALL);
2184 CallAnyCTypeFunction(external, signature);
2185 set_register(ra, saved_ra);
2186 set_pc(get_register(ra));
2187 return;
2188 }
2189
2190 int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
2191
2192 int64_t arg0 = get_register(a0);
2193 int64_t arg1 = get_register(a1);
2194 int64_t arg2 = get_register(a2);
2195 int64_t arg3 = get_register(a3);
2196 int64_t arg4 = get_register(a4);
2197 int64_t arg5 = get_register(a5);
2198 int64_t arg6 = get_register(a6);
2199 int64_t arg7 = get_register(a7);
2200 int64_t arg8 = stack_pointer[0];
2201 int64_t arg9 = stack_pointer[1];
2202 int64_t arg10 = stack_pointer[2];
2203 int64_t arg11 = stack_pointer[3];
2204 int64_t arg12 = stack_pointer[4];
2205 int64_t arg13 = stack_pointer[5];
2206 int64_t arg14 = stack_pointer[6];
2207 int64_t arg15 = stack_pointer[7];
2208 int64_t arg16 = stack_pointer[8];
2209 int64_t arg17 = stack_pointer[9];
2210 int64_t arg18 = stack_pointer[10];
2211 int64_t arg19 = stack_pointer[11];
2212 static_assert(kMaxCParameters == 20);
2213
2214 bool fp_call =
2215 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2216 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2217 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2218 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL) ||
2219 (redirection->type() == ExternalReference::BUILTIN_INT_FP_CALL);
2220
2221 // Based on CpuFeatures::IsSupported(FPU), Loong64 will use either hardware
2222 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2223 // simulator. Soft-float has additional abstraction of ExternalReference,
2224 // to support serialization.
2225 if (fp_call) {
2226 double dval0, dval1; // one or two double parameters
2227 int32_t ival; // zero or one integer parameters
2228 int64_t iresult = 0; // integer return value
2229 double dresult = 0; // double return value
2230 GetFpArgs(&dval0, &dval1, &ival);
2231 SimulatorRuntimeCall generic_target =
2232 reinterpret_cast<SimulatorRuntimeCall>(external);
2233 if (v8_flags.trace_sim) {
2234 switch (redirection->type()) {
2235 case ExternalReference::BUILTIN_FP_FP_CALL:
2236 case ExternalReference::BUILTIN_COMPARE_CALL:
2237 PrintF("Call to host function at %p with args %f, %f",
2238 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2239 dval0, dval1);
2240 break;
2241 case ExternalReference::BUILTIN_FP_CALL:
2242 PrintF("Call to host function at %p with arg %f",
2243 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2244 dval0);
2245 break;
2246 case ExternalReference::BUILTIN_FP_INT_CALL:
2247 PrintF("Call to host function at %p with args %f, %d",
2248 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2249 dval0, ival);
2250 break;
2251 case ExternalReference::BUILTIN_INT_FP_CALL:
2252 PrintF("Call to host function at %p with args %f",
2253 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2254 dval0);
2255 break;
2256 default:
2257 UNREACHABLE();
2258 }
2259 }
2260 switch (redirection->type()) {
2261 case ExternalReference::BUILTIN_COMPARE_CALL: {
2262 SimulatorRuntimeCompareCall target =
2263 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2264 iresult = target(dval0, dval1);
2265 set_register(v0, static_cast<int64_t>(iresult));
2266 // set_register(v1, static_cast<int64_t>(iresult >> 32));
2267 break;
2268 }
2269 case ExternalReference::BUILTIN_FP_FP_CALL: {
2270 SimulatorRuntimeFPFPCall target =
2271 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2272 dresult = target(dval0, dval1);
2273 SetFpResult(dresult);
2274 break;
2275 }
2276 case ExternalReference::BUILTIN_FP_CALL: {
2277 SimulatorRuntimeFPCall target =
2278 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2279 dresult = target(dval0);
2280 SetFpResult(dresult);
2281 break;
2282 }
2283 case ExternalReference::BUILTIN_FP_INT_CALL: {
2284 SimulatorRuntimeFPIntCall target =
2285 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2286 dresult = target(dval0, ival);
2287 SetFpResult(dresult);
2288 break;
2289 }
2290 case ExternalReference::BUILTIN_INT_FP_CALL: {
2291 SimulatorRuntimeIntFPCall target =
2292 reinterpret_cast<SimulatorRuntimeIntFPCall>(external);
2293 iresult = target(dval0);
2294 set_register(a0, static_cast<int64_t>(iresult));
2295 break;
2296 }
2297 default:
2298 UNREACHABLE();
2299 }
2300 if (v8_flags.trace_sim) {
2301 switch (redirection->type()) {
2302 case ExternalReference::BUILTIN_COMPARE_CALL:
2303 case ExternalReference::BUILTIN_INT_FP_CALL:
2304 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2305 break;
2306 case ExternalReference::BUILTIN_FP_FP_CALL:
2307 case ExternalReference::BUILTIN_FP_CALL:
2308 case ExternalReference::BUILTIN_FP_INT_CALL:
2309 PrintF("Returned %f\n", dresult);
2310 break;
2311 default:
2312 UNREACHABLE();
2313 }
2314 }
2315 } else if (redirection->type() ==
2316 ExternalReference::BUILTIN_FP_POINTER_CALL) {
2317 if (v8_flags.trace_sim) {
2318 PrintF("Call to host function at %p args %08" PRIx64 " \n",
2319 reinterpret_cast<void*>(external), arg0);
2320 }
2321 SimulatorRuntimeFPTaggedCall target =
2322 reinterpret_cast<SimulatorRuntimeFPTaggedCall>(external);
2323 double dresult = target(arg0, arg1, arg2, arg3);
2324 SetFpResult(dresult);
2325 if (v8_flags.trace_sim) {
2326 PrintF("Returned %f\n", dresult);
2327 }
2328 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2329 if (v8_flags.trace_sim) {
2330 PrintF("Call to host function at %p args %08" PRIx64 " \n",
2331 reinterpret_cast<void*>(external), arg0);
2332 }
2333 SimulatorRuntimeDirectApiCall target =
2334 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2335 target(arg0);
2336 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2337 if (v8_flags.trace_sim) {
2338 PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64
2339 " \n",
2340 reinterpret_cast<void*>(external), arg0, arg1);
2341 }
2342 SimulatorRuntimeDirectGetterCall target =
2343 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2344 target(arg0, arg1);
2345 } else {
2346 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2347 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2348 SimulatorRuntimeCall target =
2349 reinterpret_cast<SimulatorRuntimeCall>(external);
2350 if (v8_flags.trace_sim) {
2351 PrintF(
2352 "Call to host function at %p "
2353 "args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2354 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2355 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2356 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2357 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
2358 " \n",
2359 reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
2360 arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
2361 arg13, arg14, arg15, arg16, arg17, arg18, arg19);
2362 }
2363 ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
2364 arg8, arg9, arg10, arg11, arg12, arg13, arg14,
2365 arg15, arg16, arg17, arg18, arg19);
2366 set_register(v0, (int64_t)(result.x));
2367 set_register(v1, (int64_t)(result.y));
2368 }
2369 if (v8_flags.trace_sim) {
2370 PrintF("Returned %08" PRIx64 " : %08" PRIx64 " \n", get_register(v1),
2371 get_register(v0));
2372 }
2373 set_register(ra, saved_ra);
2374 set_pc(get_register(ra));
2375
2376 } else if (code <= kMaxStopCode) {
2377 if (IsWatchpoint(code)) {
2378 PrintWatchpoint(code);
2379 } else {
2380 IncreaseStopCounter(code);
2381 HandleStop(code, instr_.instr());
2382 }
2383 } else {
2384 // All remaining break_ codes, and all traps are handled here.
2385 Loong64Debugger dbg(this);
2386 dbg.Debug();
2387 }
2388}
2389
2390// Stop helper functions.
2391bool Simulator::IsWatchpoint(uint64_t code) {
2392 return (code <= kMaxWatchpointCode);
2393}
2394
2395void Simulator::PrintWatchpoint(uint64_t code) {
2396 Loong64Debugger dbg(this);
2397 ++break_count_;
2398 PrintF("\n---- break %" PRId64 " marker: %3d (instr count: %8" PRId64
2399 " ) ----------"
2400 "----------------------------------",
2401 code, break_count_, icount_);
2402 dbg.PrintAllRegs(); // Print registers and continue running.
2403}
2404
2405void Simulator::HandleStop(uint64_t code, Instruction* instr) {
2406 // Stop if it is enabled, otherwise go on jumping over the stop
2407 // and the message address.
2408 if (IsEnabledStop(code)) {
2409 Loong64Debugger dbg(this);
2410 dbg.Stop(instr);
2411 }
2412}
2413
2414bool Simulator::IsStopInstruction(Instruction* instr) {
2415 int32_t opcode_hi15 = instr->Bits(31, 17);
2416 uint32_t code = static_cast<uint32_t>(instr->Bits(14, 0));
2417 return (opcode_hi15 == 0x15) && code > kMaxWatchpointCode &&
2418 code <= kMaxStopCode;
2419}
2420
2421bool Simulator::IsEnabledStop(uint64_t code) {
2422 DCHECK_LE(code, kMaxStopCode);
2423 DCHECK_GT(code, kMaxWatchpointCode);
2424 return !(watched_stops_[code].count & kStopDisabledBit);
2425}
2426
2427void Simulator::EnableStop(uint64_t code) {
2428 if (!IsEnabledStop(code)) {
2429 watched_stops_[code].count &= ~kStopDisabledBit;
2430 }
2431}
2432
2433void Simulator::DisableStop(uint64_t code) {
2434 if (IsEnabledStop(code)) {
2435 watched_stops_[code].count |= kStopDisabledBit;
2436 }
2437}
2438
2439void Simulator::IncreaseStopCounter(uint64_t code) {
2440 DCHECK_LE(code, kMaxStopCode);
2441 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2442 PrintF("Stop counter for code %" PRId64
2443 " has overflowed.\n"
2444 "Enabling this code and reseting the counter to 0.\n",
2445 code);
2446 watched_stops_[code].count = 0;
2447 EnableStop(code);
2448 } else {
2449 watched_stops_[code].count++;
2450 }
2451}
2452
2453// Print a stop status.
2454void Simulator::PrintStopInfo(uint64_t code) {
2455 if (code <= kMaxWatchpointCode) {
2456 PrintF("That is a watchpoint, not a stop.\n");
2457 return;
2458 } else if (code > kMaxStopCode) {
2459 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2460 return;
2461 }
2462 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2463 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2464 // Don't print the state of unused breakpoints.
2465 if (count != 0) {
2466 if (watched_stops_[code].desc) {
2467 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i, \t%s\n",
2468 code, code, state, count, watched_stops_[code].desc);
2469 } else {
2470 PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i\n", code,
2471 code, state, count);
2472 }
2473 }
2474}
2475
2476void Simulator::SignalException(Exception e) {
2477 FATAL("Error: Exception %i raised.", static_cast<int>(e));
2478}
2479
2480template <typename T>
2481static T FPAbs(T a);
2482
2483template <>
2484double FPAbs<double>(double a) {
2485 return fabs(a);
2486}
2487
2488template <>
2489float FPAbs<float>(float a) {
2490 return fabsf(a);
2491}
2492
2493template <typename T>
2494static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
2495 if (std::isnan(a) && std::isnan(b)) {
2496 *result = a;
2497 } else if (std::isnan(a)) {
2498 *result = b;
2499 } else if (std::isnan(b)) {
2500 *result = a;
2501 } else if (b == a) {
2502 // Handle -0.0 == 0.0 case.
2503 // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2504 // negates the result.
2505 *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2506 } else {
2507 return false;
2508 }
2509 return true;
2510}
2511
2512template <typename T>
2513static T FPUMin(T a, T b) {
2514 T result;
2515 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2516 return result;
2517 } else {
2518 return b < a ? b : a;
2519 }
2520}
2521
2522template <typename T>
2523static T FPUMax(T a, T b) {
2524 T result;
2525 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
2526 return result;
2527 } else {
2528 return b > a ? b : a;
2529 }
2530}
2531
2532template <typename T>
2533static T FPUMinA(T a, T b) {
2534 T result;
2535 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2536 if (FPAbs(a) < FPAbs(b)) {
2537 result = a;
2538 } else if (FPAbs(b) < FPAbs(a)) {
2539 result = b;
2540 } else {
2541 result = a < b ? a : b;
2542 }
2543 }
2544 return result;
2545}
2546
2547template <typename T>
2548static T FPUMaxA(T a, T b) {
2549 T result;
2550 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2551 if (FPAbs(a) > FPAbs(b)) {
2552 result = a;
2553 } else if (FPAbs(b) > FPAbs(a)) {
2554 result = b;
2555 } else {
2556 result = a > b ? a : b;
2557 }
2558 }
2559 return result;
2560}
2561
2562enum class KeepSign : bool { no = false, yes };
2563
2564template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2565 int>::type = 0>
2566T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2567 DCHECK(std::isnan(arg));
2568 T qNaN = std::numeric_limits<T>::quiet_NaN();
2569 if (keepSign == KeepSign::yes) {
2570 return std::copysign(qNaN, result);
2571 }
2572 return qNaN;
2573}
2574
2575template <typename T>
2576T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2577 if (std::isnan(first)) {
2578 return FPUCanonalizeNaNArg(result, first, keepSign);
2579 }
2580 return result;
2581}
2582
2583template <typename T, typename... Args>
2584T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2585 if (std::isnan(first)) {
2586 return FPUCanonalizeNaNArg(result, first, keepSign);
2587 }
2588 return FPUCanonalizeNaNArgs(result, keepSign, args...);
2589}
2590
2591template <typename Func, typename T, typename... Args>
2592T FPUCanonalizeOperation(Func f, T first, Args... args) {
2593 return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2594}
2595
2596template <typename Func, typename T, typename... Args>
2597T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2598 T result = f(first, args...);
2599 if (std::isnan(result)) {
2600 result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2601 }
2602 return result;
2603}
2604
2605// Handle execution based on instruction types.
2606void Simulator::DecodeTypeOp6() {
2607 int64_t alu_out;
2608 // Next pc.
2609 int64_t next_pc = bad_ra;
2610
2611 // Branch instructions common part.
2612 auto BranchAndLinkHelper = [this, &next_pc]() {
2613 int64_t current_pc = get_pc();
2614 set_register(ra, current_pc + kInstrSize);
2615 int32_t offs26_low16 =
2616 static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2617 int32_t offs26_high10 = static_cast<int32_t>(instr_.Bits(9, 0) << 22) >> 6;
2618 int32_t offs26 = offs26_low16 | offs26_high10;
2619 next_pc = current_pc + (offs26 << 2);
2620 printf_instr("Offs26: %08x\n", offs26);
2621 set_pc(next_pc);
2622 };
2623
2624 auto BranchOff16Helper = [this, &next_pc](bool do_branch) {
2625 int64_t current_pc = get_pc();
2626 int32_t offs16 = static_cast<int32_t>(instr_.Bits(25, 10) << 16) >> 16;
2627 printf_instr("Offs16: %08x\n", offs16);
2628 int32_t offs = do_branch ? (offs16 << 2) : kInstrSize;
2629 next_pc = current_pc + offs;
2630 set_pc(next_pc);
2631 };
2632
2633 auto BranchOff21Helper = [this, &next_pc](bool do_branch) {
2634 int64_t current_pc = get_pc();
2635 int32_t offs21_low16 =
2636 static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2637 int32_t offs21_high5 = static_cast<int32_t>(instr_.Bits(4, 0) << 27) >> 11;
2638 int32_t offs = offs21_low16 | offs21_high5;
2639 printf_instr("Offs21: %08x\n", offs);
2640 offs = do_branch ? (offs << 2) : kInstrSize;
2641 next_pc = current_pc + offs;
2642 set_pc(next_pc);
2643 };
2644
2645 auto BranchOff26Helper = [this, &next_pc]() {
2646 int64_t current_pc = get_pc();
2647 int32_t offs26_low16 =
2648 static_cast<uint32_t>(instr_.Bits(25, 10) << 16) >> 16;
2649 int32_t offs26_high10 = static_cast<int32_t>(instr_.Bits(9, 0) << 22) >> 6;
2650 int32_t offs26 = offs26_low16 | offs26_high10;
2651 next_pc = current_pc + (offs26 << 2);
2652 printf_instr("Offs26: %08x\n", offs26);
2653 set_pc(next_pc);
2654 };
2655
2656 auto JumpOff16Helper = [this, &next_pc]() {
2657 int32_t offs16 = static_cast<int32_t>(instr_.Bits(25, 10) << 16) >> 16;
2658 printf_instr("JIRL\t %s: %016lx, %s: %016lx, offs16: %x\n",
2659 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2660 rj(), offs16);
2661 set_register(rd_reg(), get_pc() + kInstrSize);
2662 next_pc = rj() + (offs16 << 2);
2663 set_pc(next_pc);
2664 };
2665
2666 switch (instr_.Bits(31, 26) << 26) {
2667 case ADDU16I_D: {
2668 printf_instr("ADDU16I_D\t %s: %016lx, %s: %016lx, si16: %d\n",
2669 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2670 rj(), si16());
2671 int32_t si16_upper = static_cast<int32_t>(si16()) << 16;
2672 alu_out = static_cast<int64_t>(si16_upper) + rj();
2673 SetResult(rd_reg(), alu_out);
2674 break;
2675 }
2676 case BEQZ:
2677 printf_instr("BEQZ\t %s: %016lx, ", Registers::Name(rj_reg()), rj());
2678 BranchOff21Helper(rj() == 0);
2679 break;
2680 case BNEZ:
2681 printf_instr("BNEZ\t %s: %016lx, ", Registers::Name(rj_reg()), rj());
2682 BranchOff21Helper(rj() != 0);
2683 break;
2684 case BCZ: {
2685 if (instr_.Bits(9, 8) == 0b00) {
2686 // BCEQZ
2687 printf_instr("BCEQZ\t fcc%d: %s, ", cj_reg(), cj() ? "True" : "False");
2688 BranchOff21Helper(cj() == false);
2689 } else if (instr_.Bits(9, 8) == 0b01) {
2690 // BCNEZ
2691 printf_instr("BCNEZ\t fcc%d: %s, ", cj_reg(), cj() ? "True" : "False");
2692 BranchOff21Helper(cj() == true);
2693 } else {
2694 UNREACHABLE();
2695 }
2696 break;
2697 }
2698 case JIRL:
2699 JumpOff16Helper();
2700 break;
2701 case B:
2702 printf_instr("B\t ");
2703 BranchOff26Helper();
2704 break;
2705 case BL:
2706 printf_instr("BL\t ");
2707 BranchAndLinkHelper();
2708 break;
2709 case BEQ:
2710 printf_instr("BEQ\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2711 rj(), Registers::Name(rd_reg()), rd());
2712 BranchOff16Helper(rj() == rd());
2713 break;
2714 case BNE:
2715 printf_instr("BNE\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2716 rj(), Registers::Name(rd_reg()), rd());
2717 BranchOff16Helper(rj() != rd());
2718 break;
2719 case BLT:
2720 printf_instr("BLT\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2721 rj(), Registers::Name(rd_reg()), rd());
2722 BranchOff16Helper(rj() < rd());
2723 break;
2724 case BGE:
2725 printf_instr("BGE\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2726 rj(), Registers::Name(rd_reg()), rd());
2727 BranchOff16Helper(rj() >= rd());
2728 break;
2729 case BLTU:
2730 printf_instr("BLTU\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2731 rj(), Registers::Name(rd_reg()), rd());
2732 BranchOff16Helper(rj_u() < rd_u());
2733 break;
2734 case BGEU:
2735 printf_instr("BGEU\t %s: %016lx, %s, %016lx, ", Registers::Name(rj_reg()),
2736 rj(), Registers::Name(rd_reg()), rd());
2737 BranchOff16Helper(rj_u() >= rd_u());
2738 break;
2739 default:
2740 UNREACHABLE();
2741 }
2742}
2743
2744void Simulator::DecodeTypeOp7() {
2745 int64_t alu_out;
2746
2747 switch (instr_.Bits(31, 25) << 25) {
2748 case LU12I_W: {
2749 printf_instr("LU12I_W\t %s: %016lx, si20: %d\n",
2750 Registers::Name(rd_reg()), rd(), si20());
2751 int32_t si20_upper = static_cast<int32_t>(si20() << 12);
2752 SetResult(rd_reg(), static_cast<int64_t>(si20_upper));
2753 break;
2754 }
2755 case LU32I_D: {
2756 printf_instr("LU32I_D\t %s: %016lx, si20: %d\n",
2757 Registers::Name(rd_reg()), rd(), si20());
2758 int32_t si20_signExtend = static_cast<int32_t>(si20() << 12) >> 12;
2759 int64_t lower_32bit_mask = 0xFFFFFFFF;
2760 alu_out = (static_cast<int64_t>(si20_signExtend) << 32) |
2761 (rd() & lower_32bit_mask);
2762 SetResult(rd_reg(), alu_out);
2763 break;
2764 }
2765 case PCADDI: {
2766 printf_instr("PCADDI\t %s: %016lx, si20: %d\n", Registers::Name(rd_reg()),
2767 rd(), si20());
2768 int32_t si20_signExtend = static_cast<int32_t>(si20() << 12) >> 10;
2769 int64_t current_pc = get_pc();
2770 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2771 SetResult(rd_reg(), alu_out);
2772 break;
2773 }
2774 case PCALAU12I: {
2775 printf_instr("PCALAU12I\t %s: %016lx, si20: %d\n",
2776 Registers::Name(rd_reg()), rd(), si20());
2777 int32_t si20_signExtend = static_cast<int32_t>(si20() << 12);
2778 int64_t current_pc = get_pc();
2779 int64_t clear_lower12bit_mask = 0xFFFFFFFFFFFFF000;
2780 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2781 SetResult(rd_reg(), alu_out & clear_lower12bit_mask);
2782 break;
2783 }
2784 case PCADDU12I: {
2785 printf_instr("PCADDU12I\t %s: %016lx, si20: %d\n",
2786 Registers::Name(rd_reg()), rd(), si20());
2787 int32_t si20_signExtend = static_cast<int32_t>(si20() << 12);
2788 int64_t current_pc = get_pc();
2789 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
2790 SetResult(rd_reg(), alu_out);
2791 break;
2792 }
2793 case PCADDU18I: {
2794 printf_instr("PCADDU18I\t %s: %016lx, si20: %d\n",
2795 Registers::Name(rd_reg()), rd(), si20());
2796 int64_t si20_signExtend = (static_cast<int64_t>(si20()) << 44) >> 26;
2797 int64_t current_pc = get_pc();
2798 alu_out = si20_signExtend + current_pc;
2799 SetResult(rd_reg(), alu_out);
2800 break;
2801 }
2802 default:
2803 UNREACHABLE();
2804 }
2805}
2806
2807void Simulator::DecodeTypeOp8() {
2808 int64_t addr = 0x0;
2809 int64_t si14_se = (static_cast<int64_t>(si14()) << 50) >> 48;
2810
2811 switch (instr_.Bits(31, 24) << 24) {
2812 case LDPTR_W:
2813 printf_instr("LDPTR_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2814 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2815 rj(), si14_se);
2816 if (!ProbeMemory(rj() + si14_se, sizeof(int32_t))) return;
2817 set_register(rd_reg(), ReadW(rj() + si14_se, instr_.instr()));
2818 break;
2819 case STPTR_W:
2820 printf_instr("STPTR_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2821 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2822 rj(), si14_se);
2823 if (!ProbeMemory(rj() + si14_se, sizeof(int32_t))) return;
2824 WriteW(rj() + si14_se, static_cast<int32_t>(rd()), instr_.instr());
2825 break;
2826 case LDPTR_D:
2827 printf_instr("LDPTR_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2828 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2829 rj(), si14_se);
2830 if (!ProbeMemory(rj() + si14_se, sizeof(int64_t))) return;
2831 set_register(rd_reg(), Read2W(rj() + si14_se, instr_.instr()));
2832 break;
2833 case STPTR_D:
2834 printf_instr("STPTR_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2835 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2836 rj(), si14_se);
2837 if (!ProbeMemory(rj() + si14_se, sizeof(int64_t))) return;
2838 Write2W(rj() + si14_se, rd(), instr_.instr());
2839 break;
2840 case LL_W: {
2841 printf_instr("LL_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2842 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2843 rj(), si14_se);
2844 addr = si14_se + rj();
2845 if (!ProbeMemory(addr, sizeof(int32_t))) return;
2846 {
2847 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2848 set_register(rd_reg(), ReadW(addr, instr_.instr()));
2849 local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
2850 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
2851 &global_monitor_thread_);
2852 }
2853 break;
2854 }
2855 case SC_W: {
2856 printf_instr("SC_W\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2857 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2858 rj(), si14_se);
2859 addr = si14_se + rj();
2860 if (!ProbeMemory(addr, sizeof(int32_t))) return;
2861 int32_t LLbit = 0;
2862 WriteConditionalW(addr, static_cast<int32_t>(rd()), instr_.instr(),
2863 &LLbit);
2864 set_register(rd_reg(), LLbit);
2865 break;
2866 }
2867 case LL_D: {
2868 printf_instr("LL_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2869 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2870 rj(), si14_se);
2871 addr = si14_se + rj();
2872 if (!ProbeMemory(addr, sizeof(int64_t))) return;
2873 {
2874 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2875 set_register(rd_reg(), Read2W(addr, instr_.instr()));
2876 local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord);
2877 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
2878 &global_monitor_thread_);
2879 }
2880 break;
2881 }
2882 case SC_D: {
2883 printf_instr("SC_D\t %s: %016lx, %s: %016lx, si14: %016lx\n",
2884 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2885 rj(), si14_se);
2886 addr = si14_se + rj();
2887 if (!ProbeMemory(addr, sizeof(int64_t))) return;
2888 int32_t LLbit = 0;
2889 WriteConditional2W(addr, rd(), instr_.instr(), &LLbit);
2890 set_register(rd_reg(), LLbit);
2891 break;
2892 }
2893 default:
2894 UNREACHABLE();
2895 }
2896}
2897
2898void Simulator::DecodeTypeOp10() {
2899 int64_t alu_out = 0x0;
2900 int64_t si12_se = (static_cast<int64_t>(si12()) << 52) >> 52;
2901 uint64_t si12_ze = (static_cast<uint64_t>(ui12()) << 52) >> 52;
2902
2903 switch (instr_.Bits(31, 22) << 22) {
2904 case BSTR_W: {
2905 CHECK_EQ(instr_.Bit(21), 1);
2906 uint8_t lsbw_ = lsbw();
2907 uint8_t msbw_ = msbw();
2908 CHECK_LE(lsbw_, msbw_);
2909 uint8_t size = msbw_ - lsbw_ + 1;
2910 uint64_t mask = (1ULL << size) - 1;
2911 if (instr_.Bit(15) == 0) {
2912 // BSTRINS_W
2913 printf_instr(
2914 "BSTRINS_W\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2915 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2916 msbw_, lsbw_);
2917 alu_out = static_cast<int32_t>((rd_u() & ~(mask << lsbw_)) |
2918 ((rj_u() & mask) << lsbw_));
2919 } else {
2920 // BSTRPICK_W
2921 printf_instr(
2922 "BSTRPICK_W\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2923 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2924 msbw_, lsbw_);
2925 alu_out = static_cast<int32_t>((rj_u() & (mask << lsbw_)) >> lsbw_);
2926 }
2927 SetResult(rd_reg(), alu_out);
2928 break;
2929 }
2930 case BSTRINS_D: {
2931 uint8_t lsbd_ = lsbd();
2932 uint8_t msbd_ = msbd();
2933 CHECK_LE(lsbd_, msbd_);
2934 printf_instr(
2935 "BSTRINS_D\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2936 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2937 msbd_, lsbd_);
2938 uint8_t size = msbd_ - lsbd_ + 1;
2939 if (size < 64) {
2940 uint64_t mask = (1ULL << size) - 1;
2941 alu_out = (rd_u() & ~(mask << lsbd_)) | ((rj_u() & mask) << lsbd_);
2942 SetResult(rd_reg(), alu_out);
2943 } else if (size == 64) {
2944 SetResult(rd_reg(), rj());
2945 }
2946 break;
2947 }
2948 case BSTRPICK_D: {
2949 uint8_t lsbd_ = lsbd();
2950 uint8_t msbd_ = msbd();
2951 CHECK_LE(lsbd_, msbd_);
2952 printf_instr(
2953 "BSTRPICK_D\t %s: %016lx, %s: %016lx, msbw: %02x, lsbw: %02x\n",
2954 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()), rj(),
2955 msbd_, lsbd_);
2956 uint8_t size = msbd_ - lsbd_ + 1;
2957 if (size < 64) {
2958 uint64_t mask = (1ULL << size) - 1;
2959 alu_out = (rj_u() & (mask << lsbd_)) >> lsbd_;
2960 SetResult(rd_reg(), alu_out);
2961 } else if (size == 64) {
2962 SetResult(rd_reg(), rj());
2963 }
2964 break;
2965 }
2966 case SLTI:
2967 printf_instr("SLTI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2968 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2969 rj(), si12_se);
2970 SetResult(rd_reg(), rj() < si12_se ? 1 : 0);
2971 break;
2972 case SLTUI:
2973 printf_instr("SLTUI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2974 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2975 rj(), si12_se);
2976 SetResult(rd_reg(), rj_u() < static_cast<uint64_t>(si12_se) ? 1 : 0);
2977 break;
2978 case ADDI_W: {
2979 printf_instr("ADDI_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2980 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2981 rj(), si12_se);
2982 int32_t alu32_out =
2983 static_cast<int32_t>(rj()) + static_cast<int32_t>(si12_se);
2984 SetResult(rd_reg(), alu32_out);
2985 break;
2986 }
2987 case ADDI_D:
2988 printf_instr("ADDI_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2989 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2990 rj(), si12_se);
2991 SetResult(rd_reg(), rj() + si12_se);
2992 break;
2993 case LU52I_D: {
2994 printf_instr("LU52I_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
2995 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
2996 rj(), si12_se);
2997 int64_t si12_se = static_cast<int64_t>(si12()) << 52;
2998 uint64_t mask = (1ULL << 52) - 1;
2999 alu_out = si12_se + (rj() & mask);
3000 SetResult(rd_reg(), alu_out);
3001 break;
3002 }
3003 case ANDI:
3004 printf_instr("ANDI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3005 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3006 rj(), si12_ze);
3007 SetResult(rd_reg(), rj() & si12_ze);
3008 break;
3009 case ORI:
3010 printf_instr("ORI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3011 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3012 rj(), si12_ze);
3013 SetResult(rd_reg(), rj_u() | si12_ze);
3014 break;
3015 case XORI:
3016 printf_instr("XORI\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3017 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3018 rj(), si12_ze);
3019 SetResult(rd_reg(), rj_u() ^ si12_ze);
3020 break;
3021 case LD_B:
3022 printf_instr("LD_B\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3023 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3024 rj(), si12_ze);
3025 if (!ProbeMemory(rj() + si12_se, sizeof(int8_t))) return;
3026 set_register(rd_reg(), ReadB(rj() + si12_se));
3027 break;
3028 case LD_H:
3029 printf_instr("LD_H\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3030 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3031 rj(), si12_ze);
3032 if (!ProbeMemory(rj() + si12_se, sizeof(int16_t))) return;
3033 set_register(rd_reg(), ReadH(rj() + si12_se, instr_.instr()));
3034 break;
3035 case LD_W:
3036 printf_instr("LD_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3037 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3038 rj(), si12_ze);
3039 if (!ProbeMemory(rj() + si12_se, sizeof(int32_t))) return;
3040 set_register(rd_reg(), ReadW(rj() + si12_se, instr_.instr()));
3041 break;
3042 case LD_D:
3043 printf_instr("LD_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3044 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3045 rj(), si12_ze);
3046 if (!ProbeMemory(rj() + si12_se, sizeof(int64_t))) return;
3047 set_register(rd_reg(), Read2W(rj() + si12_se, instr_.instr()));
3048 break;
3049 case ST_B:
3050 printf_instr("ST_B\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3051 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3052 rj(), si12_ze);
3053 if (!ProbeMemory(rj() + si12_se, sizeof(int8_t))) return;
3054 WriteB(rj() + si12_se, static_cast<int8_t>(rd()));
3055 break;
3056 case ST_H:
3057 printf_instr("ST_H\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3058 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3059 rj(), si12_ze);
3060 if (!ProbeMemory(rj() + si12_se, sizeof(int16_t))) return;
3061 WriteH(rj() + si12_se, static_cast<int16_t>(rd()), instr_.instr());
3062 break;
3063 case ST_W:
3064 printf_instr("ST_W\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3065 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3066 rj(), si12_ze);
3067 if (!ProbeMemory(rj() + si12_se, sizeof(int32_t))) return;
3068 WriteW(rj() + si12_se, static_cast<int32_t>(rd()), instr_.instr());
3069 break;
3070 case ST_D:
3071 printf_instr("ST_D\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3072 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3073 rj(), si12_ze);
3074 if (!ProbeMemory(rj() + si12_se, sizeof(int64_t))) return;
3075 Write2W(rj() + si12_se, rd(), instr_.instr());
3076 break;
3077 case LD_BU:
3078 printf_instr("LD_BU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3079 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3080 rj(), si12_ze);
3081 if (!ProbeMemory(rj() + si12_se, sizeof(uint8_t))) return;
3082 set_register(rd_reg(), ReadBU(rj() + si12_se));
3083 break;
3084 case LD_HU:
3085 printf_instr("LD_HU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3086 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3087 rj(), si12_ze);
3088 if (!ProbeMemory(rj() + si12_se, sizeof(uint16_t))) return;
3089 set_register(rd_reg(), ReadHU(rj() + si12_se, instr_.instr()));
3090 break;
3091 case LD_WU:
3092 printf_instr("LD_WU\t %s: %016lx, %s: %016lx, si12: %016lx\n",
3093 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3094 rj(), si12_ze);
3095 if (!ProbeMemory(rj() + si12_se, sizeof(uint32_t))) return;
3096 set_register(rd_reg(), ReadWU(rj() + si12_se, instr_.instr()));
3097 break;
3098 case FLD_S: {
3099 printf_instr("FLD_S\t %s: %016f, %s: %016lx, si12: %016lx\n",
3100 FPURegisters::Name(fd_reg()), fd_float(),
3101 Registers::Name(rj_reg()), rj(), si12_ze);
3102 if (!ProbeMemory(rj() + si12_se, sizeof(float))) return;
3103 set_fpu_register(fd_reg(), kFPUInvalidResult); // Trash upper 32 bits.
3104 set_fpu_register_word(
3105 fd_reg(), ReadW(rj() + si12_se, instr_.instr(), FLOAT_DOUBLE));
3106 break;
3107 }
3108 case FST_S: {
3109 printf_instr("FST_S\t %s: %016f, %s: %016lx, si12: %016lx\n",
3110 FPURegisters::Name(fd_reg()), fd_float(),
3111 Registers::Name(rj_reg()), rj(), si12_ze);
3112 if (!ProbeMemory(rj() + si12_se, sizeof(float))) return;
3113 int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(fd_reg()));
3114 WriteW(rj() + si12_se, alu_out_32, instr_.instr());
3115 break;
3116 }
3117 case FLD_D: {
3118 printf_instr("FLD_D\t %s: %016f, %s: %016lx, si12: %016lx\n",
3119 FPURegisters::Name(fd_reg()), fd_double(),
3120 Registers::Name(rj_reg()), rj(), si12_ze);
3121 if (!ProbeMemory(rj() + si12_se, sizeof(double))) return;
3122 set_fpu_register_double(fd_reg(), ReadD(rj() + si12_se, instr_.instr()));
3123 TraceMemRd(rj() + si12_se, get_fpu_register(fd_reg()), DOUBLE);
3124 break;
3125 }
3126 case FST_D: {
3127 printf_instr("FST_D\t %s: %016f, %s: %016lx, si12: %016lx\n",
3128 FPURegisters::Name(fd_reg()), fd_double(),
3129 Registers::Name(rj_reg()), rj(), si12_ze);
3130 if (!ProbeMemory(rj() + si12_se, sizeof(double))) return;
3131 WriteD(rj() + si12_se, get_fpu_register_double(fd_reg()), instr_.instr());
3132 TraceMemWr(rj() + si12_se, get_fpu_register(fd_reg()), DWORD);
3133 break;
3134 }
3135 default:
3136 UNREACHABLE();
3137 }
3138}
3139
3140void Simulator::DecodeTypeOp12() {
3141 switch (instr_.Bits(31, 20) << 20) {
3142 case FMADD_S:
3143 printf_instr("FMADD_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3144 FPURegisters::Name(fd_reg()), fd_float(),
3145 FPURegisters::Name(fk_reg()), fk_float(),
3146 FPURegisters::Name(fa_reg()), fa_float(),
3147 FPURegisters::Name(fj_reg()), fj_float());
3148 SetFPUFloatResult(fd_reg(), std::fma(fj_float(), fk_float(), fa_float()));
3149 break;
3150 case FMADD_D:
3151 printf_instr("FMADD_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3152 FPURegisters::Name(fd_reg()), fd_double(),
3153 FPURegisters::Name(fk_reg()), fk_double(),
3154 FPURegisters::Name(fa_reg()), fa_double(),
3155 FPURegisters::Name(fj_reg()), fj_double());
3156 SetFPUDoubleResult(fd_reg(),
3157 std::fma(fj_double(), fk_double(), fa_double()));
3158 break;
3159 case FMSUB_S:
3160 printf_instr("FMSUB_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3161 FPURegisters::Name(fd_reg()), fd_float(),
3162 FPURegisters::Name(fk_reg()), fk_float(),
3163 FPURegisters::Name(fa_reg()), fa_float(),
3164 FPURegisters::Name(fj_reg()), fj_float());
3165 SetFPUFloatResult(fd_reg(),
3166 std::fma(fj_float(), fk_float(), -fa_float()));
3167 break;
3168 case FMSUB_D:
3169 printf_instr("FMSUB_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3170 FPURegisters::Name(fd_reg()), fd_double(),
3171 FPURegisters::Name(fk_reg()), fk_double(),
3172 FPURegisters::Name(fa_reg()), fa_double(),
3173 FPURegisters::Name(fj_reg()), fj_double());
3174 SetFPUDoubleResult(fd_reg(),
3175 std::fma(fj_double(), fk_double(), -fa_double()));
3176 break;
3177 case FNMADD_S:
3178 printf_instr("FNMADD_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3179 FPURegisters::Name(fd_reg()), fd_float(),
3180 FPURegisters::Name(fk_reg()), fk_float(),
3181 FPURegisters::Name(fa_reg()), fa_float(),
3182 FPURegisters::Name(fj_reg()), fj_float());
3183 SetFPUFloatResult(fd_reg(),
3184 std::fma(-fj_float(), fk_float(), -fa_float()));
3185 break;
3186 case FNMADD_D:
3187 printf_instr("FNMADD_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3188 FPURegisters::Name(fd_reg()), fd_double(),
3189 FPURegisters::Name(fk_reg()), fk_double(),
3190 FPURegisters::Name(fa_reg()), fa_double(),
3191 FPURegisters::Name(fj_reg()), fj_double());
3192 SetFPUDoubleResult(fd_reg(),
3193 std::fma(-fj_double(), fk_double(), -fa_double()));
3194 break;
3195 case FNMSUB_S:
3196 printf_instr("FNMSUB_S\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3197 FPURegisters::Name(fd_reg()), fd_float(),
3198 FPURegisters::Name(fk_reg()), fk_float(),
3199 FPURegisters::Name(fa_reg()), fa_float(),
3200 FPURegisters::Name(fj_reg()), fj_float());
3201 SetFPUFloatResult(fd_reg(),
3202 std::fma(-fj_float(), fk_float(), fa_float()));
3203 break;
3204 case FNMSUB_D:
3205 printf_instr("FNMSUB_D\t %s: %016f, %s: %016f, %s: %016f %s: %016f\n",
3206 FPURegisters::Name(fd_reg()), fd_double(),
3207 FPURegisters::Name(fk_reg()), fk_double(),
3208 FPURegisters::Name(fa_reg()), fa_double(),
3209 FPURegisters::Name(fj_reg()), fj_double());
3210 SetFPUDoubleResult(fd_reg(),
3211 std::fma(-fj_double(), fk_double(), fa_double()));
3212 break;
3213 case FCMP_COND_S: {
3214 CHECK_EQ(instr_.Bits(4, 3), 0);
3215 float fj = fj_float();
3216 float fk = fk_float();
3217 switch (cond()) {
3218 case CAF: {
3219 printf_instr("FCMP_CAF_S fcc%d\n", cd_reg());
3220 set_cf_register(cd_reg(), false);
3221 break;
3222 }
3223 case CUN: {
3224 printf_instr("FCMP_CUN_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3225 FPURegisters::Name(fj_reg()), fj,
3226 FPURegisters::Name(fk_reg()), fk);
3227 set_cf_register(cd_reg(), std::isnan(fj) || std::isnan(fk));
3228 break;
3229 }
3230 case CEQ: {
3231 printf_instr("FCMP_CEQ_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3232 FPURegisters::Name(fj_reg()), fj,
3233 FPURegisters::Name(fk_reg()), fk);
3234 set_cf_register(cd_reg(), fj == fk);
3235 break;
3236 }
3237 case CUEQ: {
3238 printf_instr("FCMP_CUEQ_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3239 FPURegisters::Name(fj_reg()), fj,
3240 FPURegisters::Name(fk_reg()), fk);
3241 set_cf_register(cd_reg(),
3242 (fj == fk) || std::isnan(fj) || std::isnan(fk));
3243 break;
3244 }
3245 case CLT: {
3246 printf_instr("FCMP_CLT_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3247 FPURegisters::Name(fj_reg()), fj,
3248 FPURegisters::Name(fk_reg()), fk);
3249 set_cf_register(cd_reg(), fj < fk);
3250 break;
3251 }
3252 case CULT: {
3253 printf_instr("FCMP_CULT_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3254 FPURegisters::Name(fj_reg()), fj,
3255 FPURegisters::Name(fk_reg()), fk);
3256 set_cf_register(cd_reg(),
3257 (fj < fk) || std::isnan(fj) || std::isnan(fk));
3258 break;
3259 }
3260 case CLE: {
3261 printf_instr("FCMP_CLE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3262 FPURegisters::Name(fj_reg()), fj,
3263 FPURegisters::Name(fk_reg()), fk);
3264 set_cf_register(cd_reg(), fj <= fk);
3265 break;
3266 }
3267 case CULE: {
3268 printf_instr("FCMP_CULE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3269 FPURegisters::Name(fj_reg()), fj,
3270 FPURegisters::Name(fk_reg()), fk);
3271 set_cf_register(cd_reg(),
3272 (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3273 break;
3274 }
3275 case CNE: {
3276 printf_instr("FCMP_CNE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3277 FPURegisters::Name(fj_reg()), fj,
3278 FPURegisters::Name(fk_reg()), fk);
3279 set_cf_register(cd_reg(), (fj < fk) || (fj > fk));
3280 break;
3281 }
3282 case COR: {
3283 printf_instr("FCMP_COR_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3284 FPURegisters::Name(fj_reg()), fj,
3285 FPURegisters::Name(fk_reg()), fk);
3286 set_cf_register(cd_reg(), !std::isnan(fj) && !std::isnan(fk));
3287 break;
3288 }
3289 case CUNE: {
3290 printf_instr("FCMP_CUNE_S fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3291 FPURegisters::Name(fj_reg()), fj,
3292 FPURegisters::Name(fk_reg()), fk);
3293 set_cf_register(cd_reg(),
3294 (fj != fk) || std::isnan(fj) || std::isnan(fk));
3295 break;
3296 }
3297 case SAF:
3298 case SUN:
3299 case SEQ:
3300 case SUEQ:
3301 case SLT:
3302 case SULT:
3303 case SLE:
3304 case SULE:
3305 case SNE:
3306 case SOR:
3307 case SUNE:
3308 UNIMPLEMENTED();
3309 default:
3310 UNREACHABLE();
3311 }
3312 break;
3313 }
3314 case FCMP_COND_D: {
3315 CHECK_EQ(instr_.Bits(4, 3), 0);
3316 double fj = fj_double();
3317 double fk = fk_double();
3318 switch (cond()) {
3319 case CAF: {
3320 printf_instr("FCMP_CAF_D fcc%d\n", cd_reg());
3321 set_cf_register(cd_reg(), false);
3322 break;
3323 }
3324 case CUN: {
3325 printf_instr("FCMP_CUN_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3326 FPURegisters::Name(fj_reg()), fj,
3327 FPURegisters::Name(fk_reg()), fk);
3328 set_cf_register(cd_reg(), std::isnan(fj) || std::isnan(fk));
3329 break;
3330 }
3331 case CEQ: {
3332 printf_instr("FCMP_CEQ_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3333 FPURegisters::Name(fj_reg()), fj,
3334 FPURegisters::Name(fk_reg()), fk);
3335 set_cf_register(cd_reg(), fj == fk);
3336 break;
3337 }
3338 case CUEQ: {
3339 printf_instr("FCMP_CUEQ_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3340 FPURegisters::Name(fj_reg()), fj,
3341 FPURegisters::Name(fk_reg()), fk);
3342 set_cf_register(cd_reg(),
3343 (fj == fk) || std::isnan(fj) || std::isnan(fk));
3344 break;
3345 }
3346 case CLT: {
3347 printf_instr("FCMP_CLT_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3348 FPURegisters::Name(fj_reg()), fj,
3349 FPURegisters::Name(fk_reg()), fk);
3350 set_cf_register(cd_reg(), fj < fk);
3351 break;
3352 }
3353 case CULT: {
3354 printf_instr("FCMP_CULT_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3355 FPURegisters::Name(fj_reg()), fj,
3356 FPURegisters::Name(fk_reg()), fk);
3357 set_cf_register(cd_reg(),
3358 (fj < fk) || std::isnan(fj) || std::isnan(fk));
3359 break;
3360 }
3361 case CLE: {
3362 printf_instr("FCMP_CLE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3363 FPURegisters::Name(fj_reg()), fj,
3364 FPURegisters::Name(fk_reg()), fk);
3365 set_cf_register(cd_reg(), fj <= fk);
3366 break;
3367 }
3368 case CULE: {
3369 printf_instr("FCMP_CULE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3370 FPURegisters::Name(fj_reg()), fj,
3371 FPURegisters::Name(fk_reg()), fk);
3372 set_cf_register(cd_reg(),
3373 (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3374 break;
3375 }
3376 case CNE: {
3377 printf_instr("FCMP_CNE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3378 FPURegisters::Name(fj_reg()), fj,
3379 FPURegisters::Name(fk_reg()), fk);
3380 set_cf_register(cd_reg(), (fj < fk) || (fj > fk));
3381 break;
3382 }
3383 case COR: {
3384 printf_instr("FCMP_COR_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3385 FPURegisters::Name(fj_reg()), fj,
3386 FPURegisters::Name(fk_reg()), fk);
3387 set_cf_register(cd_reg(), !std::isnan(fj) && !std::isnan(fk));
3388 break;
3389 }
3390 case CUNE: {
3391 printf_instr("FCMP_CUNE_D fcc%d, %s: %016f, %s: %016f\n", cd_reg(),
3392 FPURegisters::Name(fj_reg()), fj,
3393 FPURegisters::Name(fk_reg()), fk);
3394 set_cf_register(cd_reg(),
3395 (fj != fk) || std::isnan(fj) || std::isnan(fk));
3396 break;
3397 }
3398 case SAF:
3399 case SUN:
3400 case SEQ:
3401 case SUEQ:
3402 case SLT:
3403 case SULT:
3404 case SLE:
3405 case SULE:
3406 case SNE:
3407 case SOR:
3408 case SUNE:
3409 UNIMPLEMENTED();
3410 default:
3411 UNREACHABLE();
3412 }
3413 break;
3414 }
3415 case FSEL: {
3416 CHECK_EQ(instr_.Bits(19, 18), 0);
3417 printf_instr("FSEL fcc%d, %s: %016f, %s: %016f, %s: %016f\n", ca_reg(),
3418 FPURegisters::Name(fd_reg()), fd_double(),
3419 FPURegisters::Name(fj_reg()), fj_double(),
3420 FPURegisters::Name(fk_reg()), fk_double());
3421 if (ca() == 0) {
3422 SetFPUDoubleResult(fd_reg(), fj_double());
3423 } else {
3424 SetFPUDoubleResult(fd_reg(), fk_double());
3425 }
3426 break;
3427 }
3428 default:
3429 UNREACHABLE();
3430 }
3431}
3432
3433void Simulator::DecodeTypeOp14() {
3434 int64_t alu_out = 0x0;
3435 int32_t alu32_out = 0x0;
3436
3437 switch (instr_.Bits(31, 18) << 18) {
3438 case ALSL: {
3439 uint8_t sa = sa2() + 1;
3440 alu32_out =
3441 (static_cast<int32_t>(rj()) << sa) + static_cast<int32_t>(rk());
3442 if (instr_.Bit(17) == 0) {
3443 // ALSL_W
3444 printf_instr("ALSL_W\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3445 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3446 rj(), Registers::Name(rk_reg()), rk(), sa2());
3447 SetResult(rd_reg(), alu32_out);
3448 } else {
3449 // ALSL_WU
3450 printf_instr("ALSL_WU\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3451 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3452 rj(), Registers::Name(rk_reg()), rk(), sa2());
3453 SetResult(rd_reg(), static_cast<uint32_t>(alu32_out));
3454 }
3455 break;
3456 }
3457 case BYTEPICK_W: {
3458 CHECK_EQ(instr_.Bit(17), 0);
3459 printf_instr("BYTEPICK_W\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3460 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3461 rj(), Registers::Name(rk_reg()), rk(), sa2());
3462 uint8_t sa = sa2() * 8;
3463 if (sa == 0) {
3464 alu32_out = static_cast<int32_t>(rk());
3465 } else {
3466 int32_t mask = (1 << 31) >> (sa - 1);
3467 int32_t rk_hi = (static_cast<int32_t>(rk()) & (~mask)) << sa;
3468 int32_t rj_lo = (static_cast<uint32_t>(rj()) & mask) >> (32 - sa);
3469 alu32_out = rk_hi | rj_lo;
3470 }
3471 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3472 break;
3473 }
3474 case BYTEPICK_D: {
3475 printf_instr("BYTEPICK_D\t %s: %016lx, %s: %016lx, %s: %016lx, sa3: %d\n",
3476 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3477 rj(), Registers::Name(rk_reg()), rk(), sa3());
3478 uint8_t sa = sa3() * 8;
3479 if (sa == 0) {
3480 alu_out = rk();
3481 } else {
3482 int64_t mask = (1LL << 63) >> (sa - 1);
3483 int64_t rk_hi = (rk() & (~mask)) << sa;
3484 int64_t rj_lo = static_cast<uint64_t>(rj() & mask) >> (64 - sa);
3485 alu_out = rk_hi | rj_lo;
3486 }
3487 SetResult(rd_reg(), alu_out);
3488 break;
3489 }
3490 case ALSL_D: {
3491 printf_instr("ALSL_D\t %s: %016lx, %s: %016lx, %s: %016lx, sa2: %d\n",
3492 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3493 rj(), Registers::Name(rk_reg()), rk(), sa2());
3494 CHECK_EQ(instr_.Bit(17), 0);
3495 uint8_t sa = sa2() + 1;
3496 alu_out = (rj() << sa) + rk();
3497 SetResult(rd_reg(), alu_out);
3498 break;
3499 }
3500 case SLLI: {
3501 DCHECK_EQ(instr_.Bit(17), 0);
3502 if (instr_.Bits(17, 15) == 0b001) {
3503 // SLLI_W
3504 printf_instr("SLLI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3505 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3506 rj(), ui5());
3507 alu32_out = static_cast<int32_t>(rj()) << ui5();
3508 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3509 } else if ((instr_.Bits(17, 16) == 0b01)) {
3510 // SLLI_D
3511 printf_instr("SLLI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3512 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3513 rj(), ui6());
3514 SetResult(rd_reg(), rj() << ui6());
3515 }
3516 break;
3517 }
3518 case SRLI: {
3519 DCHECK_EQ(instr_.Bit(17), 0);
3520 if (instr_.Bits(17, 15) == 0b001) {
3521 // SRLI_W
3522 printf_instr("SRLI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3523 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3524 rj(), ui5());
3525 alu32_out = static_cast<uint32_t>(rj()) >> ui5();
3526 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3527 } else if (instr_.Bits(17, 16) == 0b01) {
3528 // SRLI_D
3529 printf_instr("SRLI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3530 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3531 rj(), ui6());
3532 SetResult(rd_reg(), rj_u() >> ui6());
3533 }
3534 break;
3535 }
3536 case SRAI: {
3537 DCHECK_EQ(instr_.Bit(17), 0);
3538 if (instr_.Bits(17, 15) == 0b001) {
3539 // SRAI_W
3540 printf_instr("SRAI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3541 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3542 rj(), ui5());
3543 alu32_out = static_cast<int32_t>(rj()) >> ui5();
3544 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3545 } else if (instr_.Bits(17, 16) == 0b01) {
3546 // SRAI_D
3547 printf_instr("SRAI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3548 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3549 rj(), ui6());
3550 SetResult(rd_reg(), rj() >> ui6());
3551 }
3552 break;
3553 }
3554 case ROTRI: {
3555 DCHECK_EQ(instr_.Bit(17), 0);
3556 if (instr_.Bits(17, 15) == 0b001) {
3557 // ROTRI_W
3558 printf_instr("ROTRI_W\t %s: %016lx, %s: %016lx, ui5: %d\n",
3559 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3560 rj(), ui5());
3561 alu32_out = static_cast<int32_t>(
3562 base::bits::RotateRight32(static_cast<const uint32_t>(rj_u()),
3563 static_cast<const uint32_t>(ui5())));
3564 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3565 } else if (instr_.Bits(17, 16) == 0b01) {
3566 // ROTRI_D
3567 printf_instr("ROTRI_D\t %s: %016lx, %s: %016lx, ui6: %d\n",
3568 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3569 rj(), ui6());
3570 alu_out =
3571 static_cast<int64_t>(base::bits::RotateRight64(rj_u(), ui6()));
3572 SetResult(rd_reg(), alu_out);
3573 printf_instr("ROTRI, %s, %s, %d\n", Registers::Name(rd_reg()),
3574 Registers::Name(rj_reg()), ui6());
3575 }
3576 break;
3577 }
3578 default:
3579 UNREACHABLE();
3580 }
3581}
3582
3583void Simulator::DecodeTypeOp17() {
3584 int64_t alu_out;
3585
3586 switch (instr_.Bits(31, 15) << 15) {
3587 case ADD_W: {
3588 printf_instr("ADD_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3589 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3590 rj(), Registers::Name(rk_reg()), rk());
3591 int32_t alu32_out = static_cast<int32_t>(rj() + rk());
3592 // Sign-extend result of 32bit operation into 64bit register.
3593 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3594 break;
3595 }
3596 case ADD_D:
3597 printf_instr("ADD_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3598 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3599 rj(), Registers::Name(rk_reg()), rk());
3600 SetResult(rd_reg(), rj() + rk());
3601 break;
3602 case SUB_W: {
3603 printf_instr("SUB_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3604 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3605 rj(), Registers::Name(rk_reg()), rk());
3606 int32_t alu32_out = static_cast<int32_t>(rj() - rk());
3607 // Sign-extend result of 32bit operation into 64bit register.
3608 SetResult(rd_reg(), static_cast<int64_t>(alu32_out));
3609 break;
3610 }
3611 case SUB_D:
3612 printf_instr("SUB_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3613 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3614 rj(), Registers::Name(rk_reg()), rk());
3615 SetResult(rd_reg(), rj() - rk());
3616 break;
3617 case SLT:
3618 printf_instr("SLT\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3619 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3620 rj(), Registers::Name(rk_reg()), rk());
3621 SetResult(rd_reg(), rj() < rk() ? 1 : 0);
3622 break;
3623 case SLTU:
3624 printf_instr("SLTU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3625 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3626 rj(), Registers::Name(rk_reg()), rk());
3627 SetResult(rd_reg(), rj_u() < rk_u() ? 1 : 0);
3628 break;
3629 case MASKEQZ:
3630 printf_instr("MASKEQZ\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3631 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3632 rj(), Registers::Name(rk_reg()), rk());
3633 SetResult(rd_reg(), rk() == 0 ? 0 : rj());
3634 break;
3635 case MASKNEZ:
3636 printf_instr("MASKNEZ\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3637 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3638 rj(), Registers::Name(rk_reg()), rk());
3639 SetResult(rd_reg(), rk() != 0 ? 0 : rj());
3640 break;
3641 case NOR:
3642 printf_instr("NOR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3643 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3644 rj(), Registers::Name(rk_reg()), rk());
3645 SetResult(rd_reg(), ~(rj() | rk()));
3646 break;
3647 case AND:
3648 printf_instr("AND\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3649 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3650 rj(), Registers::Name(rk_reg()), rk());
3651 SetResult(rd_reg(), rj() & rk());
3652 break;
3653 case OR:
3654 printf_instr("OR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3655 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3656 rj(), Registers::Name(rk_reg()), rk());
3657 SetResult(rd_reg(), rj() | rk());
3658 break;
3659 case XOR:
3660 printf_instr("XOR\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3661 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3662 rj(), Registers::Name(rk_reg()), rk());
3663 SetResult(rd_reg(), rj() ^ rk());
3664 break;
3665 case ORN:
3666 printf_instr("ORN\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3667 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3668 rj(), Registers::Name(rk_reg()), rk());
3669 SetResult(rd_reg(), rj() | (~rk()));
3670 break;
3671 case ANDN:
3672 printf_instr("ANDN\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3673 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3674 rj(), Registers::Name(rk_reg()), rk());
3675 SetResult(rd_reg(), rj() & (~rk()));
3676 break;
3677 case SLL_W:
3678 printf_instr("SLL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3679 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3680 rj(), Registers::Name(rk_reg()), rk());
3681 SetResult(rd_reg(), (int32_t)rj() << (rk_u() % 32));
3682 break;
3683 case SRL_W: {
3684 printf_instr("SRL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3685 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3686 rj(), Registers::Name(rk_reg()), rk());
3687 alu_out = static_cast<int32_t>((uint32_t)rj_u() >> (rk_u() % 32));
3688 SetResult(rd_reg(), alu_out);
3689 break;
3690 }
3691 case SRA_W:
3692 printf_instr("SRA_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3693 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3694 rj(), Registers::Name(rk_reg()), rk());
3695 SetResult(rd_reg(), (int32_t)rj() >> (rk_u() % 32));
3696 break;
3697 case SLL_D:
3698 printf_instr("SLL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3699 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3700 rj(), Registers::Name(rk_reg()), rk());
3701 SetResult(rd_reg(), rj() << (rk_u() % 64));
3702 break;
3703 case SRL_D: {
3704 printf_instr("SRL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3705 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3706 rj(), Registers::Name(rk_reg()), rk());
3707 alu_out = static_cast<int64_t>(rj_u() >> (rk_u() % 64));
3708 SetResult(rd_reg(), alu_out);
3709 break;
3710 }
3711 case SRA_D:
3712 printf_instr("SRA_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3713 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3714 rj(), Registers::Name(rk_reg()), rk());
3715 SetResult(rd_reg(), rj() >> (rk_u() % 64));
3716 break;
3717 case ROTR_W: {
3718 printf_instr("ROTR_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3719 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3720 rj(), Registers::Name(rk_reg()), rk());
3721 alu_out = static_cast<int32_t>(
3722 base::bits::RotateRight32(static_cast<const uint32_t>(rj_u()),
3723 static_cast<const uint32_t>(rk_u() % 32)));
3724 SetResult(rd_reg(), alu_out);
3725 break;
3726 }
3727 case ROTR_D: {
3728 printf_instr("ROTR_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3729 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3730 rj(), Registers::Name(rk_reg()), rk());
3731 alu_out = static_cast<int64_t>(
3732 base::bits::RotateRight64((rj_u()), (rk_u() % 64)));
3733 SetResult(rd_reg(), alu_out);
3734 break;
3735 }
3736 case MUL_W: {
3737 printf_instr("MUL_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3738 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3739 rj(), Registers::Name(rk_reg()), rk());
3740 alu_out = static_cast<int32_t>(rj()) * static_cast<int32_t>(rk());
3741 SetResult(rd_reg(), alu_out);
3742 break;
3743 }
3744 case MULH_W: {
3745 printf_instr("MULH_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3746 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3747 rj(), Registers::Name(rk_reg()), rk());
3748 int32_t rj_lo = static_cast<int32_t>(rj());
3749 int32_t rk_lo = static_cast<int32_t>(rk());
3750 alu_out = static_cast<int64_t>(rj_lo) * static_cast<int64_t>(rk_lo);
3751 SetResult(rd_reg(), alu_out >> 32);
3752 break;
3753 }
3754 case MULH_WU: {
3755 printf_instr("MULH_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3756 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3757 rj(), Registers::Name(rk_reg()), rk());
3758 uint32_t rj_lo = static_cast<uint32_t>(rj_u());
3759 uint32_t rk_lo = static_cast<uint32_t>(rk_u());
3760 alu_out = static_cast<uint64_t>(rj_lo) * static_cast<uint64_t>(rk_lo);
3761 SetResult(rd_reg(), alu_out >> 32);
3762 break;
3763 }
3764 case MUL_D:
3765 printf_instr("MUL_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3766 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3767 rj(), Registers::Name(rk_reg()), rk());
3768 SetResult(rd_reg(), rj() * rk());
3769 break;
3770 case MULH_D:
3771 printf_instr("MULH_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3772 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3773 rj(), Registers::Name(rk_reg()), rk());
3774 SetResult(rd_reg(), base::bits::SignedMulHigh64(rj(), rk()));
3775 break;
3776 case MULH_DU:
3777 printf_instr("MULH_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3778 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3779 rj(), Registers::Name(rk_reg()), rk());
3780 SetResult(rd_reg(), base::bits::UnsignedMulHigh64(rj_u(), rk_u()));
3781 break;
3782 case MULW_D_W: {
3783 printf_instr("MULW_D_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3784 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3785 rj(), Registers::Name(rk_reg()), rk());
3786 int64_t rj_i32 = static_cast<int32_t>(rj());
3787 int64_t rk_i32 = static_cast<int32_t>(rk());
3788 SetResult(rd_reg(), rj_i32 * rk_i32);
3789 break;
3790 }
3791 case MULW_D_WU: {
3792 printf_instr("MULW_D_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3793 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3794 rj(), Registers::Name(rk_reg()), rk());
3795 uint64_t rj_u32 = static_cast<uint32_t>(rj_u());
3796 uint64_t rk_u32 = static_cast<uint32_t>(rk_u());
3797 SetResult(rd_reg(), rj_u32 * rk_u32);
3798 break;
3799 }
3800 case DIV_W: {
3801 printf_instr("DIV_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3802 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3803 rj(), Registers::Name(rk_reg()), rk());
3804 int32_t rj_i32 = static_cast<int32_t>(rj());
3805 int32_t rk_i32 = static_cast<int32_t>(rk());
3806 if (rj_i32 == INT_MIN && rk_i32 == -1) {
3807 SetResult(rd_reg(), INT_MIN);
3808 } else if (rk_i32 != 0) {
3809 SetResult(rd_reg(), rj_i32 / rk_i32);
3810 }
3811 break;
3812 }
3813 case MOD_W: {
3814 printf_instr("MOD_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3815 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3816 rj(), Registers::Name(rk_reg()), rk());
3817 int32_t rj_i32 = static_cast<int32_t>(rj());
3818 int32_t rk_i32 = static_cast<int32_t>(rk());
3819 if (rj_i32 == INT_MIN && rk_i32 == -1) {
3820 SetResult(rd_reg(), 0);
3821 } else if (rk_i32 != 0) {
3822 SetResult(rd_reg(), rj_i32 % rk_i32);
3823 }
3824 break;
3825 }
3826 case DIV_WU: {
3827 printf_instr("DIV_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3828 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3829 rj(), Registers::Name(rk_reg()), rk());
3830 uint32_t rj_u32 = static_cast<uint32_t>(rj());
3831 uint32_t rk_u32 = static_cast<uint32_t>(rk());
3832 if (rk_u32 != 0) {
3833 SetResult(rd_reg(), static_cast<int32_t>(rj_u32 / rk_u32));
3834 }
3835 break;
3836 }
3837 case MOD_WU: {
3838 printf_instr("MOD_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3839 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3840 rj(), Registers::Name(rk_reg()), rk());
3841 uint32_t rj_u32 = static_cast<uint32_t>(rj());
3842 uint32_t rk_u32 = static_cast<uint32_t>(rk());
3843 if (rk_u32 != 0) {
3844 SetResult(rd_reg(), static_cast<int32_t>(rj_u32 % rk_u32));
3845 }
3846 break;
3847 }
3848 case DIV_D: {
3849 printf_instr("DIV_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3850 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3851 rj(), Registers::Name(rk_reg()), rk());
3852 if (rj() == LONG_MIN && rk() == -1) {
3853 SetResult(rd_reg(), LONG_MIN);
3854 } else if (rk() != 0) {
3855 SetResult(rd_reg(), rj() / rk());
3856 }
3857 break;
3858 }
3859 case MOD_D: {
3860 printf_instr("MOD_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3861 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3862 rj(), Registers::Name(rk_reg()), rk());
3863 if (rj() == LONG_MIN && rk() == -1) {
3864 SetResult(rd_reg(), 0);
3865 } else if (rk() != 0) {
3866 SetResult(rd_reg(), rj() % rk());
3867 }
3868 break;
3869 }
3870 case DIV_DU: {
3871 printf_instr("DIV_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3872 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3873 rj(), Registers::Name(rk_reg()), rk());
3874 if (rk_u() != 0) {
3875 SetResult(rd_reg(), static_cast<int64_t>(rj_u() / rk_u()));
3876 }
3877 break;
3878 }
3879 case MOD_DU: {
3880 printf_instr("MOD_DU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
3881 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
3882 rj(), Registers::Name(rk_reg()), rk());
3883 if (rk_u() != 0) {
3884 SetResult(rd_reg(), static_cast<int64_t>(rj_u() % rk_u()));
3885 }
3886 break;
3887 }
3888 case BREAK:
3889 printf_instr("BREAK\t code: %x\n", instr_.Bits(14, 0));
3890 SoftwareInterrupt();
3891 break;
3892 case FADD_S: {
3893 printf_instr("FADD_S\t %s: %016f, %s, %016f, %s, %016f\n",
3894 FPURegisters::Name(fd_reg()), fd_float(),
3895 FPURegisters::Name(fj_reg()), fj_float(),
3896 FPURegisters::Name(fk_reg()), fk_float());
3897 SetFPUFloatResult(
3898 fd_reg(),
3899 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
3900 fj_float(), fk_float()));
3901 break;
3902 }
3903 case FADD_D: {
3904 printf_instr("FADD_D\t %s: %016f, %s, %016f, %s, %016f\n",
3905 FPURegisters::Name(fd_reg()), fd_double(),
3906 FPURegisters::Name(fj_reg()), fj_double(),
3907 FPURegisters::Name(fk_reg()), fk_double());
3908 SetFPUDoubleResult(fd_reg(),
3909 FPUCanonalizeOperation(
3910 [](double lhs, double rhs) { return lhs + rhs; },
3911 fj_double(), fk_double()));
3912 break;
3913 }
3914 case FSUB_S: {
3915 printf_instr("FSUB_S\t %s: %016f, %s, %016f, %s, %016f\n",
3916 FPURegisters::Name(fd_reg()), fd_float(),
3917 FPURegisters::Name(fj_reg()), fj_float(),
3918 FPURegisters::Name(fk_reg()), fk_float());
3919 SetFPUFloatResult(fd_reg(), fj_float() - fk_float());
3920 break;
3921 }
3922 case FSUB_D: {
3923 printf_instr("FSUB_D\t %s: %016f, %s, %016f, %s, %016f\n",
3924 FPURegisters::Name(fd_reg()), fd_double(),
3925 FPURegisters::Name(fj_reg()), fj_double(),
3926 FPURegisters::Name(fk_reg()), fk_double());
3927 SetFPUDoubleResult(fd_reg(), fj_double() - fk_double());
3928 break;
3929 }
3930 case FMUL_S: {
3931 printf_instr("FMUL_S\t %s: %016f, %s, %016f, %s, %016f\n",
3932 FPURegisters::Name(fd_reg()), fd_float(),
3933 FPURegisters::Name(fj_reg()), fj_float(),
3934 FPURegisters::Name(fk_reg()), fk_float());
3935 SetFPUFloatResult(
3936 fd_reg(),
3937 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
3938 fj_float(), fk_float()));
3939 break;
3940 }
3941 case FMUL_D: {
3942 printf_instr("FMUL_D\t %s: %016f, %s, %016f, %s, %016f\n",
3943 FPURegisters::Name(fd_reg()), fd_double(),
3944 FPURegisters::Name(fj_reg()), fj_double(),
3945 FPURegisters::Name(fk_reg()), fk_double());
3946 SetFPUDoubleResult(fd_reg(),
3947 FPUCanonalizeOperation(
3948 [](double lhs, double rhs) { return lhs * rhs; },
3949 fj_double(), fk_double()));
3950 break;
3951 }
3952 case FDIV_S: {
3953 printf_instr("FDIV_S\t %s: %016f, %s, %016f, %s, %016f\n",
3954 FPURegisters::Name(fd_reg()), fd_float(),
3955 FPURegisters::Name(fj_reg()), fj_float(),
3956 FPURegisters::Name(fk_reg()), fk_float());
3957 SetFPUFloatResult(
3958 fd_reg(),
3959 FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
3960 fj_float(), fk_float()));
3961 break;
3962 }
3963 case FDIV_D: {
3964 printf_instr("FDIV_D\t %s: %016f, %s, %016f, %s, %016f\n",
3965 FPURegisters::Name(fd_reg()), fd_double(),
3966 FPURegisters::Name(fj_reg()), fj_double(),
3967 FPURegisters::Name(fk_reg()), fk_double());
3968 SetFPUDoubleResult(fd_reg(),
3969 FPUCanonalizeOperation(
3970 [](double lhs, double rhs) { return lhs / rhs; },
3971 fj_double(), fk_double()));
3972 break;
3973 }
3974 case FMAX_S:
3975 printf_instr("FMAX_S\t %s: %016f, %s, %016f, %s, %016f\n",
3976 FPURegisters::Name(fd_reg()), fd_float(),
3977 FPURegisters::Name(fj_reg()), fj_float(),
3978 FPURegisters::Name(fk_reg()), fk_float());
3979 SetFPUFloatResult(fd_reg(), FPUMax(fk_float(), fj_float()));
3980 break;
3981 case FMAX_D:
3982 printf_instr("FMAX_D\t %s: %016f, %s, %016f, %s, %016f\n",
3983 FPURegisters::Name(fd_reg()), fd_double(),
3984 FPURegisters::Name(fj_reg()), fj_double(),
3985 FPURegisters::Name(fk_reg()), fk_double());
3986 SetFPUDoubleResult(fd_reg(), FPUMax(fk_double(), fj_double()));
3987 break;
3988 case FMIN_S:
3989 printf_instr("FMIN_S\t %s: %016f, %s, %016f, %s, %016f\n",
3990 FPURegisters::Name(fd_reg()), fd_float(),
3991 FPURegisters::Name(fj_reg()), fj_float(),
3992 FPURegisters::Name(fk_reg()), fk_float());
3993 SetFPUFloatResult(fd_reg(), FPUMin(fk_float(), fj_float()));
3994 break;
3995 case FMIN_D:
3996 printf_instr("FMIN_D\t %s: %016f, %s, %016f, %s, %016f\n",
3997 FPURegisters::Name(fd_reg()), fd_double(),
3998 FPURegisters::Name(fj_reg()), fj_double(),
3999 FPURegisters::Name(fk_reg()), fk_double());
4000 SetFPUDoubleResult(fd_reg(), FPUMin(fk_double(), fj_double()));
4001 break;
4002 case FMAXA_S:
4003 printf_instr("FMAXA_S\t %s: %016f, %s, %016f, %s, %016f\n",
4004 FPURegisters::Name(fd_reg()), fd_float(),
4005 FPURegisters::Name(fj_reg()), fj_float(),
4006 FPURegisters::Name(fk_reg()), fk_float());
4007 SetFPUFloatResult(fd_reg(), FPUMaxA(fk_float(), fj_float()));
4008 break;
4009 case FMAXA_D:
4010 printf_instr("FMAXA_D\t %s: %016f, %s, %016f, %s, %016f\n",
4011 FPURegisters::Name(fd_reg()), fd_double(),
4012 FPURegisters::Name(fj_reg()), fj_double(),
4013 FPURegisters::Name(fk_reg()), fk_double());
4014 SetFPUDoubleResult(fd_reg(), FPUMaxA(fk_double(), fj_double()));
4015 break;
4016 case FMINA_S:
4017 printf_instr("FMINA_S\t %s: %016f, %s, %016f, %s, %016f\n",
4018 FPURegisters::Name(fd_reg()), fd_float(),
4019 FPURegisters::Name(fj_reg()), fj_float(),
4020 FPURegisters::Name(fk_reg()), fk_float());
4021 SetFPUFloatResult(fd_reg(), FPUMinA(fk_float(), fj_float()));
4022 break;
4023 case FMINA_D:
4024 printf_instr("FMINA_D\t %s: %016f, %s, %016f, %s, %016f\n",
4025 FPURegisters::Name(fd_reg()), fd_double(),
4026 FPURegisters::Name(fj_reg()), fj_double(),
4027 FPURegisters::Name(fk_reg()), fk_double());
4028 SetFPUDoubleResult(fd_reg(), FPUMinA(fk_double(), fj_double()));
4029 break;
4030 case LDX_B:
4031 printf_instr("LDX_B\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4032 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4033 rj(), Registers::Name(rk_reg()), rk());
4034 if (!ProbeMemory(rj() + rk(), sizeof(int8_t))) return;
4035 set_register(rd_reg(), ReadB(rj() + rk()));
4036 break;
4037 case LDX_H:
4038 printf_instr("LDX_H\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4039 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4040 rj(), Registers::Name(rk_reg()), rk());
4041 if (!ProbeMemory(rj() + rk(), sizeof(int16_t))) return;
4042 set_register(rd_reg(), ReadH(rj() + rk(), instr_.instr()));
4043 break;
4044 case LDX_W:
4045 printf_instr("LDX_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4046 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4047 rj(), Registers::Name(rk_reg()), rk());
4048 if (!ProbeMemory(rj() + rk(), sizeof(int32_t))) return;
4049 set_register(rd_reg(), ReadW(rj() + rk(), instr_.instr()));
4050 break;
4051 case LDX_D:
4052 printf_instr("LDX_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4053 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4054 rj(), Registers::Name(rk_reg()), rk());
4055 if (!ProbeMemory(rj() + rk(), sizeof(int64_t))) return;
4056 set_register(rd_reg(), Read2W(rj() + rk(), instr_.instr()));
4057 break;
4058 case STX_B:
4059 printf_instr("STX_B\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4060 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4061 rj(), Registers::Name(rk_reg()), rk());
4062 if (!ProbeMemory(rj() + rk(), sizeof(int8_t))) return;
4063 WriteB(rj() + rk(), static_cast<int8_t>(rd()));
4064 break;
4065 case STX_H:
4066 printf_instr("STX_H\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4067 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4068 rj(), Registers::Name(rk_reg()), rk());
4069 if (!ProbeMemory(rj() + rk(), sizeof(int16_t))) return;
4070 WriteH(rj() + rk(), static_cast<int16_t>(rd()), instr_.instr());
4071 break;
4072 case STX_W:
4073 printf_instr("STX_W\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4074 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4075 rj(), Registers::Name(rk_reg()), rk());
4076 if (!ProbeMemory(rj() + rk(), sizeof(int32_t))) return;
4077 WriteW(rj() + rk(), static_cast<int32_t>(rd()), instr_.instr());
4078 break;
4079 case STX_D:
4080 printf_instr("STX_D\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4081 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4082 rj(), Registers::Name(rk_reg()), rk());
4083 if (!ProbeMemory(rj() + rk(), sizeof(int64_t))) return;
4084 Write2W(rj() + rk(), rd(), instr_.instr());
4085 break;
4086 case LDX_BU:
4087 printf_instr("LDX_BU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4088 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4089 rj(), Registers::Name(rk_reg()), rk());
4090 if (!ProbeMemory(rj() + rk(), sizeof(uint8_t))) return;
4091 set_register(rd_reg(), ReadBU(rj() + rk()));
4092 break;
4093 case LDX_HU:
4094 printf_instr("LDX_HU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4095 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4096 rj(), Registers::Name(rk_reg()), rk());
4097 if (!ProbeMemory(rj() + rk(), sizeof(uint16_t))) return;
4098 set_register(rd_reg(), ReadHU(rj() + rk(), instr_.instr()));
4099 break;
4100 case LDX_WU:
4101 printf_instr("LDX_WU\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4102 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4103 rj(), Registers::Name(rk_reg()), rk());
4104 if (!ProbeMemory(rj() + rk(), sizeof(uint32_t))) return;
4105 set_register(rd_reg(), ReadWU(rj() + rk(), instr_.instr()));
4106 break;
4107 case FLDX_S:
4108 printf_instr("FLDX_S\t %s: %016f, %s: %016lx, %s: %016lx\n",
4109 FPURegisters::Name(fd_reg()), fd_float(),
4110 Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
4111 rk());
4112 if (!ProbeMemory(rj() + rk(), sizeof(float))) return;
4113 set_fpu_register(fd_reg(), kFPUInvalidResult); // Trash upper 32 bits.
4114 set_fpu_register_word(fd_reg(),
4115 ReadW(rj() + rk(), instr_.instr(), FLOAT_DOUBLE));
4116 break;
4117 case FLDX_D:
4118 printf_instr("FLDX_D\t %s: %016f, %s: %016lx, %s: %016lx\n",
4119 FPURegisters::Name(fd_reg()), fd_double(),
4120 Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
4121 rk());
4122 if (!ProbeMemory(rj() + rk(), sizeof(double))) return;
4123 set_fpu_register_double(fd_reg(), ReadD(rj() + rk(), instr_.instr()));
4124 break;
4125 case FSTX_S:
4126 printf_instr("FSTX_S\t %s: %016f, %s: %016lx, %s: %016lx\n",
4127 FPURegisters::Name(fd_reg()), fd_float(),
4128 Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
4129 rk());
4130 if (!ProbeMemory(rj() + rk(), sizeof(float))) return;
4131 WriteW(rj() + rk(), static_cast<int32_t>(get_fpu_register(fd_reg())),
4132 instr_.instr());
4133 break;
4134 case FSTX_D:
4135 printf_instr("FSTX_D\t %s: %016f, %s: %016lx, %s: %016lx\n",
4136 FPURegisters::Name(fd_reg()), fd_double(),
4137 Registers::Name(rj_reg()), rj(), Registers::Name(rk_reg()),
4138 rk());
4139 if (!ProbeMemory(rj() + rk(), sizeof(double))) return;
4140 WriteD(rj() + rk(), get_fpu_register_double(fd_reg()), instr_.instr());
4141 break;
4142 case AMSWAP_W:
4143 printf("Sim UNIMPLEMENTED: AMSWAP_W\n");
4144 UNIMPLEMENTED();
4145 case AMSWAP_D:
4146 printf("Sim UNIMPLEMENTED: AMSWAP_D\n");
4147 UNIMPLEMENTED();
4148 case AMADD_W:
4149 printf("Sim UNIMPLEMENTED: AMADD_W\n");
4150 UNIMPLEMENTED();
4151 case AMADD_D:
4152 printf("Sim UNIMPLEMENTED: AMADD_D\n");
4153 UNIMPLEMENTED();
4154 case AMAND_W:
4155 printf("Sim UNIMPLEMENTED: AMAND_W\n");
4156 UNIMPLEMENTED();
4157 case AMAND_D:
4158 printf("Sim UNIMPLEMENTED: AMAND_D\n");
4159 UNIMPLEMENTED();
4160 case AMOR_W:
4161 printf("Sim UNIMPLEMENTED: AMOR_W\n");
4162 UNIMPLEMENTED();
4163 case AMOR_D:
4164 printf("Sim UNIMPLEMENTED: AMOR_D\n");
4165 UNIMPLEMENTED();
4166 case AMXOR_W:
4167 printf("Sim UNIMPLEMENTED: AMXOR_W\n");
4168 UNIMPLEMENTED();
4169 case AMXOR_D:
4170 printf("Sim UNIMPLEMENTED: AMXOR_D\n");
4171 UNIMPLEMENTED();
4172 case AMMAX_W:
4173 printf("Sim UNIMPLEMENTED: AMMAX_W\n");
4174 UNIMPLEMENTED();
4175 case AMMAX_D:
4176 printf("Sim UNIMPLEMENTED: AMMAX_D\n");
4177 UNIMPLEMENTED();
4178 case AMMIN_W:
4179 printf("Sim UNIMPLEMENTED: AMMIN_W\n");
4180 UNIMPLEMENTED();
4181 case AMMIN_D:
4182 printf("Sim UNIMPLEMENTED: AMMIN_D\n");
4183 UNIMPLEMENTED();
4184 case AMMAX_WU:
4185 printf("Sim UNIMPLEMENTED: AMMAX_WU\n");
4186 UNIMPLEMENTED();
4187 case AMMAX_DU:
4188 printf("Sim UNIMPLEMENTED: AMMAX_DU\n");
4189 UNIMPLEMENTED();
4190 case AMMIN_WU:
4191 printf("Sim UNIMPLEMENTED: AMMIN_WU\n");
4192 UNIMPLEMENTED();
4193 case AMMIN_DU:
4194 printf("Sim UNIMPLEMENTED: AMMIN_DU\n");
4195 UNIMPLEMENTED();
4196 case AMSWAP_DB_W: {
4197 printf_instr("AMSWAP_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4198 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4199 rk(), Registers::Name(rj_reg()), rj());
4200 if (!ProbeMemory(rj(), sizeof(int32_t))) return;
4201 int32_t success = 0;
4202 do {
4203 {
4204 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4205 set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4206 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4207 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4208 rj(), &global_monitor_thread_);
4209 }
4210 WriteConditionalW(rj(), static_cast<int32_t>(rk()), instr_.instr(),
4211 &success);
4212 } while (!success);
4213 } break;
4214 case AMSWAP_DB_D: {
4215 printf_instr("AMSWAP_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4216 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4217 rk(), Registers::Name(rj_reg()), rj());
4218 if (!ProbeMemory(rj(), sizeof(int64_t))) return;
4219 int32_t success = 0;
4220 do {
4221 {
4222 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4223 set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4224 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4225 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4226 rj(), &global_monitor_thread_);
4227 }
4228 WriteConditional2W(rj(), rk(), instr_.instr(), &success);
4229 } while (!success);
4230 } break;
4231 case AMADD_DB_W: {
4232 printf_instr("AMADD_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4233 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4234 rk(), Registers::Name(rj_reg()), rj());
4235 if (!ProbeMemory(rj(), sizeof(int32_t))) return;
4236 int32_t success = 0;
4237 do {
4238 {
4239 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4240 set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4241 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4242 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4243 rj(), &global_monitor_thread_);
4244 }
4245 WriteConditionalW(rj(),
4246 static_cast<int32_t>(static_cast<int32_t>(rk()) +
4247 static_cast<int32_t>(rd())),
4248 instr_.instr(), &success);
4249 } while (!success);
4250 } break;
4251 case AMADD_DB_D: {
4252 printf_instr("AMADD_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4253 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4254 rk(), Registers::Name(rj_reg()), rj());
4255 if (!ProbeMemory(rj(), sizeof(int64_t))) return;
4256 int32_t success = 0;
4257 do {
4258 {
4259 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4260 set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4261 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4262 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4263 rj(), &global_monitor_thread_);
4264 }
4265 WriteConditional2W(rj(), rk() + rd(), instr_.instr(), &success);
4266 } while (!success);
4267 } break;
4268 case AMAND_DB_W: {
4269 printf_instr("AMAND_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4270 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4271 rk(), Registers::Name(rj_reg()), rj());
4272 if (!ProbeMemory(rj(), sizeof(int32_t))) return;
4273 int32_t success = 0;
4274 do {
4275 {
4276 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4277 set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4278 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4279 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4280 rj(), &global_monitor_thread_);
4281 }
4282 WriteConditionalW(rj(),
4283 static_cast<int32_t>(static_cast<int32_t>(rk()) &
4284 static_cast<int32_t>(rd())),
4285 instr_.instr(), &success);
4286 } while (!success);
4287 } break;
4288 case AMAND_DB_D: {
4289 printf_instr("AMAND_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4290 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4291 rk(), Registers::Name(rj_reg()), rj());
4292 if (!ProbeMemory(rj(), sizeof(int64_t))) return;
4293 int32_t success = 0;
4294 do {
4295 {
4296 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4297 set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4298 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4299 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4300 rj(), &global_monitor_thread_);
4301 }
4302 WriteConditional2W(rj(), rk() & rd(), instr_.instr(), &success);
4303 } while (!success);
4304 } break;
4305 case AMOR_DB_W: {
4306 printf_instr("AMOR_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4307 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4308 rk(), Registers::Name(rj_reg()), rj());
4309 if (!ProbeMemory(rj(), sizeof(int32_t))) return;
4310 int32_t success = 0;
4311 do {
4312 {
4313 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4314 set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4315 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4316 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4317 rj(), &global_monitor_thread_);
4318 }
4319 WriteConditionalW(rj(),
4320 static_cast<int32_t>(static_cast<int32_t>(rk()) |
4321 static_cast<int32_t>(rd())),
4322 instr_.instr(), &success);
4323 } while (!success);
4324 } break;
4325 case AMOR_DB_D: {
4326 printf_instr("AMOR_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4327 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4328 rk(), Registers::Name(rj_reg()), rj());
4329 if (!ProbeMemory(rj(), sizeof(int64_t))) return;
4330 int32_t success = 0;
4331 do {
4332 {
4333 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4334 set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4335 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4336 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4337 rj(), &global_monitor_thread_);
4338 }
4339 WriteConditional2W(rj(), rk() | rd(), instr_.instr(), &success);
4340 } while (!success);
4341 } break;
4342 case AMXOR_DB_W: {
4343 printf_instr("AMXOR_DB_W:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4344 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4345 rk(), Registers::Name(rj_reg()), rj());
4346 if (!ProbeMemory(rj(), sizeof(int32_t))) return;
4347 int32_t success = 0;
4348 do {
4349 {
4350 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4351 set_register(rd_reg(), ReadW(rj(), instr_.instr()));
4352 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::Word);
4353 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4354 rj(), &global_monitor_thread_);
4355 }
4356 WriteConditionalW(rj(),
4357 static_cast<int32_t>(static_cast<int32_t>(rk()) ^
4358 static_cast<int32_t>(rd())),
4359 instr_.instr(), &success);
4360 } while (!success);
4361 } break;
4362 case AMXOR_DB_D: {
4363 printf_instr("AMXOR_DB_D:\t %s: %016lx, %s, %016lx, %s, %016lx\n",
4364 Registers::Name(rd_reg()), rd(), Registers::Name(rk_reg()),
4365 rk(), Registers::Name(rj_reg()), rj());
4366 if (!ProbeMemory(rj(), sizeof(int64_t))) return;
4367 int32_t success = 0;
4368 do {
4369 {
4370 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4371 set_register(rd_reg(), Read2W(rj(), instr_.instr()));
4372 local_monitor_.NotifyLoadLinked(rj(), TransactionSize::DoubleWord);
4373 GlobalMonitor::Get()->NotifyLoadLinked_Locked(
4374 rj(), &global_monitor_thread_);
4375 }
4376 WriteConditional2W(rj(), rk() ^ rd(), instr_.instr(), &success);
4377 } while (!success);
4378 } break;
4379 case AMMAX_DB_W:
4380 printf("Sim UNIMPLEMENTED: AMMAX_DB_W\n");
4381 UNIMPLEMENTED();
4382 case AMMAX_DB_D:
4383 printf("Sim UNIMPLEMENTED: AMMAX_DB_D\n");
4384 UNIMPLEMENTED();
4385 case AMMIN_DB_W:
4386 printf("Sim UNIMPLEMENTED: AMMIN_DB_W\n");
4387 UNIMPLEMENTED();
4388 case AMMIN_DB_D:
4389 printf("Sim UNIMPLEMENTED: AMMIN_DB_D\n");
4390 UNIMPLEMENTED();
4391 case AMMAX_DB_WU:
4392 printf("Sim UNIMPLEMENTED: AMMAX_DB_WU\n");
4393 UNIMPLEMENTED();
4394 case AMMAX_DB_DU:
4395 printf("Sim UNIMPLEMENTED: AMMAX_DB_DU\n");
4396 UNIMPLEMENTED();
4397 case AMMIN_DB_WU:
4398 printf("Sim UNIMPLEMENTED: AMMIN_DB_WU\n");
4399 UNIMPLEMENTED();
4400 case AMMIN_DB_DU:
4401 printf("Sim UNIMPLEMENTED: AMMIN_DB_DU\n");
4402 UNIMPLEMENTED();
4403 case DBAR:
4404 printf_instr("DBAR\n");
4405 break;
4406 case IBAR:
4407 printf("Sim UNIMPLEMENTED: IBAR\n");
4408 UNIMPLEMENTED();
4409 case FSCALEB_S:
4410 printf("Sim UNIMPLEMENTED: FSCALEB_S\n");
4411 UNIMPLEMENTED();
4412 case FSCALEB_D:
4413 printf("Sim UNIMPLEMENTED: FSCALEB_D\n");
4414 UNIMPLEMENTED();
4415 case FCOPYSIGN_S: {
4416 printf_instr("FCOPYSIGN_S\t %s: %016f, %s, %016f, %s, %016f\n",
4417 FPURegisters::Name(fd_reg()), fd_float(),
4418 FPURegisters::Name(fj_reg()), fj_float(),
4419 FPURegisters::Name(fk_reg()), fk_float());
4420 SetFPUFloatResult(fd_reg(), std::copysign(fj_float(), fk_float()));
4421 } break;
4422 case FCOPYSIGN_D: {
4423 printf_instr("FCOPYSIGN_d\t %s: %016f, %s, %016f, %s, %016f\n",
4424 FPURegisters::Name(fd_reg()), fd_double(),
4425 FPURegisters::Name(fj_reg()), fj_double(),
4426 FPURegisters::Name(fk_reg()), fk_double());
4427 SetFPUDoubleResult(fd_reg(), std::copysign(fj_double(), fk_double()));
4428 } break;
4429 default:
4430 UNREACHABLE();
4431 }
4432}
4433
4434void Simulator::DecodeTypeOp22() {
4435 int64_t alu_out;
4436
4437 switch (instr_.Bits(31, 10) << 10) {
4438 case CLZ_W: {
4439 printf_instr("CLZ_W\t %s: %016lx, %s, %016lx\n",
4440 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4441 rj());
4442 alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rj_u()));
4443 SetResult(rd_reg(), alu_out);
4444 break;
4445 }
4446 case CTZ_W: {
4447 printf_instr("CTZ_W\t %s: %016lx, %s, %016lx\n",
4448 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4449 rj());
4450 alu_out = base::bits::CountTrailingZeros32(static_cast<int32_t>(rj_u()));
4451 SetResult(rd_reg(), alu_out);
4452 break;
4453 }
4454 case CLZ_D: {
4455 printf_instr("CLZ_D\t %s: %016lx, %s, %016lx\n",
4456 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4457 rj());
4458 alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rj_u()));
4459 SetResult(rd_reg(), alu_out);
4460 break;
4461 }
4462 case CTZ_D: {
4463 printf_instr("CTZ_D\t %s: %016lx, %s, %016lx\n",
4464 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4465 rj());
4466 alu_out = base::bits::CountTrailingZeros64(static_cast<int64_t>(rj_u()));
4467 SetResult(rd_reg(), alu_out);
4468 break;
4469 }
4470 case REVB_2H: {
4471 printf_instr("REVB_2H\t %s: %016lx, %s, %016lx\n",
4472 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4473 rj());
4474 uint32_t input = static_cast<uint32_t>(rj());
4475 uint64_t output = 0;
4476
4477 uint32_t mask = 0xFF000000;
4478 for (int i = 0; i < 4; i++) {
4479 uint32_t tmp = mask & input;
4480 if (i % 2 == 0) {
4481 tmp = tmp >> 8;
4482 } else {
4483 tmp = tmp << 8;
4484 }
4485 output = output | tmp;
4486 mask = mask >> 8;
4487 }
4488
4489 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4490 SetResult(rd_reg(), alu_out);
4491 break;
4492 }
4493 case REVB_4H: {
4494 printf_instr("REVB_4H\t %s: %016lx, %s, %016lx\n",
4495 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4496 rj());
4497 uint64_t input = rj_u();
4498 uint64_t output = 0;
4499
4500 uint64_t mask = 0xFF00000000000000;
4501 for (int i = 0; i < 8; i++) {
4502 uint64_t tmp = mask & input;
4503 if (i % 2 == 0) {
4504 tmp = tmp >> 8;
4505 } else {
4506 tmp = tmp << 8;
4507 }
4508 output = output | tmp;
4509 mask = mask >> 8;
4510 }
4511
4512 alu_out = static_cast<int64_t>(output);
4513 SetResult(rd_reg(), alu_out);
4514 break;
4515 }
4516 case REVB_2W: {
4517 printf_instr("REVB_2W\t %s: %016lx, %s, %016lx\n",
4518 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4519 rj());
4520 uint64_t input = rj_u();
4521 uint64_t output = 0;
4522
4523 uint64_t mask = 0xFF000000FF000000;
4524 for (int i = 0; i < 4; i++) {
4525 uint64_t tmp = mask & input;
4526 if (i <= 1) {
4527 tmp = tmp >> (24 - i * 16);
4528 } else {
4529 tmp = tmp << (i * 16 - 24);
4530 }
4531 output = output | tmp;
4532 mask = mask >> 8;
4533 }
4534
4535 alu_out = static_cast<int64_t>(output);
4536 SetResult(rd_reg(), alu_out);
4537 break;
4538 }
4539 case REVB_D: {
4540 printf_instr("REVB_D\t %s: %016lx, %s, %016lx\n",
4541 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4542 rj());
4543 uint64_t input = rj_u();
4544 uint64_t output = 0;
4545
4546 uint64_t mask = 0xFF00000000000000;
4547 for (int i = 0; i < 8; i++) {
4548 uint64_t tmp = mask & input;
4549 if (i <= 3) {
4550 tmp = tmp >> (56 - i * 16);
4551 } else {
4552 tmp = tmp << (i * 16 - 56);
4553 }
4554 output = output | tmp;
4555 mask = mask >> 8;
4556 }
4557
4558 alu_out = static_cast<int64_t>(output);
4559 SetResult(rd_reg(), alu_out);
4560 break;
4561 }
4562 case REVH_2W: {
4563 printf_instr("REVH_2W\t %s: %016lx, %s, %016lx\n",
4564 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4565 rj());
4566 uint64_t input = rj_u();
4567 uint64_t output = 0;
4568
4569 uint64_t mask = 0xFFFF000000000000;
4570 for (int i = 0; i < 4; i++) {
4571 uint64_t tmp = mask & input;
4572 if (i % 2 == 0) {
4573 tmp = tmp >> 16;
4574 } else {
4575 tmp = tmp << 16;
4576 }
4577 output = output | tmp;
4578 mask = mask >> 16;
4579 }
4580
4581 alu_out = static_cast<int64_t>(output);
4582 SetResult(rd_reg(), alu_out);
4583 break;
4584 }
4585 case REVH_D: {
4586 printf_instr("REVH_D\t %s: %016lx, %s, %016lx\n",
4587 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4588 rj());
4589 uint64_t input = rj_u();
4590 uint64_t output = 0;
4591
4592 uint64_t mask = 0xFFFF000000000000;
4593 for (int i = 0; i < 4; i++) {
4594 uint64_t tmp = mask & input;
4595 if (i <= 1) {
4596 tmp = tmp >> (48 - i * 32);
4597 } else {
4598 tmp = tmp << (i * 32 - 48);
4599 }
4600 output = output | tmp;
4601 mask = mask >> 16;
4602 }
4603
4604 alu_out = static_cast<int64_t>(output);
4605 SetResult(rd_reg(), alu_out);
4606 break;
4607 }
4608 case BITREV_4B: {
4609 printf_instr("BITREV_4B\t %s: %016lx, %s, %016lx\n",
4610 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4611 rj());
4612 uint32_t input = static_cast<uint32_t>(rj());
4613 uint32_t output = 0;
4614 uint8_t i_byte, o_byte;
4615
4616 // Reverse the bit in byte for each individual byte
4617 for (int i = 0; i < 4; i++) {
4618 output = output >> 8;
4619 i_byte = input & 0xFF;
4620
4621 // Fast way to reverse bits in byte
4622 // Devised by Sean Anderson, July 13, 2001
4623 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4624 (i_byte * 0x8020LU & 0x88440LU)) *
4625 0x10101LU >>
4626 16);
4627
4628 output = output | (static_cast<uint32_t>(o_byte << 24));
4629 input = input >> 8;
4630 }
4631
4632 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4633 SetResult(rd_reg(), alu_out);
4634 break;
4635 }
4636 case BITREV_8B: {
4637 printf_instr("BITREV_8B\t %s: %016lx, %s, %016lx\n",
4638 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4639 rj());
4640 uint64_t input = rj_u();
4641 uint64_t output = 0;
4642 uint8_t i_byte, o_byte;
4643
4644 // Reverse the bit in byte for each individual byte
4645 for (int i = 0; i < 8; i++) {
4646 output = output >> 8;
4647 i_byte = input & 0xFF;
4648
4649 // Fast way to reverse bits in byte
4650 // Devised by Sean Anderson, July 13, 2001
4651 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4652 (i_byte * 0x8020LU & 0x88440LU)) *
4653 0x10101LU >>
4654 16);
4655
4656 output = output | (static_cast<uint64_t>(o_byte) << 56);
4657 input = input >> 8;
4658 }
4659
4660 alu_out = static_cast<int64_t>(output);
4661 SetResult(rd_reg(), alu_out);
4662 break;
4663 }
4664 case BITREV_W: {
4665 printf_instr("BITREV_W\t %s: %016lx, %s, %016lx\n",
4666 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4667 rj());
4668 uint32_t input = static_cast<uint32_t>(rj());
4669 uint32_t output = 0;
4670 output = base::bits::ReverseBits(input);
4671 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4672 SetResult(rd_reg(), alu_out);
4673 break;
4674 }
4675 case BITREV_D: {
4676 printf_instr("BITREV_D\t %s: %016lx, %s, %016lx\n",
4677 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4678 rj());
4679 alu_out = static_cast<int64_t>(base::bits::ReverseBits(rj_u()));
4680 SetResult(rd_reg(), alu_out);
4681 break;
4682 }
4683 case EXT_W_B: {
4684 printf_instr("EXT_W_B\t %s: %016lx, %s, %016lx\n",
4685 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4686 rj());
4687 uint8_t input = static_cast<uint8_t>(rj());
4688 alu_out = static_cast<int64_t>(static_cast<int8_t>(input));
4689 SetResult(rd_reg(), alu_out);
4690 break;
4691 }
4692 case EXT_W_H: {
4693 printf_instr("EXT_W_H\t %s: %016lx, %s, %016lx\n",
4694 Registers::Name(rd_reg()), rd(), Registers::Name(rj_reg()),
4695 rj());
4696 uint16_t input = static_cast<uint16_t>(rj());
4697 alu_out = static_cast<int64_t>(static_cast<int16_t>(input));
4698 SetResult(rd_reg(), alu_out);
4699 break;
4700 }
4701 case FABS_S:
4702 printf_instr("FABS_S\t %s: %016f, %s, %016f\n",
4703 FPURegisters::Name(fd_reg()), fd_float(),
4704 FPURegisters::Name(fj_reg()), fj_float());
4705 SetFPUFloatResult(fd_reg(), std::abs(fj_float()));
4706 break;
4707 case FABS_D:
4708 printf_instr("FABS_D\t %s: %016f, %s, %016f\n",
4709 FPURegisters::Name(fd_reg()), fd_double(),
4710 FPURegisters::Name(fj_reg()), fj_double());
4711 SetFPUDoubleResult(fd_reg(), std::abs(fj_double()));
4712 break;
4713 case FNEG_S:
4714 printf_instr("FNEG_S\t %s: %016f, %s, %016f\n",
4715 FPURegisters::Name(fd_reg()), fd_float(),
4716 FPURegisters::Name(fj_reg()), fj_float());
4717 SetFPUFloatResult(fd_reg(), -fj_float());
4718 break;
4719 case FNEG_D:
4720 printf_instr("FNEG_D\t %s: %016f, %s, %016f\n",
4721 FPURegisters::Name(fd_reg()), fd_double(),
4722 FPURegisters::Name(fj_reg()), fj_double());
4723 SetFPUDoubleResult(fd_reg(), -fj_double());
4724 break;
4725 case FSQRT_S: {
4726 printf_instr("FSQRT_S\t %s: %016f, %s, %016f\n",
4727 FPURegisters::Name(fd_reg()), fd_float(),
4728 FPURegisters::Name(fj_reg()), fj_float());
4729 if (fj_float() >= 0) {
4730 SetFPUFloatResult(fd_reg(), std::sqrt(fj_float()));
4731 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
4732 } else {
4733 SetFPUFloatResult(fd_reg(), std::sqrt(-1)); // qnan
4734 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
4735 }
4736 break;
4737 }
4738 case FSQRT_D: {
4739 printf_instr("FSQRT_D\t %s: %016f, %s, %016f\n",
4740 FPURegisters::Name(fd_reg()), fd_double(),
4741 FPURegisters::Name(fj_reg()), fj_double());
4742 if (fj_double() >= 0) {
4743 SetFPUDoubleResult(fd_reg(), std::sqrt(fj_double()));
4744 set_fcsr_bit(kFCSRInvalidOpCauseBit, false);
4745 } else {
4746 SetFPUDoubleResult(fd_reg(), std::sqrt(-1)); // qnan
4747 set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
4748 }
4749 break;
4750 }
4751 case FMOV_S:
4752 printf_instr("FMOV_S\t %s: %016f, %s, %016f\n",
4753 FPURegisters::Name(fd_reg()), fd_float(),
4754 FPURegisters::Name(fj_reg()), fj_float());
4755 SetFPUFloatResult(fd_reg(), fj_float());
4756 break;
4757 case FMOV_D:
4758 printf_instr("FMOV_D\t %s: %016f, %s, %016f\n",
4759 FPURegisters::Name(fd_reg()), fd_float(),
4760 FPURegisters::Name(fj_reg()), fj_float());
4761 SetFPUDoubleResult(fd_reg(), fj_double());
4762 break;
4763 case MOVGR2FR_W: {
4764 printf_instr("MOVGR2FR_W\t %s: %016f, %s, %016lx\n",
4765 FPURegisters::Name(fd_reg()), fd_double(),
4766 Registers::Name(rj_reg()), rj());
4767 set_fpu_register_word(fd_reg(), static_cast<int32_t>(rj()));
4768 TraceRegWr(get_fpu_register(fd_reg()), FLOAT_DOUBLE);
4769 break;
4770 }
4771 case MOVGR2FR_D:
4772 printf_instr("MOVGR2FR_D\t %s: %016f, %s, %016lx\n",
4773 FPURegisters::Name(fd_reg()), fd_double(),
4774 Registers::Name(rj_reg()), rj());
4775 SetFPUResult2(fd_reg(), rj());
4776 break;
4777 case MOVGR2FRH_W: {
4778 printf_instr("MOVGR2FRH_W\t %s: %016f, %s, %016lx\n",
4779 FPURegisters::Name(fd_reg()), fd_double(),
4780 Registers::Name(rj_reg()), rj());
4781 set_fpu_register_hi_word(fd_reg(), static_cast<int32_t>(rj()));
4782 TraceRegWr(get_fpu_register(fd_reg()), DOUBLE);
4783 break;
4784 }
4785 case MOVFR2GR_S: {
4786 printf_instr("MOVFR2GR_S\t %s: %016lx, %s, %016f\n",
4787 Registers::Name(rd_reg()), rd(),
4788 FPURegisters::Name(fj_reg()), fj_float());
4789 set_register(rd_reg(),
4790 static_cast<int64_t>(get_fpu_register_word(fj_reg())));
4791 TraceRegWr(get_register(rd_reg()), WORD_DWORD);
4792 break;
4793 }
4794 case MOVFR2GR_D:
4795 printf_instr("MOVFR2GR_D\t %s: %016lx, %s, %016f\n",
4796 Registers::Name(rd_reg()), rd(),
4797 FPURegisters::Name(fj_reg()), fj_double());
4798 SetResult(rd_reg(), get_fpu_register(fj_reg()));
4799 break;
4800 case MOVFRH2GR_S:
4801 printf_instr("MOVFRH2GR_S\t %s: %016lx, %s, %016f\n",
4802 Registers::Name(rd_reg()), rd(),
4803 FPURegisters::Name(fj_reg()), fj_double());
4804 SetResult(rd_reg(), get_fpu_register_hi_word(fj_reg()));
4805 break;
4806 case MOVGR2FCSR: {
4807 printf_instr("MOVGR2FCSR\t fcsr: %016x, %s, %016lx\n", FCSR_,
4808 Registers::Name(rj_reg()), rj());
4809 // fcsr could be 0-3
4810 CHECK_LT(rd_reg(), 4);
4811 FCSR_ = static_cast<uint32_t>(rj());
4812 TraceRegWr(FCSR_);
4813 break;
4814 }
4815 case MOVFCSR2GR: {
4816 printf_instr("MOVFCSR2GR\t %s, %016lx, FCSR: %016x\n",
4817 Registers::Name(rd_reg()), rd(), FCSR_);
4818 // fcsr could be 0-3
4819 CHECK_LT(rj_reg(), 4);
4820 SetResult(rd_reg(), FCSR_);
4821 break;
4822 }
4823 case FCVT_S_D:
4824 printf_instr("FCVT_S_D\t %s: %016f, %s, %016f\n",
4825 FPURegisters::Name(fd_reg()), fd_double(),
4826 FPURegisters::Name(fj_reg()), fj_double());
4827 SetFPUFloatResult(fd_reg(), static_cast<float>(fj_double()));
4828 break;
4829 case FCVT_D_S:
4830 printf_instr("FCVT_D_S\t %s: %016f, %s, %016f\n",
4831 FPURegisters::Name(fd_reg()), fd_double(),
4832 FPURegisters::Name(fj_reg()), fj_float());
4833 SetFPUDoubleResult(fd_reg(), static_cast<double>(fj_float()));
4834 break;
4835 case FTINTRM_W_S: {
4836 printf_instr("FTINTRM_W_S\t %s: %016f, %s, %016f\n",
4837 FPURegisters::Name(fd_reg()), fd_double(),
4838 FPURegisters::Name(fj_reg()), fj_float());
4839 float fj = fj_float();
4840 float rounded = floor(fj);
4841 int32_t result = static_cast<int32_t>(rounded);
4842 SetFPUWordResult(fd_reg(), result);
4843 if (set_fcsr_round_error(fj, rounded)) {
4844 set_fpu_register_word_invalid_result(fj, rounded);
4845 }
4846 break;
4847 }
4848 case FTINTRM_W_D: {
4849 printf_instr("FTINTRM_W_D\t %s: %016f, %s, %016f\n",
4850 FPURegisters::Name(fd_reg()), fd_double(),
4851 FPURegisters::Name(fj_reg()), fj_double());
4852 double fj = fj_double();
4853 double rounded = floor(fj);
4854 int32_t result = static_cast<int32_t>(rounded);
4855 SetFPUWordResult(fd_reg(), result);
4856 if (set_fcsr_round_error(fj, rounded)) {
4857 set_fpu_register_invalid_result(fj, rounded);
4858 }
4859 break;
4860 }
4861 case FTINTRM_L_S: {
4862 printf_instr("FTINTRM_L_S\t %s: %016f, %s, %016f\n",
4863 FPURegisters::Name(fd_reg()), fd_double(),
4864 FPURegisters::Name(fj_reg()), fj_float());
4865 float fj = fj_float();
4866 float rounded = floor(fj);
4867 int64_t result = static_cast<int64_t>(rounded);
4868 SetFPUResult(fd_reg(), result);
4869 if (set_fcsr_round64_error(fj, rounded)) {
4870 set_fpu_register_invalid_result64(fj, rounded);
4871 }
4872 break;
4873 }
4874 case FTINTRM_L_D: {
4875 printf_instr("FTINTRM_L_D\t %s: %016f, %s, %016f\n",
4876 FPURegisters::Name(fd_reg()), fd_double(),
4877 FPURegisters::Name(fj_reg()), fj_double());
4878 double fj = fj_double();
4879 double rounded = floor(fj);
4880 int64_t result = static_cast<int64_t>(rounded);
4881 SetFPUResult(fd_reg(), result);
4882 if (set_fcsr_round64_error(fj, rounded)) {
4883 set_fpu_register_invalid_result64(fj, rounded);
4884 }
4885 break;
4886 }
4887 case FTINTRP_W_S: {
4888 printf_instr("FTINTRP_W_S\t %s: %016f, %s, %016f\n",
4889 FPURegisters::Name(fd_reg()), fd_double(),
4890 FPURegisters::Name(fj_reg()), fj_float());
4891 float fj = fj_float();
4892 float rounded = ceil(fj);
4893 int32_t result = static_cast<int32_t>(rounded);
4894 SetFPUWordResult(fd_reg(), result);
4895 if (set_fcsr_round_error(fj, rounded)) {
4896 set_fpu_register_word_invalid_result(fj, rounded);
4897 }
4898 break;
4899 }
4900 case FTINTRP_W_D: {
4901 printf_instr("FTINTRP_W_D\t %s: %016f, %s, %016f\n",
4902 FPURegisters::Name(fd_reg()), fd_double(),
4903 FPURegisters::Name(fj_reg()), fj_double());
4904 double fj = fj_double();
4905 double rounded = ceil(fj);
4906 int32_t result = static_cast<int32_t>(rounded);
4907 SetFPUWordResult(fd_reg(), result);
4908 if (set_fcsr_round_error(fj, rounded)) {
4909 set_fpu_register_invalid_result(fj, rounded);
4910 }
4911 break;
4912 }
4913 case FTINTRP_L_S: {
4914 printf_instr("FTINTRP_L_S\t %s: %016f, %s, %016f\n",
4915 FPURegisters::Name(fd_reg()), fd_double(),
4916 FPURegisters::Name(fj_reg()), fj_float());
4917 float fj = fj_float();
4918 float rounded = ceil(fj);
4919 int64_t result = static_cast<int64_t>(rounded);
4920 SetFPUResult(fd_reg(), result);
4921 if (set_fcsr_round64_error(fj, rounded)) {
4922 set_fpu_register_invalid_result64(fj, rounded);
4923 }
4924 break;
4925 }
4926 case FTINTRP_L_D: {
4927 printf_instr("FTINTRP_L_D\t %s: %016f, %s, %016f\n",
4928 FPURegisters::Name(fd_reg()), fd_double(),
4929 FPURegisters::Name(fj_reg()), fj_double());
4930 double fj = fj_double();
4931 double rounded = ceil(fj);
4932 int64_t result = static_cast<int64_t>(rounded);
4933 SetFPUResult(fd_reg(), result);
4934 if (set_fcsr_round64_error(fj, rounded)) {
4935 set_fpu_register_invalid_result64(fj, rounded);
4936 }
4937 break;
4938 }
4939 case FTINTRZ_W_S: {
4940 printf_instr("FTINTRZ_W_S\t %s: %016f, %s, %016f\n",
4941 FPURegisters::Name(fd_reg()), fd_double(),
4942 FPURegisters::Name(fj_reg()), fj_float());
4943 float fj = fj_float();
4944 float rounded = trunc(fj);
4945 int32_t result = static_cast<int32_t>(rounded);
4946 SetFPUWordResult(fd_reg(), result);
4947 if (set_fcsr_round_error(fj, rounded)) {
4948 set_fpu_register_word_invalid_result(fj, rounded);
4949 }
4950 break;
4951 }
4952 case FTINTRZ_W_D: {
4953 printf_instr("FTINTRZ_W_D\t %s: %016f, %s, %016f\n",
4954 FPURegisters::Name(fd_reg()), fd_double(),
4955 FPURegisters::Name(fj_reg()), fj_double());
4956 double fj = fj_double();
4957 double rounded = trunc(fj);
4958 int32_t result = static_cast<int32_t>(rounded);
4959 SetFPUWordResult(fd_reg(), result);
4960 if (set_fcsr_round_error(fj, rounded)) {
4961 set_fpu_register_invalid_result(fj, rounded);
4962 }
4963 break;
4964 }
4965 case FTINTRZ_L_S: {
4966 printf_instr("FTINTRZ_L_S\t %s: %016f, %s, %016f\n",
4967 FPURegisters::Name(fd_reg()), fd_double(),
4968 FPURegisters::Name(fj_reg()), fj_float());
4969 float fj = fj_float();
4970 float rounded = trunc(fj);
4971 int64_t result = static_cast<int64_t>(rounded);
4972 SetFPUResult(fd_reg(), result);
4973 if (set_fcsr_round64_error(fj, rounded)) {
4974 set_fpu_register_invalid_result64(fj, rounded);
4975 }
4976 break;
4977 }
4978 case FTINTRZ_L_D: {
4979 printf_instr("FTINTRZ_L_D\t %s: %016f, %s, %016f\n",
4980 FPURegisters::Name(fd_reg()), fd_double(),
4981 FPURegisters::Name(fj_reg()), fj_double());
4982 double fj = fj_double();
4983 double rounded = trunc(fj);
4984 int64_t result = static_cast<int64_t>(rounded);
4985 SetFPUResult(fd_reg(), result);
4986 if (set_fcsr_round64_error(fj, rounded)) {
4987 set_fpu_register_invalid_result64(fj, rounded);
4988 }
4989 break;
4990 }
4991 case FTINTRNE_W_S: {
4992 printf_instr("FTINTRNE_W_S\t %s: %016f, %s, %016f\n",
4993 FPURegisters::Name(fd_reg()), fd_double(),
4994 FPURegisters::Name(fj_reg()), fj_float());
4995 float fj = fj_float();
4996 float rounded = floor(fj + 0.5);
4997 int32_t result = static_cast<int32_t>(rounded);
4998 if ((result & 1) != 0 && result - fj == 0.5) {
4999 // If the number is halfway between two integers,
5000 // round to the even one.
5001 result--;
5002 }
5003 SetFPUWordResult(fd_reg(), result);
5004 if (set_fcsr_round_error(fj, rounded)) {
5005 set_fpu_register_word_invalid_result(fj, rounded);
5006 }
5007 break;
5008 }
5009 case FTINTRNE_W_D: {
5010 printf_instr("FTINTRNE_W_D\t %s: %016f, %s, %016f\n",
5011 FPURegisters::Name(fd_reg()), fd_double(),
5012 FPURegisters::Name(fj_reg()), fj_double());
5013 double fj = fj_double();
5014 double rounded = floor(fj + 0.5);
5015 int32_t result = static_cast<int32_t>(rounded);
5016 if ((result & 1) != 0 && result - fj == 0.5) {
5017 // If the number is halfway between two integers,
5018 // round to the even one.
5019 result--;
5020 }
5021 SetFPUWordResult(fd_reg(), result);
5022 if (set_fcsr_round_error(fj, rounded)) {
5023 set_fpu_register_invalid_result(fj, rounded);
5024 }
5025 break;
5026 }
5027 case FTINTRNE_L_S: {
5028 printf_instr("FTINTRNE_L_S\t %s: %016f, %s, %016f\n",
5029 FPURegisters::Name(fd_reg()), fd_double(),
5030 FPURegisters::Name(fj_reg()), fj_float());
5031 float fj = fj_float();
5032 float rounded = floor(fj + 0.5);
5033 int64_t result = static_cast<int64_t>(rounded);
5034 if ((result & 1) != 0 && result - fj == 0.5) {
5035 // If the number is halfway between two integers,
5036 // round to the even one.
5037 result--;
5038 }
5039 SetFPUResult(fd_reg(), result);
5040 if (set_fcsr_round64_error(fj, rounded)) {
5041 set_fpu_register_invalid_result64(fj, rounded);
5042 }
5043 break;
5044 }
5045 case FTINTRNE_L_D: {
5046 printf_instr("FTINTRNE_L_D\t %s: %016f, %s, %016f\n",
5047 FPURegisters::Name(fd_reg()), fd_double(),
5048 FPURegisters::Name(fj_reg()), fj_double());
5049 double fj = fj_double();
5050 double rounded = floor(fj + 0.5);
5051 int64_t result = static_cast<int64_t>(rounded);
5052 if ((result & 1) != 0 && result - fj == 0.5) {
5053 // If the number is halfway between two integers,
5054 // round to the even one.
5055 result--;
5056 }
5057 SetFPUResult(fd_reg(), result);
5058 if (set_fcsr_round64_error(fj, rounded)) {
5059 set_fpu_register_invalid_result64(fj, rounded);
5060 }
5061 break;
5062 }
5063 case FTINT_W_S: {
5064 printf_instr("FTINT_W_S\t %s: %016f, %s, %016f\n",
5065 FPURegisters::Name(fd_reg()), fd_double(),
5066 FPURegisters::Name(fj_reg()), fj_float());
5067 float fj = fj_float();
5068 float rounded;
5070 round_according_to_fcsr(fj, &rounded, &result);
5071 SetFPUWordResult(fd_reg(), result);
5072 if (set_fcsr_round_error(fj, rounded)) {
5073 set_fpu_register_word_invalid_result(fj, rounded);
5074 }
5075 break;
5076 }
5077 case FTINT_W_D: {
5078 printf_instr("FTINT_W_D\t %s: %016f, %s, %016f\n",
5079 FPURegisters::Name(fd_reg()), fd_double(),
5080 FPURegisters::Name(fj_reg()), fj_double());
5081 double fj = fj_double();
5082 double rounded;
5084 round_according_to_fcsr(fj, &rounded, &result);
5085 SetFPUWordResult(fd_reg(), result);
5086 if (set_fcsr_round_error(fj, rounded)) {
5087 set_fpu_register_word_invalid_result(fj, rounded);
5088 }
5089 break;
5090 }
5091 case FTINT_L_S: {
5092 printf_instr("FTINT_L_S\t %s: %016f, %s, %016f\n",
5093 FPURegisters::Name(fd_reg()), fd_double(),
5094 FPURegisters::Name(fj_reg()), fj_float());
5095 float fj = fj_float();
5096 float rounded;
5097 int64_t result;
5098 round64_according_to_fcsr(fj, &rounded, &result);
5099 SetFPUResult(fd_reg(), result);
5100 if (set_fcsr_round64_error(fj, rounded)) {
5101 set_fpu_register_invalid_result64(fj, rounded);
5102 }
5103 break;
5104 }
5105 case FTINT_L_D: {
5106 printf_instr("FTINT_L_D\t %s: %016f, %s, %016f\n",
5107 FPURegisters::Name(fd_reg()), fd_double(),
5108 FPURegisters::Name(fj_reg()), fj_double());
5109 double fj = fj_double();
5110 double rounded;
5111 int64_t result;
5112 round64_according_to_fcsr(fj, &rounded, &result);
5113 SetFPUResult(fd_reg(), result);
5114 if (set_fcsr_round64_error(fj, rounded)) {
5115 set_fpu_register_invalid_result64(fj, rounded);
5116 }
5117 break;
5118 }
5119 case FFINT_S_W: {
5120 alu_out = get_fpu_register_signed_word(fj_reg());
5121 printf_instr("FFINT_S_W\t %s: %016f, %s, %016x\n",
5122 FPURegisters::Name(fd_reg()), fd_double(),
5123 FPURegisters::Name(fj_reg()), static_cast<int>(alu_out));
5124 SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
5125 break;
5126 }
5127 case FFINT_S_L: {
5128 alu_out = get_fpu_register(fj_reg());
5129 printf_instr("FFINT_S_L\t %s: %016f, %s, %016lx\n",
5130 FPURegisters::Name(fd_reg()), fd_double(),
5131 FPURegisters::Name(fj_reg()), alu_out);
5132 SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
5133 break;
5134 }
5135 case FFINT_D_W: {
5136 alu_out = get_fpu_register_signed_word(fj_reg());
5137 printf_instr("FFINT_D_W\t %s: %016f, %s, %016x\n",
5138 FPURegisters::Name(fd_reg()), fd_double(),
5139 FPURegisters::Name(fj_reg()), static_cast<int>(alu_out));
5140 SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
5141 break;
5142 }
5143 case FFINT_D_L: {
5144 alu_out = get_fpu_register(fj_reg());
5145 printf_instr("FFINT_D_L\t %s: %016f, %s, %016lx\n",
5146 FPURegisters::Name(fd_reg()), fd_double(),
5147 FPURegisters::Name(fj_reg()), alu_out);
5148 SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
5149 break;
5150 }
5151 case FRINT_S: {
5152 printf_instr("FRINT_S\t %s: %016f, %s, %016f mode : ",
5153 FPURegisters::Name(fd_reg()), fd_float(),
5154 FPURegisters::Name(fj_reg()), fj_float());
5155 float fj = fj_float();
5156 float result, temp_result;
5157 double temp;
5158 float upper = ceil(fj);
5159 float lower = floor(fj);
5160 switch (get_fcsr_rounding_mode()) {
5161 case kRoundToNearest:
5162 printf_instr(" kRoundToNearest\n");
5163 if (upper - fj < fj - lower) {
5164 result = upper;
5165 } else if (upper - fj > fj - lower) {
5166 result = lower;
5167 } else {
5168 temp_result = upper / 2;
5169 float reminder = std::modf(temp_result, &temp);
5170 if (reminder == 0) {
5171 result = upper;
5172 } else {
5173 result = lower;
5174 }
5175 }
5176 break;
5177 case kRoundToZero:
5178 printf_instr(" kRoundToZero\n");
5179 result = (fj > 0 ? lower : upper);
5180 break;
5181 case kRoundToPlusInf:
5182 printf_instr(" kRoundToPlusInf\n");
5183 result = upper;
5184 break;
5185 case kRoundToMinusInf:
5186 printf_instr(" kRoundToMinusInf\n");
5187 result = lower;
5188 break;
5189 }
5190 SetFPUFloatResult(fd_reg(), result);
5191 set_fcsr_bit(kFCSRInexactCauseBit, result != fj);
5192 break;
5193 }
5194 case FRINT_D: {
5195 printf_instr("FRINT_D\t %s: %016f, %s, %016f mode : ",
5196 FPURegisters::Name(fd_reg()), fd_double(),
5197 FPURegisters::Name(fj_reg()), fj_double());
5198 double fj = fj_double();
5199 double result, temp, temp_result;
5200 double upper = ceil(fj);
5201 double lower = floor(fj);
5202 switch (get_fcsr_rounding_mode()) {
5203 case kRoundToNearest:
5204 printf_instr(" kRoundToNearest\n");
5205 if (upper - fj < fj - lower) {
5206 result = upper;
5207 } else if (upper - fj > fj - lower) {
5208 result = lower;
5209 } else {
5210 temp_result = upper / 2;
5211 double reminder = std::modf(temp_result, &temp);
5212 if (reminder == 0) {
5213 result = upper;
5214 } else {
5215 result = lower;
5216 }
5217 }
5218 break;
5219 case kRoundToZero:
5220 printf_instr(" kRoundToZero\n");
5221 result = (fj > 0 ? lower : upper);
5222 break;
5223 case kRoundToPlusInf:
5224 printf_instr(" kRoundToPlusInf\n");
5225 result = upper;
5226 break;
5227 case kRoundToMinusInf:
5228 printf_instr(" kRoundToMinusInf\n");
5229 result = lower;
5230 break;
5231 }
5232 SetFPUDoubleResult(fd_reg(), result);
5233 set_fcsr_bit(kFCSRInexactCauseBit, result != fj);
5234 break;
5235 }
5236 case MOVFR2CF:
5237 printf("Sim UNIMPLEMENTED: MOVFR2CF\n");
5238 UNIMPLEMENTED();
5239 case MOVCF2FR:
5240 printf("Sim UNIMPLEMENTED: MOVCF2FR\n");
5241 UNIMPLEMENTED();
5242 case MOVGR2CF:
5243 printf_instr("MOVGR2CF\t FCC%d, %s: %016lx\n", cd_reg(),
5244 Registers::Name(rj_reg()), rj());
5245 set_cf_register(cd_reg(), rj() & 1);
5246 break;
5247 case MOVCF2GR:
5248 printf_instr("MOVCF2GR\t %s: %016lx, FCC%d\n", Registers::Name(rd_reg()),
5249 rd(), cj_reg());
5250 SetResult(rd_reg(), cj());
5251 break;
5252 case FRECIP_S:
5253 printf("Sim UNIMPLEMENTED: FRECIP_S\n");
5254 UNIMPLEMENTED();
5255 case FRECIP_D:
5256 printf("Sim UNIMPLEMENTED: FRECIP_D\n");
5257 UNIMPLEMENTED();
5258 case FRSQRT_S:
5259 printf("Sim UNIMPLEMENTED: FRSQRT_S\n");
5260 UNIMPLEMENTED();
5261 case FRSQRT_D:
5262 printf("Sim UNIMPLEMENTED: FRSQRT_D\n");
5263 UNIMPLEMENTED();
5264 case FCLASS_S:
5265 printf("Sim UNIMPLEMENTED: FCLASS_S\n");
5266 UNIMPLEMENTED();
5267 case FCLASS_D:
5268 printf("Sim UNIMPLEMENTED: FCLASS_D\n");
5269 UNIMPLEMENTED();
5270 case FLOGB_S:
5271 printf("Sim UNIMPLEMENTED: FLOGB_S\n");
5272 UNIMPLEMENTED();
5273 case FLOGB_D:
5274 printf("Sim UNIMPLEMENTED: FLOGB_D\n");
5275 UNIMPLEMENTED();
5276 case CLO_W:
5277 printf("Sim UNIMPLEMENTED: CLO_W\n");
5278 UNIMPLEMENTED();
5279 case CTO_W:
5280 printf("Sim UNIMPLEMENTED: CTO_W\n");
5281 UNIMPLEMENTED();
5282 case CLO_D:
5283 printf("Sim UNIMPLEMENTED: CLO_D\n");
5284 UNIMPLEMENTED();
5285 case CTO_D:
5286 printf("Sim UNIMPLEMENTED: CTO_D\n");
5287 UNIMPLEMENTED();
5288 // Unimplemented opcodes raised an error in the configuration step before,
5289 // so we can use the default here to set the destination register in common
5290 // cases.
5291 default:
5292 UNREACHABLE();
5293 }
5294}
5295
5296// Executes the current instruction.
5297void Simulator::InstructionDecode(Instruction* instr) {
5298 if (v8_flags.check_icache) {
5299 CheckICache(i_cache(), instr);
5300 }
5301 pc_modified_ = false;
5302
5304
5305 if (v8_flags.trace_sim) {
5306 base::SNPrintF(trace_buf_, " ");
5307 disasm::NameConverter converter;
5308 disasm::Disassembler dasm(converter);
5309 // Use a reasonably large buffer.
5310 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr));
5311 }
5312
5313 static int instr_count = 0;
5314 USE(instr_count);
5315 instr_ = instr;
5316 printf_instr("\nInstr%3d: %08x, PC: %016lx\t", instr_count++,
5317 instr_.Bits(31, 0), get_pc());
5318 switch (instr_.InstructionType()) {
5319 case Instruction::kOp6Type:
5320 DecodeTypeOp6();
5321 break;
5322 case Instruction::kOp7Type:
5323 DecodeTypeOp7();
5324 break;
5325 case Instruction::kOp8Type:
5326 DecodeTypeOp8();
5327 break;
5328 case Instruction::kOp10Type:
5329 DecodeTypeOp10();
5330 break;
5331 case Instruction::kOp12Type:
5332 DecodeTypeOp12();
5333 break;
5334 case Instruction::kOp14Type:
5335 DecodeTypeOp14();
5336 break;
5337 case Instruction::kOp17Type:
5338 DecodeTypeOp17();
5339 break;
5340 case Instruction::kOp22Type:
5341 DecodeTypeOp22();
5342 break;
5343 default: {
5344 printf("instr_: %x\n", instr_.Bits(31, 0));
5345 UNREACHABLE();
5346 }
5347 }
5348
5349 if (v8_flags.trace_sim) {
5350 PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
5351 reinterpret_cast<intptr_t>(instr), buffer.begin(),
5352 trace_buf_.begin());
5353 }
5354
5355 if (!pc_modified_) {
5356 set_register(pc, reinterpret_cast<int64_t>(instr) + kInstrSize);
5357 }
5358}
5359
5360void Simulator::Execute() {
5361 // Get the PC to simulate. Cannot use the accessor here as we need the
5362 // raw PC value and not the one used as input to arithmetic instructions.
5363 int64_t program_counter = get_pc();
5364 if (v8_flags.stop_sim_at == 0) {
5365 // Fast version of the dispatch loop without checking whether the simulator
5366 // should be stopping at a particular executed instruction.
5367 while (program_counter != end_sim_pc) {
5368 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5369 icount_++;
5370 InstructionDecode(instr);
5371 program_counter = get_pc();
5372 }
5373 } else {
5374 // v8_flags.stop_sim_at is at the non-default value. Stop in the debugger
5375 // when we reach the particular instruction count.
5376 while (program_counter != end_sim_pc) {
5377 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5378 icount_++;
5379 if (icount_ == static_cast<int64_t>(v8_flags.stop_sim_at)) {
5380 Loong64Debugger dbg(this);
5381 dbg.Debug();
5382 } else {
5383 InstructionDecode(instr);
5384 }
5385 program_counter = get_pc();
5386 }
5387 }
5388}
5389
5390void Simulator::CallInternal(Address entry) {
5391 // Adjust JS-based stack limit to C-based stack limit.
5392 isolate_->stack_guard()->AdjustStackLimitForSimulator();
5393
5394 // Prepare to execute the code at entry.
5395 set_register(pc, static_cast<int64_t>(entry));
5396 // Put down marker for end of simulation. The simulator will stop simulation
5397 // when the PC reaches this value. By saving the "end simulation" value into
5398 // the LR the simulation stops when returning to this call point.
5399 set_register(ra, end_sim_pc);
5400
5401 // Remember the values of callee-saved registers.
5402 int64_t s0_val = get_register(s0);
5403 int64_t s1_val = get_register(s1);
5404 int64_t s2_val = get_register(s2);
5405 int64_t s3_val = get_register(s3);
5406 int64_t s4_val = get_register(s4);
5407 int64_t s5_val = get_register(s5);
5408 int64_t s6_val = get_register(s6);
5409 int64_t s7_val = get_register(s7);
5410 int64_t s8_val = get_register(s8);
5411 int64_t gp_val = get_register(gp);
5412 int64_t sp_val = get_register(sp);
5413 int64_t tp_val = get_register(tp);
5414 int64_t fp_val = get_register(fp);
5415
5416 // Set up the callee-saved registers with a known value. To be able to check
5417 // that they are preserved properly across JS execution.
5418 int64_t callee_saved_value = icount_;
5419 set_register(s0, callee_saved_value);
5420 set_register(s1, callee_saved_value);
5421 set_register(s2, callee_saved_value);
5422 set_register(s3, callee_saved_value);
5423 set_register(s4, callee_saved_value);
5424 set_register(s5, callee_saved_value);
5425 set_register(s6, callee_saved_value);
5426 set_register(s7, callee_saved_value);
5427 set_register(s8, callee_saved_value);
5428 set_register(gp, callee_saved_value);
5429 set_register(tp, callee_saved_value);
5430 set_register(fp, callee_saved_value);
5431
5432 // Start the simulation.
5433 Execute();
5434
5435 // Check that the callee-saved registers have been preserved.
5436 CHECK_EQ(callee_saved_value, get_register(s0));
5437 CHECK_EQ(callee_saved_value, get_register(s1));
5438 CHECK_EQ(callee_saved_value, get_register(s2));
5439 CHECK_EQ(callee_saved_value, get_register(s3));
5440 CHECK_EQ(callee_saved_value, get_register(s4));
5441 CHECK_EQ(callee_saved_value, get_register(s5));
5442 CHECK_EQ(callee_saved_value, get_register(s6));
5443 CHECK_EQ(callee_saved_value, get_register(s7));
5444 CHECK_EQ(callee_saved_value, get_register(s8));
5445 CHECK_EQ(callee_saved_value, get_register(gp));
5446 CHECK_EQ(callee_saved_value, get_register(tp));
5447 CHECK_EQ(callee_saved_value, get_register(fp));
5448
5449 // Restore callee-saved registers with the original value.
5450 set_register(s0, s0_val);
5451 set_register(s1, s1_val);
5452 set_register(s2, s2_val);
5453 set_register(s3, s3_val);
5454 set_register(s4, s4_val);
5455 set_register(s5, s5_val);
5456 set_register(s6, s6_val);
5457 set_register(s7, s7_val);
5458 set_register(s8, s8_val);
5459 set_register(gp, gp_val);
5460 set_register(sp, sp_val);
5461 set_register(tp, tp_val);
5462 set_register(fp, fp_val);
5463}
5464
5465void Simulator::CallImpl(Address entry, CallArgument* args) {
5466 int index_gp = 0;
5467 int index_fp = 0;
5468
5469 std::vector<int64_t> stack_args(0);
5470 for (int i = 0; !args[i].IsEnd(); i++) {
5471 CallArgument arg = args[i];
5472 if (arg.IsGP() && (index_gp < 8)) {
5473 set_register(index_gp + 4, arg.bits());
5474 index_gp++;
5475 } else if (arg.IsFP() && (index_fp < 8)) {
5476 set_fpu_register(index_fp++, arg.bits());
5477 } else if (arg.IsFP() && (index_gp < 8)) {
5478 set_register(index_gp + 4, arg.bits());
5479 index_gp++;
5480 } else {
5481 DCHECK(arg.IsFP() || arg.IsGP());
5482 stack_args.push_back(arg.bits());
5483 }
5484 }
5485
5486 // Remaining arguments passed on stack.
5487 int64_t original_stack = get_register(sp);
5488 // Compute position of stack on entry to generated code.
5489 int64_t stack_args_size = stack_args.size() * sizeof(stack_args[0]);
5490 int64_t entry_stack = original_stack - stack_args_size;
5491
5492 if (base::OS::ActivationFrameAlignment() != 0) {
5493 entry_stack &= -base::OS::ActivationFrameAlignment();
5494 }
5495 // Store remaining arguments on stack, from low to high memory.
5496 char* stack_argument = reinterpret_cast<char*>(entry_stack);
5497 memcpy(stack_argument, stack_args.data(),
5498 stack_args.size() * sizeof(int64_t));
5499 set_register(sp, entry_stack);
5500
5501 CallInternal(entry);
5502
5503 // Pop stack passed arguments.
5504 CHECK_EQ(entry_stack, get_register(sp));
5505 set_register(sp, original_stack);
5506}
5507
5508double Simulator::CallFP(Address entry, double d0, double d1) {
5509 const FPURegister fparg2 = f1;
5510 set_fpu_register_double(f0, d0);
5511 set_fpu_register_double(fparg2, d1);
5512 CallInternal(entry);
5513 return get_fpu_register_double(f0);
5514}
5515
5516uintptr_t Simulator::PushAddress(uintptr_t address) {
5517 int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
5518 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
5519 *stack_slot = address;
5520 set_register(sp, new_sp);
5521 return new_sp;
5522}
5523
5524uintptr_t Simulator::PopAddress() {
5525 int64_t current_sp = get_register(sp);
5526 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
5527 uintptr_t address = *stack_slot;
5528 set_register(sp, current_sp + sizeof(uintptr_t));
5529 return address;
5530}
5531
5532Simulator::LocalMonitor::LocalMonitor()
5533 : access_state_(MonitorAccess::Open),
5534 tagged_addr_(0),
5535 size_(TransactionSize::None) {}
5536
5537void Simulator::LocalMonitor::Clear() {
5538 access_state_ = MonitorAccess::Open;
5539 tagged_addr_ = 0;
5540 size_ = TransactionSize::None;
5541}
5542
5543void Simulator::LocalMonitor::NotifyLoad() {
5544 if (access_state_ == MonitorAccess::RMW) {
5545 // A non linked load could clear the local monitor. As a result, it's
5546 // most strict to unconditionally clear the local monitor on load.
5547 Clear();
5548 }
5549}
5550
5551void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
5552 TransactionSize size) {
5553 access_state_ = MonitorAccess::RMW;
5554 tagged_addr_ = addr;
5555 size_ = size;
5556}
5557
5558void Simulator::LocalMonitor::NotifyStore() {
5559 if (access_state_ == MonitorAccess::RMW) {
5560 // A non exclusive store could clear the local monitor. As a result, it's
5561 // most strict to unconditionally clear the local monitor on store.
5562 Clear();
5563 }
5564}
5565
5566bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
5567 TransactionSize size) {
5568 if (access_state_ == MonitorAccess::RMW) {
5569 if (addr == tagged_addr_ && size_ == size) {
5570 Clear();
5571 return true;
5572 } else {
5573 return false;
5574 }
5575 } else {
5576 DCHECK(access_state_ == MonitorAccess::Open);
5577 return false;
5578 }
5579}
5580
5581Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
5582 : access_state_(MonitorAccess::Open),
5583 tagged_addr_(0),
5584 next_(nullptr),
5585 prev_(nullptr),
5586 failure_counter_(0) {}
5587
5588void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
5589 access_state_ = MonitorAccess::Open;
5590 tagged_addr_ = 0;
5591}
5592
5593void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
5594 uintptr_t addr) {
5595 access_state_ = MonitorAccess::RMW;
5596 tagged_addr_ = addr;
5597}
5598
5599void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
5600 if (access_state_ == MonitorAccess::RMW) {
5601 // A non exclusive store could clear the global monitor. As a result, it's
5602 // most strict to unconditionally clear global monitors on store.
5603 Clear_Locked();
5604 }
5605}
5606
5607bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
5608 uintptr_t addr, bool is_requesting_thread) {
5609 if (access_state_ == MonitorAccess::RMW) {
5610 if (is_requesting_thread) {
5611 if (addr == tagged_addr_) {
5612 Clear_Locked();
5613 // Introduce occasional sc/scd failures. This is to simulate the
5614 // behavior of hardware, which can randomly fail due to background
5615 // cache evictions.
5616 if (failure_counter_++ >= kMaxFailureCounter) {
5617 failure_counter_ = 0;
5618 return false;
5619 } else {
5620 return true;
5621 }
5622 }
5623 } else if ((addr & kExclusiveTaggedAddrMask) ==
5624 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
5625 // Check the masked addresses when responding to a successful lock by
5626 // another thread so the implementation is more conservative (i.e. the
5627 // granularity of locking is as large as possible.)
5628 Clear_Locked();
5629 return false;
5630 }
5631 }
5632 return false;
5633}
5634
5635void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
5636 uintptr_t addr, LinkedAddress* linked_address) {
5637 linked_address->NotifyLoadLinked_Locked(addr);
5638 PrependProcessor_Locked(linked_address);
5639}
5640
5641void Simulator::GlobalMonitor::NotifyStore_Locked(
5642 LinkedAddress* linked_address) {
5643 // Notify each thread of the store operation.
5644 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
5645 iter->NotifyStore_Locked();
5646 }
5647}
5648
5649bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
5650 uintptr_t addr, LinkedAddress* linked_address) {
5651 DCHECK(IsProcessorInLinkedList_Locked(linked_address));
5652 if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
5653 // Notify the other processors that this StoreConditional succeeded.
5654 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
5655 if (iter != linked_address) {
5656 iter->NotifyStoreConditional_Locked(addr, false);
5657 }
5658 }
5659 return true;
5660 } else {
5661 return false;
5662 }
5663}
5664
5665bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
5666 LinkedAddress* linked_address) const {
5667 return head_ == linked_address || linked_address->next_ ||
5668 linked_address->prev_;
5669}
5670
5671void Simulator::GlobalMonitor::PrependProcessor_Locked(
5672 LinkedAddress* linked_address) {
5673 if (IsProcessorInLinkedList_Locked(linked_address)) {
5674 return;
5675 }
5676
5677 if (head_) {
5678 head_->prev_ = linked_address;
5679 }
5680 linked_address->prev_ = nullptr;
5681 linked_address->next_ = head_;
5682 head_ = linked_address;
5683}
5684
5685void Simulator::GlobalMonitor::RemoveLinkedAddress(
5686 LinkedAddress* linked_address) {
5687 base::MutexGuard lock_guard(&mutex);
5688 if (!IsProcessorInLinkedList_Locked(linked_address)) {
5689 return;
5690 }
5691
5692 if (linked_address->prev_) {
5693 linked_address->prev_->next_ = linked_address->next_;
5694 } else {
5695 head_ = linked_address->next_;
5696 }
5697 if (linked_address->next_) {
5698 linked_address->next_->prev_ = linked_address->prev_;
5699 }
5700 linked_address->prev_ = nullptr;
5701 linked_address->next_ = nullptr;
5702}
5703
5704#undef SScanF
5705#undef BRACKETS
5706
5707} // namespace internal
5708} // namespace v8
5709
5710#endif // USE_SIMULATOR
Isolate * isolate_
#define T
#define one
#define BREAK
Builtins::Kind kind
Definition builtins.cc:40
virtual void VisitPointer(const void *address)=0
static void DebugBreak()
constexpr T * begin() const
Definition vector.h:96
static const char * Name(int reg)
static int Number(const char *name)
int Bits(int hi, int lo) const
constexpr int8_t code() const
static int Number(const char *name)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
Handle< Code > code
const int size_
Definition assembler.cc:132
#define FUNCTION_ADDR(f)
Definition globals.h:712
int start
int end
LineAndColumn current
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int32_t offset
#define XSTR(s)
TNode< Object > target
std::optional< TNode< JSArray > > a
Instruction * instr
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
LiftoffRegister reg
Register tmp
int y
int x
uint32_t const mask
base::Mutex mutex
#define DISABLE_MSAN
Definition msan.h:40
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
signed short int16_t
Definition unicode.cc:38
uintptr_t Address
Definition memory.h:13
CustomMatcherTemplateHashMapImpl< DefaultAllocationPolicy > CustomMatcherHashMap
Definition hashmap.h:480
void DeleteArray(T *array)
Definition allocation.h:63
constexpr VFPRoundingMode kRoundToNearest
constexpr UnconditionalBranchOp BL
constexpr VFPRoundingMode kRoundToMinusInf
constexpr Opcode AND
void PrintF(const char *format,...)
Definition utils.cc:39
char * ReadLine(const char *prompt)
Definition utils.cc:69
const Instr rtCallRedirInstr
constexpr uint32_t kMaxStopCode
const uint32_t kMaxWatchpointCode
constexpr int B
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
const int kNumFPURegisters
const int kInvalidFPURegister
void Print(Tagged< Object > obj)
Definition objects.h:774
const int kNumSimuRegisters
constexpr VFPRoundingMode kRoundToPlusInf
const int kInvalidRegister
constexpr LogicalOp ORN
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
constexpr Register kWasmTrapHandlerFaultAddressRegister
V8_EXPORT_PRIVATE FlagValues v8_flags
const uint32_t kFPURoundingModeMask
constexpr VFPRoundingMode kRoundToZero
uint64_t ObjectPair
return value
Definition map-inl.h:893
constexpr uint8_t kInstrSize
V8_WARN_UNUSED_RESULT bool IsValidHeapObject(Heap *heap, Tagged< HeapObject > object)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
@ None
Definition v8-object.h:141
base::SmallVector< RegisterT, kStaticCapacity > registers_
const uintptr_t stack_limit_
Node * prev_
#define UNREACHABLE()
Definition logging.h:67
#define FATAL(...)
Definition logging.h:47
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_LT(lhs, rhs)
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_EQ(lhs, rhs)
#define UNIMPLEMENTED()
Definition logging.h:66
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8PRIxPTR
Definition macros.h:331
std::unique_ptr< ValueMirror > value
unsigned long DWORD