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