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