Simulator-riscv64.cpp (138695B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright 2021 the V8 project authors. All rights reserved. 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following 12 // disclaimer in the documentation and/or other materials provided 13 // with the distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived 16 // from this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 #ifdef JS_SIMULATOR_RISCV64 30 # include "jit/riscv64/Simulator-riscv64.h" 31 32 # include "mozilla/Casting.h" 33 # include "mozilla/IntegerPrintfMacros.h" 34 35 # include <cinttypes> 36 # include <float.h> 37 # include <iostream> 38 # include <limits> 39 40 # include "jit/AtomicOperations.h" 41 # include "jit/riscv64/Assembler-riscv64.h" 42 # include "js/Conversions.h" 43 # include "js/UniquePtr.h" 44 # include "js/Utility.h" 45 # include "threading/LockGuard.h" 46 # include "vm/JSContext.h" 47 # include "vm/Runtime.h" 48 # include "wasm/WasmInstance.h" 49 # include "wasm/WasmSignalHandlers.h" 50 51 # define I8(v) static_cast<int8_t>(v) 52 # define I16(v) static_cast<int16_t>(v) 53 # define U16(v) static_cast<uint16_t>(v) 54 # define I32(v) static_cast<int32_t>(v) 55 # define U32(v) static_cast<uint32_t>(v) 56 # define I64(v) static_cast<int64_t>(v) 57 # define U64(v) static_cast<uint64_t>(v) 58 # define I128(v) static_cast<__int128_t>(v) 59 # define U128(v) static_cast<__uint128_t>(v) 60 61 # define REGIx_FORMAT PRIx64 62 # define REGId_FORMAT PRId64 63 64 # define I32_CHECK(v) \ 65 ({ \ 66 MOZ_ASSERT(I64(I32(v)) == I64(v)); \ 67 I32((v)); \ 68 }) 69 70 namespace js { 71 namespace jit { 72 73 bool Simulator::FLAG_trace_sim = false; 74 bool Simulator::FLAG_debug_sim = false; 75 bool Simulator::FLAG_riscv_trap_to_simulator_debugger = false; 76 bool Simulator::FLAG_riscv_print_watchpoint = false; 77 78 static void UNIMPLEMENTED() { 79 printf("UNIMPLEMENTED instruction.\n"); 80 MOZ_CRASH(); 81 } 82 static void UNREACHABLE() { 83 printf("UNREACHABLE instruction.\n"); 84 MOZ_CRASH(); 85 } 86 # define UNSUPPORTED() \ 87 std::cout << "Unrecognized instruction [@pc=0x" << std::hex \ 88 << registers_[pc] << "]: 0x" << instr_.InstructionBits() \ 89 << std::endl; \ 90 printf("Unsupported instruction.\n"); \ 91 MOZ_CRASH(); 92 93 static char* ReadLine(const char* prompt) { 94 UniqueChars result; 95 char lineBuf[256]; 96 int offset = 0; 97 bool keepGoing = true; 98 fprintf(stdout, "%s", prompt); 99 fflush(stdout); 100 while (keepGoing) { 101 if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) { 102 // fgets got an error. Just give up. 103 return nullptr; 104 } 105 int len = strlen(lineBuf); 106 if (len > 0 && lineBuf[len - 1] == '\n') { 107 // Since we read a new line we are done reading the line. This 108 // will exit the loop after copying this buffer into the result. 109 keepGoing = false; 110 } 111 if (!result) { 112 // Allocate the initial result and make room for the terminating '\0' 113 result.reset(js_pod_malloc<char>(len + 1)); 114 if (!result) { 115 return nullptr; 116 } 117 } else { 118 // Allocate a new result with enough room for the new addition. 119 int new_len = offset + len + 1; 120 char* new_result = js_pod_malloc<char>(new_len); 121 if (!new_result) { 122 return nullptr; 123 } 124 // Copy the existing input into the new array and set the new 125 // array as the result. 126 memcpy(new_result, result.get(), offset * sizeof(char)); 127 result.reset(new_result); 128 } 129 // Copy the newly read line into the result. 130 memcpy(result.get() + offset, lineBuf, len * sizeof(char)); 131 offset += len; 132 } 133 134 MOZ_ASSERT(result); 135 result[offset] = '\0'; 136 return result.release(); 137 } 138 139 // ----------------------------------------------------------------------------- 140 // Riscv assembly various constants. 141 142 // C/C++ argument slots size. 143 const int kCArgSlotCount = 0; 144 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t); 145 const int kBranchReturnOffset = 2 * kInstrSize; 146 147 class CachePage { 148 public: 149 static const int LINE_VALID = 0; 150 static const int LINE_INVALID = 1; 151 152 static const int kPageShift = 12; 153 static const int kPageSize = 1 << kPageShift; 154 static const int kPageMask = kPageSize - 1; 155 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 156 static const int kLineLength = 1 << kLineShift; 157 static const int kLineMask = kLineLength - 1; 158 159 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); } 160 161 char* validityByte(int offset) { 162 return &validity_map_[offset >> kLineShift]; 163 } 164 165 char* cachedData(int offset) { return &data_[offset]; } 166 167 private: 168 char data_[kPageSize]; // The cached data. 169 static const int kValidityMapSize = kPageSize >> kLineShift; 170 char validity_map_[kValidityMapSize]; // One byte per line. 171 }; 172 173 // Protects the icache() and redirection() properties of the 174 // Simulator. 175 class AutoLockSimulatorCache : public LockGuard<Mutex> { 176 using Base = LockGuard<Mutex>; 177 178 public: 179 explicit AutoLockSimulatorCache() 180 : Base(SimulatorProcess::singleton_->cacheLock_) {} 181 }; 182 183 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 184 SimulatorProcess::ICacheCheckingDisableCount( 185 1); // Checking is disabled by default. 186 SimulatorProcess* SimulatorProcess::singleton_ = nullptr; 187 188 int64_t Simulator::StopSimAt = -1; 189 190 static bool IsFlag(const char* found, const char* flag) { 191 return strlen(found) == strlen(flag) && strcmp(found, flag) == 0; 192 } 193 194 Simulator* Simulator::Create() { 195 auto sim = MakeUnique<Simulator>(); 196 if (!sim) { 197 return nullptr; 198 } 199 200 if (!sim->init()) { 201 return nullptr; 202 } 203 204 int64_t stopAt; 205 char* stopAtStr = getenv("RISCV_SIM_STOP_AT"); 206 if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) { 207 fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt); 208 Simulator::StopSimAt = stopAt; 209 } 210 char* str = getenv("RISCV_TRACE_SIM"); 211 if (str != nullptr && IsFlag(str, "true")) { 212 FLAG_trace_sim = true; 213 } 214 215 return sim.release(); 216 } 217 218 void Simulator::Destroy(Simulator* sim) { js_delete(sim); } 219 220 # if JS_CODEGEN_RISCV64 221 void Simulator::TraceRegWr(int64_t value, TraceType t) { 222 if (FLAG_trace_sim) { 223 union { 224 int64_t fmt_int64; 225 int32_t fmt_int32[2]; 226 float fmt_float[2]; 227 double fmt_double; 228 } v; 229 v.fmt_int64 = value; 230 231 switch (t) { 232 case WORD: 233 SNPrintF(trace_buf_, 234 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 235 " uint32:%" PRIu32, 236 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]); 237 break; 238 case DWORD: 239 SNPrintF(trace_buf_, 240 "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" REGId_FORMAT 241 " uint64:%" PRIu64, 242 value, icount_, value, value); 243 break; 244 case FLOAT: 245 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", 246 v.fmt_int64, icount_, v.fmt_float[0]); 247 break; 248 case DOUBLE: 249 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") dbl:%e", 250 v.fmt_int64, icount_, v.fmt_double); 251 break; 252 default: 253 UNREACHABLE(); 254 } 255 } 256 } 257 258 # elif JS_CODEGEN_RISCV32 259 template <typename T> 260 void Simulator::TraceRegWr(T value, TraceType t) { 261 if (::v8::internal::FLAG_trace_sim) { 262 union { 263 int32_t fmt_int32; 264 float fmt_float; 265 double fmt_double; 266 } v; 267 if (t != DOUBLE) { 268 v.fmt_int32 = value; 269 } else { 270 DCHECK_EQ(sizeof(T), 8); 271 v.fmt_double = value; 272 } 273 switch (t) { 274 case WORD: 275 SNPrintF(trace_buf_, 276 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" REGId_FORMAT 277 " uint32:%" PRIu32, 278 v.fmt_int32, icount_, v.fmt_int32, v.fmt_int32); 279 break; 280 case FLOAT: 281 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", 282 v.fmt_int32, icount_, v.fmt_float); 283 break; 284 case DOUBLE: 285 SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e", 286 static_cast<int64_t>(v.fmt_double), icount_, v.fmt_double); 287 break; 288 default: 289 UNREACHABLE(); 290 } 291 } 292 } 293 # endif 294 // The RiscvDebugger class is used by the simulator while debugging simulated 295 // code. 296 class RiscvDebugger { 297 public: 298 explicit RiscvDebugger(Simulator* sim) : sim_(sim) {} 299 300 void Debug(); 301 // Print all registers with a nice formatting. 302 void PrintRegs(char name_prefix, int start_index, int end_index); 303 void printAllRegs(); 304 void printAllRegsIncludingFPU(); 305 306 static const Instr kNopInstr = 0x0; 307 308 private: 309 Simulator* sim_; 310 311 int64_t GetRegisterValue(int regnum); 312 int64_t GetFPURegisterValue(int regnum); 313 float GetFPURegisterValueFloat(int regnum); 314 double GetFPURegisterValueDouble(int regnum); 315 # ifdef CAN_USE_RVV_INSTRUCTIONS 316 __int128_t GetVRegisterValue(int regnum); 317 # endif 318 bool GetValue(const char* desc, int64_t* value); 319 }; 320 321 int64_t RiscvDebugger::GetRegisterValue(int regnum) { 322 if (regnum == Simulator::Register::kNumSimuRegisters) { 323 return sim_->get_pc(); 324 } else { 325 return sim_->getRegister(regnum); 326 } 327 } 328 329 int64_t RiscvDebugger::GetFPURegisterValue(int regnum) { 330 if (regnum == Simulator::FPURegister::kNumFPURegisters) { 331 return sim_->get_pc(); 332 } else { 333 return sim_->getFpuRegister(regnum); 334 } 335 } 336 337 float RiscvDebugger::GetFPURegisterValueFloat(int regnum) { 338 if (regnum == Simulator::FPURegister::kNumFPURegisters) { 339 return sim_->get_pc(); 340 } else { 341 return sim_->getFpuRegisterFloat(regnum); 342 } 343 } 344 345 double RiscvDebugger::GetFPURegisterValueDouble(int regnum) { 346 if (regnum == Simulator::FPURegister::kNumFPURegisters) { 347 return sim_->get_pc(); 348 } else { 349 return sim_->getFpuRegisterDouble(regnum); 350 } 351 } 352 353 # ifdef CAN_USE_RVV_INSTRUCTIONS 354 __int128_t RiscvDebugger::GetVRegisterValue(int regnum) { 355 if (regnum == kNumVRegisters) { 356 return sim_->get_pc(); 357 } else { 358 return sim_->get_vregister(regnum); 359 } 360 } 361 # endif 362 363 bool RiscvDebugger::GetValue(const char* desc, int64_t* value) { 364 int regnum = Registers::FromName(desc); 365 int fpuregnum = FloatRegisters::FromName(desc); 366 367 if (regnum != Registers::invalid_reg) { 368 *value = GetRegisterValue(regnum); 369 return true; 370 } else if (fpuregnum != FloatRegisters::invalid_reg) { 371 *value = GetFPURegisterValue(fpuregnum); 372 return true; 373 } else if (strncmp(desc, "0x", 2) == 0) { 374 return sscanf(desc + 2, "%" SCNx64, reinterpret_cast<int64_t*>(value)) == 1; 375 } else { 376 return sscanf(desc, "%" SCNu64, reinterpret_cast<int64_t*>(value)) == 1; 377 } 378 } 379 380 # define REG_INFO(name) \ 381 name, GetRegisterValue(Registers::FromName(name)), \ 382 GetRegisterValue(Registers::FromName(name)) 383 384 void RiscvDebugger::PrintRegs(char name_prefix, int start_index, 385 int end_index) { 386 EmbeddedVector<char, 10> name1, name2; 387 MOZ_ASSERT(name_prefix == 'a' || name_prefix == 't' || name_prefix == 's'); 388 MOZ_ASSERT(start_index >= 0 && end_index <= 99); 389 int num_registers = (end_index - start_index) + 1; 390 for (int i = 0; i < num_registers / 2; i++) { 391 SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i); 392 SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1); 393 printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 394 " \t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n", 395 REG_INFO(name1.start()), REG_INFO(name2.start())); 396 } 397 if (num_registers % 2 == 1) { 398 SNPrintF(name1, "%c%d", name_prefix, end_index); 399 printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n", 400 REG_INFO(name1.start())); 401 } 402 } 403 404 void RiscvDebugger::printAllRegs() { 405 printf("\n"); 406 // ra, sp, gp 407 printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 408 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 409 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n", 410 REG_INFO("ra"), REG_INFO("sp"), REG_INFO("gp")); 411 412 // tp, fp, pc 413 printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 414 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 415 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n", 416 REG_INFO("tp"), REG_INFO("fp"), REG_INFO("pc")); 417 418 // print register a0, .., a7 419 PrintRegs('a', 0, 7); 420 // print registers s1, ..., s11 421 PrintRegs('s', 1, 11); 422 // print registers t0, ..., t6 423 PrintRegs('t', 0, 6); 424 } 425 426 # undef REG_INFO 427 428 void RiscvDebugger::printAllRegsIncludingFPU() { 429 # define FPU_REG_INFO(n) \ 430 FloatRegisters::GetName(n), GetFPURegisterValue(n), \ 431 GetFPURegisterValueDouble(n) 432 433 printAllRegs(); 434 435 printf("\n\n"); 436 // f0, f1, f2, ... f31. 437 MOZ_ASSERT(kNumFPURegisters % 2 == 0); 438 for (int i = 0; i < kNumFPURegisters; i += 2) 439 printf("%3s: 0x%016" PRIx64 " %16.4e \t%3s: 0x%016" PRIx64 " %16.4e\n", 440 FPU_REG_INFO(i), FPU_REG_INFO(i + 1)); 441 # undef FPU_REG_INFO 442 } 443 444 void RiscvDebugger::Debug() { 445 intptr_t last_pc = -1; 446 bool done = false; 447 448 # define COMMAND_SIZE 63 449 # define ARG_SIZE 255 450 451 # define STR(a) #a 452 # define XSTR(a) STR(a) 453 454 char cmd[COMMAND_SIZE + 1]; 455 char arg1[ARG_SIZE + 1]; 456 char arg2[ARG_SIZE + 1]; 457 char* argv[3] = {cmd, arg1, arg2}; 458 459 // Make sure to have a proper terminating character if reaching the limit. 460 cmd[COMMAND_SIZE] = 0; 461 arg1[ARG_SIZE] = 0; 462 arg2[ARG_SIZE] = 0; 463 464 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) { 465 if (last_pc != sim_->get_pc()) { 466 disasm::NameConverter converter; 467 disasm::Disassembler dasm(converter); 468 // Use a reasonably large buffer. 469 EmbeddedVector<char, 256> buffer; 470 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc())); 471 printf(" 0x%016" REGIx_FORMAT " %s\n", sim_->get_pc(), buffer.start()); 472 last_pc = sim_->get_pc(); 473 } 474 char* line = ReadLine("sim> "); 475 if (line == nullptr) { 476 break; 477 } else { 478 char* last_input = sim_->lastDebuggerInput(); 479 if (strcmp(line, "\n") == 0 && last_input != nullptr) { 480 line = last_input; 481 } else { 482 // Ownership is transferred to sim_; 483 sim_->setLastDebuggerInput(line); 484 } 485 // Use sscanf to parse the individual parts of the command line. At the 486 // moment no command expects more than two parameters. 487 int argc = sscanf( 488 line, 489 "%" XSTR(COMMAND_SIZE) "s " 490 "%" XSTR(ARG_SIZE) "s " 491 "%" XSTR(ARG_SIZE) "s", 492 cmd, arg1, arg2); 493 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { 494 SimInstruction* instr = 495 reinterpret_cast<SimInstruction*>(sim_->get_pc()); 496 if (!(instr->IsTrap()) || 497 instr->InstructionBits() == rtCallRedirInstr) { 498 sim_->icount_++; 499 sim_->InstructionDecode( 500 reinterpret_cast<Instruction*>(sim_->get_pc())); 501 } else { 502 // Allow si to jump over generated breakpoints. 503 printf("/!\\ Jumping over generated breakpoint.\n"); 504 sim_->set_pc(sim_->get_pc() + kInstrSize); 505 } 506 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { 507 // Leave the debugger shell. 508 done = true; 509 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { 510 if (argc == 2) { 511 int64_t value; 512 int64_t fvalue; 513 double dvalue; 514 if (strcmp(arg1, "all") == 0) { 515 printAllRegs(); 516 } else if (strcmp(arg1, "allf") == 0) { 517 printAllRegsIncludingFPU(); 518 } else { 519 int regnum = Registers::FromName(arg1); 520 int fpuregnum = FloatRegisters::FromName(arg1); 521 # ifdef CAN_USE_RVV_INSTRUCTIONS 522 int vregnum = VRegisters::FromName(arg1); 523 # endif 524 if (regnum != Registers::invalid_reg) { 525 value = GetRegisterValue(regnum); 526 printf("%s: 0x%08" REGIx_FORMAT " %" REGId_FORMAT " \n", arg1, 527 value, value); 528 } else if (fpuregnum != FloatRegisters::invalid_reg) { 529 fvalue = GetFPURegisterValue(fpuregnum); 530 dvalue = GetFPURegisterValueDouble(fpuregnum); 531 printf("%3s: 0x%016" PRIx64 " %16.4e\n", 532 FloatRegisters::GetName(fpuregnum), fvalue, dvalue); 533 # ifdef CAN_USE_RVV_INSTRUCTIONS 534 } else if (vregnum != kInvalidVRegister) { 535 __int128_t v = GetVRegisterValue(vregnum); 536 printf("\t%s:0x%016" REGIx_FORMAT "%016" REGIx_FORMAT "\n", 537 VRegisters::GetName(vregnum), (uint64_t)(v >> 64), 538 (uint64_t)v); 539 # endif 540 } else { 541 printf("%s unrecognized\n", arg1); 542 } 543 } 544 } else { 545 if (argc == 3) { 546 if (strcmp(arg2, "single") == 0) { 547 int64_t value; 548 float fvalue; 549 int fpuregnum = FloatRegisters::FromName(arg1); 550 551 if (fpuregnum != FloatRegisters::invalid_reg) { 552 value = GetFPURegisterValue(fpuregnum); 553 value &= 0xFFFFFFFFUL; 554 fvalue = GetFPURegisterValueFloat(fpuregnum); 555 printf("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue); 556 } else { 557 printf("%s unrecognized\n", arg1); 558 } 559 } else { 560 printf("print <fpu register> single\n"); 561 } 562 } else { 563 printf("print <register> or print <fpu register> single\n"); 564 } 565 } 566 } else if ((strcmp(cmd, "po") == 0) || 567 (strcmp(cmd, "printobject") == 0)) { 568 UNIMPLEMENTED(); 569 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { 570 int64_t* cur = nullptr; 571 int64_t* end = nullptr; 572 int next_arg = 1; 573 if (argc < 2) { 574 printf("Need to specify <address> to memhex command\n"); 575 continue; 576 } 577 int64_t value; 578 if (!GetValue(arg1, &value)) { 579 printf("%s unrecognized\n", arg1); 580 continue; 581 } 582 cur = reinterpret_cast<int64_t*>(value); 583 next_arg++; 584 585 int64_t words; 586 if (argc == next_arg) { 587 words = 10; 588 } else { 589 if (!GetValue(argv[next_arg], &words)) { 590 words = 10; 591 } 592 } 593 end = cur + words; 594 595 while (cur < end) { 596 printf(" 0x%012" PRIxPTR " : 0x%016" REGIx_FORMAT 597 " %14" REGId_FORMAT " ", 598 reinterpret_cast<intptr_t>(cur), *cur, *cur); 599 printf("\n"); 600 cur++; 601 } 602 } else if ((strcmp(cmd, "watch") == 0)) { 603 if (argc < 2) { 604 printf("Need to specify <address> to mem command\n"); 605 continue; 606 } 607 int64_t value; 608 if (!GetValue(arg1, &value)) { 609 printf("%s unrecognized\n", arg1); 610 continue; 611 } 612 sim_->watch_address_ = reinterpret_cast<intptr_t*>(value); 613 sim_->watch_value_ = *(sim_->watch_address_); 614 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) || 615 (strcmp(cmd, "di") == 0)) { 616 disasm::NameConverter converter; 617 disasm::Disassembler dasm(converter); 618 // Use a reasonably large buffer. 619 EmbeddedVector<char, 256> buffer; 620 621 byte* cur = nullptr; 622 byte* end = nullptr; 623 624 if (argc == 1) { 625 cur = reinterpret_cast<byte*>(sim_->get_pc()); 626 end = cur + (10 * kInstrSize); 627 } else if (argc == 2) { 628 auto regnum = Registers::FromName(arg1); 629 if (regnum != Registers::invalid_reg || strncmp(arg1, "0x", 2) == 0) { 630 // The argument is an address or a register name. 631 sreg_t value; 632 if (GetValue(arg1, &value)) { 633 cur = reinterpret_cast<byte*>(value); 634 // Disassemble 10 instructions at <arg1>. 635 end = cur + (10 * kInstrSize); 636 } 637 } else { 638 // The argument is the number of instructions. 639 sreg_t value; 640 if (GetValue(arg1, &value)) { 641 cur = reinterpret_cast<byte*>(sim_->get_pc()); 642 // Disassemble <arg1> instructions. 643 end = cur + (value * kInstrSize); 644 } 645 } 646 } else { 647 sreg_t value1; 648 sreg_t value2; 649 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { 650 cur = reinterpret_cast<byte*>(value1); 651 end = cur + (value2 * kInstrSize); 652 } 653 } 654 while (cur < end) { 655 dasm.InstructionDecode(buffer, cur); 656 printf(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), 657 buffer.start()); 658 cur += kInstrSize; 659 } 660 } else if (strcmp(cmd, "trace") == 0) { 661 Simulator::FLAG_trace_sim = true; 662 Simulator::FLAG_riscv_print_watchpoint = true; 663 } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0 || 664 strcmp(cmd, "tbreak") == 0) { 665 bool is_tbreak = strcmp(cmd, "tbreak") == 0; 666 if (argc == 2) { 667 int64_t value; 668 if (GetValue(arg1, &value)) { 669 sim_->SetBreakpoint(reinterpret_cast<SimInstruction*>(value), 670 is_tbreak); 671 } else { 672 printf("%s unrecognized\n", arg1); 673 } 674 } else { 675 sim_->ListBreakpoints(); 676 printf("Use `break <address>` to set or disable a breakpoint\n"); 677 printf( 678 "Use `tbreak <address>` to set or disable a temporary " 679 "breakpoint\n"); 680 } 681 } else if (strcmp(cmd, "flags") == 0) { 682 printf("No flags on RISC-V !\n"); 683 } else if (strcmp(cmd, "stop") == 0) { 684 int64_t value; 685 if (argc == 3) { 686 // Print information about all/the specified breakpoint(s). 687 if (strcmp(arg1, "info") == 0) { 688 if (strcmp(arg2, "all") == 0) { 689 printf("Stop information:\n"); 690 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 691 i++) { 692 sim_->printStopInfo(i); 693 } 694 } else if (GetValue(arg2, &value)) { 695 sim_->printStopInfo(value); 696 } else { 697 printf("Unrecognized argument.\n"); 698 } 699 } else if (strcmp(arg1, "enable") == 0) { 700 // Enable all/the specified breakpoint(s). 701 if (strcmp(arg2, "all") == 0) { 702 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 703 i++) { 704 sim_->enableStop(i); 705 } 706 } else if (GetValue(arg2, &value)) { 707 sim_->enableStop(value); 708 } else { 709 printf("Unrecognized argument.\n"); 710 } 711 } else if (strcmp(arg1, "disable") == 0) { 712 // Disable all/the specified breakpoint(s). 713 if (strcmp(arg2, "all") == 0) { 714 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 715 i++) { 716 sim_->disableStop(i); 717 } 718 } else if (GetValue(arg2, &value)) { 719 sim_->disableStop(value); 720 } else { 721 printf("Unrecognized argument.\n"); 722 } 723 } 724 } else { 725 printf("Wrong usage. Use help command for more information.\n"); 726 } 727 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) { 728 UNIMPLEMENTED(); 729 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { 730 printf("cont (alias 'c')\n"); 731 printf(" Continue execution\n"); 732 printf("stepi (alias 'si')\n"); 733 printf(" Step one instruction\n"); 734 printf("print (alias 'p')\n"); 735 printf(" print <register>\n"); 736 printf(" Print register content\n"); 737 printf(" Use register name 'all' to print all GPRs\n"); 738 printf(" Use register name 'allf' to print all GPRs and FPRs\n"); 739 printf("printobject (alias 'po')\n"); 740 printf(" printobject <register>\n"); 741 printf(" Print an object from a register\n"); 742 printf("stack\n"); 743 printf(" stack [<words>]\n"); 744 printf(" Dump stack content, default dump 10 words)\n"); 745 printf("mem\n"); 746 printf(" mem <address> [<words>]\n"); 747 printf(" Dump memory content, default dump 10 words)\n"); 748 printf("watch\n"); 749 printf(" watch <address> \n"); 750 printf(" watch memory content.)\n"); 751 printf("flags\n"); 752 printf(" print flags\n"); 753 printf("disasm (alias 'di')\n"); 754 printf(" disasm [<instructions>]\n"); 755 printf(" disasm [<address/register>] (e.g., disasm pc) \n"); 756 printf(" disasm [[<address/register>] <instructions>]\n"); 757 printf(" Disassemble code, default is 10 instructions\n"); 758 printf(" from pc\n"); 759 printf("gdb \n"); 760 printf(" Return to gdb if the simulator was started with gdb\n"); 761 printf("break (alias 'b')\n"); 762 printf(" break : list all breakpoints\n"); 763 printf(" break <address> : set / enable / disable a breakpoint.\n"); 764 printf("tbreak\n"); 765 printf(" tbreak : list all breakpoints\n"); 766 printf( 767 " tbreak <address> : set / enable / disable a temporary " 768 "breakpoint.\n"); 769 printf(" Set a breakpoint enabled only for one stop. \n"); 770 printf("stop feature:\n"); 771 printf(" Description:\n"); 772 printf(" Stops are debug instructions inserted by\n"); 773 printf(" the Assembler::stop() function.\n"); 774 printf(" When hitting a stop, the Simulator will\n"); 775 printf(" stop and give control to the Debugger.\n"); 776 printf(" All stop codes are watched:\n"); 777 printf(" - They can be enabled / disabled: the Simulator\n"); 778 printf(" will / won't stop when hitting them.\n"); 779 printf(" - The Simulator keeps track of how many times they \n"); 780 printf(" are met. (See the info command.) Going over a\n"); 781 printf(" disabled stop still increases its counter. \n"); 782 printf(" Commands:\n"); 783 printf(" stop info all/<code> : print infos about number <code>\n"); 784 printf(" or all stop(s).\n"); 785 printf(" stop enable/disable all/<code> : enables / disables\n"); 786 printf(" all or number <code> stop(s)\n"); 787 } else { 788 printf("Unknown command: %s\n", cmd); 789 } 790 } 791 } 792 793 # undef COMMAND_SIZE 794 # undef ARG_SIZE 795 796 # undef STR 797 # undef XSTR 798 } 799 800 void Simulator::SetBreakpoint(SimInstruction* location, bool is_tbreak) { 801 for (unsigned i = 0; i < breakpoints_.size(); i++) { 802 if (breakpoints_.at(i).location == location) { 803 if (breakpoints_.at(i).is_tbreak != is_tbreak) { 804 printf("Change breakpoint at %p to %s breakpoint\n", 805 reinterpret_cast<void*>(location), 806 is_tbreak ? "temporary" : "regular"); 807 breakpoints_.at(i).is_tbreak = is_tbreak; 808 return; 809 } 810 printf("Existing breakpoint at %p was %s\n", 811 reinterpret_cast<void*>(location), 812 breakpoints_.at(i).enabled ? "disabled" : "enabled"); 813 breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled; 814 return; 815 } 816 } 817 Breakpoint new_breakpoint = {location, true, is_tbreak}; 818 breakpoints_.push_back(new_breakpoint); 819 printf("Set a %sbreakpoint at %p\n", is_tbreak ? "temporary " : "", 820 reinterpret_cast<void*>(location)); 821 } 822 823 void Simulator::ListBreakpoints() { 824 printf("Breakpoints:\n"); 825 for (unsigned i = 0; i < breakpoints_.size(); i++) { 826 printf("%p : %s %s\n", 827 reinterpret_cast<void*>(breakpoints_.at(i).location), 828 breakpoints_.at(i).enabled ? "enabled" : "disabled", 829 breakpoints_.at(i).is_tbreak ? ": temporary" : ""); 830 } 831 } 832 833 void Simulator::CheckBreakpoints() { 834 bool hit_a_breakpoint = false; 835 bool is_tbreak = false; 836 SimInstruction* pc_ = reinterpret_cast<SimInstruction*>(get_pc()); 837 for (unsigned i = 0; i < breakpoints_.size(); i++) { 838 if ((breakpoints_.at(i).location == pc_) && breakpoints_.at(i).enabled) { 839 hit_a_breakpoint = true; 840 if (breakpoints_.at(i).is_tbreak) { 841 // Disable a temporary breakpoint. 842 is_tbreak = true; 843 breakpoints_.at(i).enabled = false; 844 } 845 break; 846 } 847 } 848 if (hit_a_breakpoint) { 849 printf("Hit %sa breakpoint at %p.\n", is_tbreak ? "and disabled " : "", 850 reinterpret_cast<void*>(pc_)); 851 RiscvDebugger dbg(this); 852 dbg.Debug(); 853 } 854 } 855 856 static bool AllOnOnePage(uintptr_t start, int size) { 857 intptr_t start_page = (start & ~CachePage::kPageMask); 858 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); 859 return start_page == end_page; 860 } 861 862 void Simulator::setLastDebuggerInput(char* input) { 863 js_free(lastDebuggerInput_); 864 lastDebuggerInput_ = input; 865 } 866 867 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache, 868 void* page) { 869 SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page); 870 if (p) { 871 return p->value(); 872 } 873 AutoEnterOOMUnsafeRegion oomUnsafe; 874 CachePage* new_page = js_new<CachePage>(); 875 if (!new_page || !i_cache.add(p, page, new_page)) { 876 oomUnsafe.crash("Simulator CachePage"); 877 } 878 return new_page; 879 } 880 881 // Flush from start up to and not including start + size. 882 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache, 883 intptr_t start, int size) { 884 MOZ_ASSERT(size <= CachePage::kPageSize); 885 MOZ_ASSERT(AllOnOnePage(start, size - 1)); 886 MOZ_ASSERT((start & CachePage::kLineMask) == 0); 887 MOZ_ASSERT((size & CachePage::kLineMask) == 0); 888 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); 889 int offset = (start & CachePage::kPageMask); 890 CachePage* cache_page = GetCachePageLocked(i_cache, page); 891 char* valid_bytemap = cache_page->validityByte(offset); 892 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); 893 } 894 895 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache, 896 void* start_addr, size_t size) { 897 intptr_t start = reinterpret_cast<intptr_t>(start_addr); 898 int intra_line = (start & CachePage::kLineMask); 899 start -= intra_line; 900 size += intra_line; 901 size = ((size - 1) | CachePage::kLineMask) + 1; 902 int offset = (start & CachePage::kPageMask); 903 while (!AllOnOnePage(start, size - 1)) { 904 int bytes_to_flush = CachePage::kPageSize - offset; 905 FlushOnePageLocked(i_cache, start, bytes_to_flush); 906 start += bytes_to_flush; 907 size -= bytes_to_flush; 908 MOZ_ASSERT((start & CachePage::kPageMask) == 0); 909 offset = 0; 910 } 911 if (size != 0) { 912 FlushOnePageLocked(i_cache, start, size); 913 } 914 } 915 916 /* static */ 917 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) { 918 intptr_t address = reinterpret_cast<intptr_t>(instr); 919 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); 920 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); 921 int offset = (address & CachePage::kPageMask); 922 CachePage* cache_page = GetCachePageLocked(icache(), page); 923 char* cache_valid_byte = cache_page->validityByte(offset); 924 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); 925 char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask); 926 927 if (cache_hit) { 928 # ifdef DEBUG 929 // Check that the data in memory matches the contents of the I-cache. 930 int cmpret = memcmp(reinterpret_cast<void*>(instr), 931 cache_page->cachedData(offset), kInstrSize); 932 MOZ_ASSERT(cmpret == 0); 933 # endif 934 } else { 935 // Cache miss. Load memory into the cache. 936 memcpy(cached_line, line, CachePage::kLineLength); 937 *cache_valid_byte = CachePage::LINE_VALID; 938 } 939 } 940 941 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) { 942 return U32(reinterpret_cast<uintptr_t>(l)) >> 2; 943 } 944 945 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) { 946 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0); 947 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0); 948 return k == l; 949 } 950 951 /* static */ 952 void SimulatorProcess::FlushICache(void* start_addr, size_t size) { 953 if (!ICacheCheckingDisableCount) { 954 AutoLockSimulatorCache als; 955 js::jit::FlushICacheLocked(icache(), start_addr, size); 956 } 957 } 958 959 Simulator::Simulator() { 960 // Set up simulator support first. Some of this information is needed to 961 // setup the architecture state. 962 963 // Note, allocation and anything that depends on allocated memory is 964 // deferred until init(), in order to handle OOM properly. 965 966 stack_ = nullptr; 967 stackLimit_ = 0; 968 pc_modified_ = false; 969 icount_ = 0; 970 break_count_ = 0; 971 break_pc_ = nullptr; 972 break_instr_ = 0; 973 single_stepping_ = false; 974 single_step_callback_ = nullptr; 975 single_step_callback_arg_ = nullptr; 976 977 // Set up architecture state. 978 // All registers are initialized to zero to start with. 979 for (int i = 0; i < Simulator::Register::kNumSimuRegisters; i++) { 980 registers_[i] = 0; 981 } 982 for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) { 983 FPUregisters_[i] = 0; 984 } 985 FCSR_ = 0; 986 LLBit_ = false; 987 LLAddr_ = 0; 988 lastLLValue_ = 0; 989 990 // The ra and pc are initialized to a known bad value that will cause an 991 // access violation if the simulator ever tries to execute it. 992 registers_[pc] = bad_ra; 993 registers_[ra] = bad_ra; 994 995 for (int i = 0; i < kNumExceptions; i++) { 996 exceptions[i] = 0; 997 } 998 999 lastDebuggerInput_ = nullptr; 1000 } 1001 1002 bool Simulator::init() { 1003 // Allocate 2MB for the stack. Note that we will only use 1MB, see below. 1004 static const size_t stackSize = 2 * 1024 * 1024; 1005 stack_ = js_pod_malloc<char>(stackSize); 1006 if (!stack_) { 1007 return false; 1008 } 1009 1010 // Leave a safety margin of 1MB to prevent overrunning the stack when 1011 // pushing values (total stack size is 2MB). 1012 stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024; 1013 1014 // The sp is initialized to point to the bottom (high address) of the 1015 // allocated stack area. To be safe in potential stack underflows we leave 1016 // some buffer below. 1017 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64; 1018 1019 return true; 1020 } 1021 1022 // When the generated code calls an external reference we need to catch that in 1023 // the simulator. The external reference will be a function compiled for the 1024 // host architecture. We need to call that function instead of trying to 1025 // execute it with the simulator. We do that by redirecting the external 1026 // reference to a swi (software-interrupt) instruction that is handled by 1027 // the simulator. We write the original destination of the jump just at a known 1028 // offset from the swi instruction so the simulator knows what to call. 1029 class Redirection { 1030 friend class SimulatorProcess; 1031 1032 // sim's lock must already be held. 1033 Redirection(void* nativeFunction, ABIFunctionType type) 1034 : nativeFunction_(nativeFunction), 1035 swiInstruction_(rtCallRedirInstr), 1036 type_(type), 1037 next_(nullptr) { 1038 next_ = SimulatorProcess::redirection(); 1039 if (!SimulatorProcess::ICacheCheckingDisableCount) { 1040 FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(), 1041 kInstrSize); 1042 } 1043 SimulatorProcess::setRedirection(this); 1044 } 1045 1046 public: 1047 void* addressOfSwiInstruction() { return &swiInstruction_; } 1048 void* nativeFunction() const { return nativeFunction_; } 1049 ABIFunctionType type() const { return type_; } 1050 1051 static Redirection* Get(void* nativeFunction, ABIFunctionType type) { 1052 AutoLockSimulatorCache als; 1053 1054 Redirection* current = SimulatorProcess::redirection(); 1055 for (; current != nullptr; current = current->next_) { 1056 if (current->nativeFunction_ == nativeFunction) { 1057 MOZ_ASSERT(current->type() == type); 1058 return current; 1059 } 1060 } 1061 1062 // Note: we can't use js_new here because the constructor is private. 1063 AutoEnterOOMUnsafeRegion oomUnsafe; 1064 Redirection* redir = js_pod_malloc<Redirection>(1); 1065 if (!redir) { 1066 oomUnsafe.crash("Simulator redirection"); 1067 } 1068 new (redir) Redirection(nativeFunction, type); 1069 return redir; 1070 } 1071 1072 static Redirection* FromSwiInstruction(Instruction* swiInstruction) { 1073 uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction); 1074 uint8_t* addrOfRedirection = 1075 addrOfSwi - offsetof(Redirection, swiInstruction_); 1076 return reinterpret_cast<Redirection*>(addrOfRedirection); 1077 } 1078 1079 private: 1080 void* nativeFunction_; 1081 uint32_t swiInstruction_; 1082 ABIFunctionType type_; 1083 Redirection* next_; 1084 }; 1085 1086 Simulator::~Simulator() { js_free(stack_); } 1087 1088 SimulatorProcess::SimulatorProcess() 1089 : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) { 1090 if (getenv("MIPS_SIM_ICACHE_CHECKS")) { 1091 ICacheCheckingDisableCount = 0; 1092 } 1093 } 1094 1095 SimulatorProcess::~SimulatorProcess() { 1096 Redirection* r = redirection_; 1097 while (r) { 1098 Redirection* next = r->next_; 1099 js_delete(r); 1100 r = next; 1101 } 1102 } 1103 1104 /* static */ 1105 void* Simulator::RedirectNativeFunction(void* nativeFunction, 1106 ABIFunctionType type) { 1107 Redirection* redirection = Redirection::Get(nativeFunction, type); 1108 return redirection->addressOfSwiInstruction(); 1109 } 1110 1111 // Get the active Simulator for the current thread. 1112 Simulator* Simulator::Current() { 1113 JSContext* cx = TlsContext.get(); 1114 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 1115 return cx->simulator(); 1116 } 1117 1118 // Sets the register in the architecture state. It will also deal with updating 1119 // Simulator internal state for special registers such as PC. 1120 void Simulator::setRegister(int reg, int64_t value) { 1121 MOZ_ASSERT((reg >= 0) && (reg < Simulator::Register::kNumSimuRegisters)); 1122 if (reg == pc) { 1123 pc_modified_ = true; 1124 } 1125 1126 // Zero register always holds 0. 1127 registers_[reg] = (reg == 0) ? 0 : value; 1128 } 1129 1130 void Simulator::setFpuRegister(int fpureg, int64_t value) { 1131 MOZ_ASSERT((fpureg >= 0) && 1132 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1133 FPUregisters_[fpureg] = value; 1134 } 1135 1136 void Simulator::setFpuRegisterLo(int fpureg, int32_t value) { 1137 MOZ_ASSERT((fpureg >= 0) && 1138 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1139 *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]) = value; 1140 } 1141 1142 void Simulator::setFpuRegisterHi(int fpureg, int32_t value) { 1143 MOZ_ASSERT((fpureg >= 0) && 1144 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1145 *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1) = value; 1146 } 1147 1148 void Simulator::setFpuRegisterFloat(int fpureg, float value) { 1149 MOZ_ASSERT((fpureg >= 0) && 1150 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1151 *mozilla::BitwiseCast<int64_t*>(&FPUregisters_[fpureg]) = box_float(value); 1152 } 1153 1154 void Simulator::setFpuRegisterFloat(int fpureg, Float32 value) { 1155 MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1156 Float64 t = Float64::FromBits(box_float(value.get_bits())); 1157 memcpy(&FPUregisters_[fpureg], &t, 8); 1158 } 1159 1160 void Simulator::setFpuRegisterDouble(int fpureg, double value) { 1161 MOZ_ASSERT((fpureg >= 0) && 1162 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1163 *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value; 1164 } 1165 1166 void Simulator::setFpuRegisterDouble(int fpureg, Float64 value) { 1167 MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1168 memcpy(&FPUregisters_[fpureg], &value, 8); 1169 } 1170 1171 // Get the register from the architecture state. This function does handle 1172 // the special case of accessing the PC register. 1173 int64_t Simulator::getRegister(int reg) const { 1174 MOZ_ASSERT((reg >= 0) && (reg < Simulator::Register::kNumSimuRegisters)); 1175 if (reg == 0) { 1176 return 0; 1177 } 1178 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0); 1179 } 1180 1181 int64_t Simulator::getFpuRegister(int fpureg) const { 1182 MOZ_ASSERT((fpureg >= 0) && 1183 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1184 return FPUregisters_[fpureg]; 1185 } 1186 1187 int32_t Simulator::getFpuRegisterLo(int fpureg) const { 1188 MOZ_ASSERT((fpureg >= 0) && 1189 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1190 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]); 1191 } 1192 1193 int32_t Simulator::getFpuRegisterHi(int fpureg) const { 1194 MOZ_ASSERT((fpureg >= 0) && 1195 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1196 return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1); 1197 } 1198 1199 float Simulator::getFpuRegisterFloat(int fpureg) const { 1200 MOZ_ASSERT((fpureg >= 0) && 1201 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1202 return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]); 1203 } 1204 1205 Float32 Simulator::getFpuRegisterFloat32(int fpureg) const { 1206 MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1207 if (!is_boxed_float(FPUregisters_[fpureg])) { 1208 return Float32::FromBits(0x7ffc0000); 1209 } 1210 return Float32::FromBits( 1211 *bit_cast<uint32_t*>(const_cast<int64_t*>(&FPUregisters_[fpureg]))); 1212 } 1213 1214 double Simulator::getFpuRegisterDouble(int fpureg) const { 1215 MOZ_ASSERT((fpureg >= 0) && 1216 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1217 return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]); 1218 } 1219 1220 Float64 Simulator::getFpuRegisterFloat64(int fpureg) const { 1221 MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1222 return Float64::FromBits(FPUregisters_[fpureg]); 1223 } 1224 1225 void Simulator::setCallResultDouble(double result) { 1226 setFpuRegisterDouble(fa0, result); 1227 } 1228 1229 void Simulator::setCallResultFloat(float result) { 1230 setFpuRegisterFloat(fa0, result); 1231 } 1232 1233 void Simulator::setCallResult(int64_t res) { setRegister(a0, res); } 1234 1235 void Simulator::setCallResult(__int128_t res) { 1236 setRegister(a0, I64(res)); 1237 setRegister(a1, I64(res >> 64)); 1238 } 1239 1240 // Raw access to the PC register. 1241 void Simulator::set_pc(int64_t value) { 1242 pc_modified_ = true; 1243 registers_[pc] = value; 1244 } 1245 1246 bool Simulator::has_bad_pc() const { 1247 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); 1248 } 1249 1250 // Raw access to the PC register without the special adjustment when reading. 1251 int64_t Simulator::get_pc() const { return registers_[pc]; } 1252 1253 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() { 1254 wasm::RegisterState state; 1255 state.pc = (void*)get_pc(); 1256 state.fp = (void*)getRegister(fp); 1257 state.sp = (void*)getRegister(sp); 1258 state.lr = (void*)getRegister(ra); 1259 return state; 1260 } 1261 1262 void Simulator::HandleWasmTrap() { 1263 uint8_t* newPC; 1264 if (wasm::HandleIllegalInstruction(registerState(), &newPC)) { 1265 set_pc(int64_t(newPC)); 1266 return; 1267 } 1268 } 1269 1270 // TODO(plind): consider making icount_ printing a flag option. 1271 template <typename T> 1272 void Simulator::TraceMemRd(sreg_t addr, T value, sreg_t reg_value) { 1273 if (FLAG_trace_sim) { 1274 if (std::is_integral<T>::value) { 1275 switch (sizeof(T)) { 1276 case 1: 1277 SNPrintF(trace_buf_, 1278 "%016" REGIx_FORMAT " (%" PRId64 ") int8:%" PRId8 1279 " uint8:%" PRIu8 " <-- [addr: %" REGIx_FORMAT "]", 1280 reg_value, icount_, static_cast<int8_t>(value), 1281 static_cast<uint8_t>(value), addr); 1282 break; 1283 case 2: 1284 SNPrintF(trace_buf_, 1285 "%016" REGIx_FORMAT " (%" PRId64 ") int16:%" PRId16 1286 " uint16:%" PRIu16 " <-- [addr: %" REGIx_FORMAT "]", 1287 reg_value, icount_, static_cast<int16_t>(value), 1288 static_cast<uint16_t>(value), addr); 1289 break; 1290 case 4: 1291 SNPrintF(trace_buf_, 1292 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 1293 " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]", 1294 reg_value, icount_, static_cast<int32_t>(value), 1295 static_cast<uint32_t>(value), addr); 1296 break; 1297 case 8: 1298 SNPrintF(trace_buf_, 1299 "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" PRId64 1300 " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]", 1301 reg_value, icount_, static_cast<int64_t>(value), 1302 static_cast<uint64_t>(value), addr); 1303 break; 1304 default: 1305 UNREACHABLE(); 1306 } 1307 } else if (std::is_same<float, T>::value) { 1308 SNPrintF(trace_buf_, 1309 "%016" REGIx_FORMAT " (%" PRId64 1310 ") flt:%e <-- [addr: %" REGIx_FORMAT "]", 1311 reg_value, icount_, static_cast<float>(value), addr); 1312 } else if (std::is_same<double, T>::value) { 1313 SNPrintF(trace_buf_, 1314 "%016" REGIx_FORMAT " (%" PRId64 1315 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", 1316 reg_value, icount_, static_cast<double>(value), addr); 1317 } else { 1318 UNREACHABLE(); 1319 } 1320 } 1321 } 1322 1323 void Simulator::TraceMemRdFloat(sreg_t addr, Float32 value, int64_t reg_value) { 1324 if (FLAG_trace_sim) { 1325 SNPrintF(trace_buf_, 1326 "%016" PRIx64 " (%" PRId64 1327 ") flt:%e <-- [addr: %" REGIx_FORMAT "]", 1328 reg_value, icount_, static_cast<float>(value.get_scalar()), addr); 1329 } 1330 } 1331 1332 void Simulator::TraceMemRdDouble(sreg_t addr, double value, int64_t reg_value) { 1333 if (FLAG_trace_sim) { 1334 SNPrintF(trace_buf_, 1335 "%016" PRIx64 " (%" PRId64 1336 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", 1337 reg_value, icount_, static_cast<double>(value), addr); 1338 } 1339 } 1340 1341 void Simulator::TraceMemRdDouble(sreg_t addr, Float64 value, 1342 int64_t reg_value) { 1343 if (FLAG_trace_sim) { 1344 SNPrintF(trace_buf_, 1345 "%016" PRIx64 " (%" PRId64 1346 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", 1347 reg_value, icount_, static_cast<double>(value.get_scalar()), addr); 1348 } 1349 } 1350 1351 template <typename T> 1352 void Simulator::TraceMemWr(sreg_t addr, T value) { 1353 if (FLAG_trace_sim) { 1354 switch (sizeof(T)) { 1355 case 1: 1356 SNPrintF(trace_buf_, 1357 " (%" PRIu64 ") int8:%" PRId8 1358 " uint8:%" PRIu8 " --> [addr: %" REGIx_FORMAT "]", 1359 icount_, static_cast<int8_t>(value), 1360 static_cast<uint8_t>(value), addr); 1361 break; 1362 case 2: 1363 SNPrintF(trace_buf_, 1364 " (%" PRIu64 ") int16:%" PRId16 1365 " uint16:%" PRIu16 " --> [addr: %" REGIx_FORMAT "]", 1366 icount_, static_cast<int16_t>(value), 1367 static_cast<uint16_t>(value), addr); 1368 break; 1369 case 4: 1370 if (std::is_integral<T>::value) { 1371 SNPrintF(trace_buf_, 1372 " (%" PRIu64 ") int32:%" PRId32 1373 " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]", 1374 icount_, static_cast<int32_t>(value), 1375 static_cast<uint32_t>(value), addr); 1376 } else { 1377 SNPrintF(trace_buf_, 1378 " (%" PRIu64 1379 ") flt:%e --> [addr: %" REGIx_FORMAT "]", 1380 icount_, static_cast<float>(value), addr); 1381 } 1382 break; 1383 case 8: 1384 if (std::is_integral<T>::value) { 1385 SNPrintF(trace_buf_, 1386 " (%" PRIu64 ") int64:%" PRId64 1387 " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]", 1388 icount_, static_cast<int64_t>(value), 1389 static_cast<uint64_t>(value), addr); 1390 } else { 1391 SNPrintF(trace_buf_, 1392 " (%" PRIu64 1393 ") dbl:%e --> [addr: %" REGIx_FORMAT "]", 1394 icount_, static_cast<double>(value), addr); 1395 } 1396 break; 1397 default: 1398 UNREACHABLE(); 1399 } 1400 } 1401 } 1402 1403 void Simulator::TraceMemWrDouble(sreg_t addr, double value) { 1404 if (FLAG_trace_sim) { 1405 SNPrintF(trace_buf_, 1406 " (%" PRIu64 1407 ") dbl:%e --> [addr: %" REGIx_FORMAT "]", 1408 icount_, value, addr); 1409 } 1410 } 1411 1412 template <typename T> 1413 void Simulator::TraceLr(sreg_t addr, T value, sreg_t reg_value) { 1414 if (FLAG_trace_sim) { 1415 if (std::is_integral<T>::value) { 1416 switch (sizeof(T)) { 1417 case 4: 1418 SNPrintF(trace_buf_, 1419 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 1420 " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]", 1421 reg_value, icount_, static_cast<int32_t>(value), 1422 static_cast<uint32_t>(value), addr); 1423 break; 1424 case 8: 1425 SNPrintF(trace_buf_, 1426 "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" PRId64 1427 " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]", 1428 reg_value, icount_, static_cast<int64_t>(value), 1429 static_cast<uint64_t>(value), addr); 1430 break; 1431 default: 1432 UNREACHABLE(); 1433 } 1434 } else { 1435 UNREACHABLE(); 1436 } 1437 } 1438 } 1439 1440 template <typename T> 1441 void Simulator::TraceSc(sreg_t addr, T value) { 1442 if (FLAG_trace_sim) { 1443 switch (sizeof(T)) { 1444 case 4: 1445 SNPrintF(trace_buf_, 1446 "%016" REGIx_FORMAT " (%" PRIu64 ") int32:%" PRId32 1447 " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]", 1448 getRegister(rd_reg()), icount_, static_cast<int32_t>(value), 1449 static_cast<uint32_t>(value), addr); 1450 break; 1451 case 8: 1452 SNPrintF(trace_buf_, 1453 "%016" REGIx_FORMAT " (%" PRIu64 ") int64:%" PRId64 1454 " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]", 1455 getRegister(rd_reg()), icount_, static_cast<int64_t>(value), 1456 static_cast<uint64_t>(value), addr); 1457 break; 1458 default: 1459 UNREACHABLE(); 1460 } 1461 } 1462 } 1463 1464 // TODO(RISCV): check whether the specific board supports unaligned load/store 1465 // (determined by EEI). For now, we assume the board does not support unaligned 1466 // load/store (e.g., trapping) 1467 template <typename T> 1468 T Simulator::ReadMem(sreg_t addr, Instruction* instr) { 1469 if (handleWasmSegFault(addr, sizeof(T))) { 1470 return -1; 1471 } 1472 if (addr >= 0 && addr < 0x400) { 1473 // This has to be a nullptr-dereference, drop into debugger. 1474 printf("Memory read from bad address: 0x%08" REGIx_FORMAT 1475 " , pc=0x%08" PRIxPTR " \n", 1476 addr, reinterpret_cast<intptr_t>(instr)); 1477 DieOrDebug(); 1478 } 1479 T* ptr = reinterpret_cast<T*>(addr); 1480 T value = *ptr; 1481 return value; 1482 } 1483 1484 template <typename T> 1485 void Simulator::WriteMem(sreg_t addr, T value, Instruction* instr) { 1486 if (handleWasmSegFault(addr, sizeof(T))) { 1487 value = -1; 1488 return; 1489 } 1490 if (addr >= 0 && addr < 0x400) { 1491 // This has to be a nullptr-dereference, drop into debugger. 1492 printf("Memory write to bad address: 0x%08" REGIx_FORMAT 1493 " , pc=0x%08" PRIxPTR " \n", 1494 addr, reinterpret_cast<intptr_t>(instr)); 1495 DieOrDebug(); 1496 } 1497 T* ptr = reinterpret_cast<T*>(addr); 1498 if (!std::is_same<double, T>::value) { 1499 TraceMemWr(addr, value); 1500 } else { 1501 TraceMemWrDouble(addr, value); 1502 } 1503 *ptr = value; 1504 } 1505 1506 template <> 1507 void Simulator::WriteMem(sreg_t addr, Float32 value, Instruction* instr) { 1508 if (handleWasmSegFault(addr, 4)) { 1509 value = Float32(-1.0f); 1510 return; 1511 } 1512 if (addr >= 0 && addr < 0x400) { 1513 // This has to be a nullptr-dereference, drop into debugger. 1514 printf("Memory write to bad address: 0x%08" REGIx_FORMAT 1515 " , pc=0x%08" PRIxPTR " \n", 1516 addr, reinterpret_cast<intptr_t>(instr)); 1517 DieOrDebug(); 1518 } 1519 float* ptr = reinterpret_cast<float*>(addr); 1520 TraceMemWr(addr, value.get_scalar()); 1521 memcpy(ptr, &value, 4); 1522 } 1523 1524 template <> 1525 void Simulator::WriteMem(sreg_t addr, Float64 value, Instruction* instr) { 1526 if (handleWasmSegFault(addr, 8)) { 1527 value = Float64(-1.0); 1528 return; 1529 } 1530 if (addr >= 0 && addr < 0x400) { 1531 // This has to be a nullptr-dereference, drop into debugger. 1532 printf("Memory write to bad address: 0x%08" REGIx_FORMAT 1533 " , pc=0x%08" PRIxPTR " \n", 1534 addr, reinterpret_cast<intptr_t>(instr)); 1535 DieOrDebug(); 1536 } 1537 double* ptr = reinterpret_cast<double*>(addr); 1538 TraceMemWrDouble(addr, value.get_scalar()); 1539 memcpy(ptr, &value, 8); 1540 } 1541 1542 uintptr_t Simulator::stackLimit() const { return stackLimit_; } 1543 1544 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; } 1545 1546 bool Simulator::overRecursed(uintptr_t newsp) const { 1547 if (newsp == 0) { 1548 newsp = getRegister(sp); 1549 } 1550 return newsp <= stackLimit(); 1551 } 1552 1553 bool Simulator::overRecursedWithExtra(uint32_t extra) const { 1554 uintptr_t newsp = getRegister(sp) - extra; 1555 return newsp <= stackLimit(); 1556 } 1557 1558 // Unsupported instructions use format to print an error and stop execution. 1559 void Simulator::format(SimInstruction* instr, const char* format) { 1560 printf("Simulator found unsupported instruction:\n 0x%016" PRIxPTR ": %s\n", 1561 reinterpret_cast<intptr_t>(instr), format); 1562 MOZ_CRASH(); 1563 } 1564 1565 // Note: With the code below we assume that all runtime calls return a 64 bits 1566 // result. If they don't, the v1 result register contains a bogus value, which 1567 // is fine because it is caller-saved. 1568 ABI_FUNCTION_TYPE_SIM_PROTOTYPES 1569 1570 // Generated by Assembler::break_()/stop(), ebreak code is passed as immediate 1571 // field of a subsequent LUI instruction; otherwise returns -1 1572 static inline uint32_t get_ebreak_code(Instruction* instr) { 1573 MOZ_ASSERT(instr->InstructionBits() == kBreakInstr); 1574 uint8_t* cur = reinterpret_cast<uint8_t*>(instr); 1575 Instruction* next_instr = reinterpret_cast<Instruction*>(cur + kInstrSize); 1576 if (next_instr->BaseOpcodeFieldRaw() == LUI) 1577 return (next_instr->Imm20UValue()); 1578 else 1579 return -1; 1580 } 1581 1582 // Software interrupt instructions are used by the simulator to call into C++. 1583 void Simulator::SoftwareInterrupt() { 1584 // There are two instructions that could get us here, the ebreak or ecall 1585 // instructions are "SYSTEM" class opcode distinuished by Imm12Value field w/ 1586 // the rest of instruction fields being zero 1587 // We first check if we met a call_rt_redirected. 1588 if (instr_.InstructionBits() == rtCallRedirInstr) { 1589 Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr()); 1590 uintptr_t nativeFn = 1591 reinterpret_cast<uintptr_t>(redirection->nativeFunction()); 1592 1593 intptr_t arg0 = getRegister(a0); 1594 intptr_t arg1 = getRegister(a1); 1595 intptr_t arg2 = getRegister(a2); 1596 intptr_t arg3 = getRegister(a3); 1597 intptr_t arg4 = getRegister(a4); 1598 intptr_t arg5 = getRegister(a5); 1599 intptr_t arg6 = getRegister(a6); 1600 intptr_t arg7 = getRegister(a7); 1601 1602 // This is dodgy but it works because the C entry stubs are never moved. 1603 // See comment in codegen-arm.cc and bug 1242173. 1604 intptr_t saved_ra = getRegister(ra); 1605 1606 intptr_t external = 1607 reinterpret_cast<intptr_t>(redirection->nativeFunction()); 1608 1609 bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0; 1610 if (!stack_aligned) { 1611 fprintf(stderr, "Runtime call with unaligned stack!\n"); 1612 MOZ_CRASH(); 1613 } 1614 int64_t* sp_ = reinterpret_cast<int64_t*>(getRegister(sp)); 1615 1616 if (single_stepping_) { 1617 single_step_callback_(single_step_callback_arg_, this, nullptr); 1618 } 1619 if (FLAG_trace_sim) { 1620 printf("Call to host function at %p with args %" PRIdPTR ", %" PRIdPTR 1621 ", %" PRIdPTR ", %" PRIdPTR ", %" PRIdPTR ", %" PRIdPTR 1622 ", %" PRIdPTR ", %" PRIdPTR "\n", 1623 reinterpret_cast<void*>(external), arg0, arg1, arg2, arg3, arg4, 1624 arg5, arg6, arg7); 1625 } 1626 switch (redirection->type()) { 1627 ABI_FUNCTION_TYPE_RISCV64_SIM_DISPATCH 1628 default: 1629 MOZ_CRASH("Unknown function type."); 1630 } 1631 1632 if (single_stepping_) { 1633 single_step_callback_(single_step_callback_arg_, this, nullptr); 1634 } 1635 1636 setRegister(ra, saved_ra); 1637 set_pc(getRegister(ra)); 1638 1639 } else if (instr_.InstructionBits() == kBreakInstr && 1640 (get_ebreak_code(instr_.instr()) <= kMaxStopCode)) { 1641 uint32_t code = get_ebreak_code(instr_.instr()); 1642 if (code == 0) { 1643 // Default `ebreak`s generated by 1644 // MacroAssemblerRiscv64Compat::breakpoint(). 1645 DieOrDebug(); 1646 } else if (isWatchpoint(code)) { 1647 printWatchpoint(code); 1648 } else if (IsTracepoint(code)) { 1649 if (!FLAG_debug_sim) { 1650 MOZ_CRASH("Add --debug-sim when tracepoint instruction is used.\n"); 1651 } 1652 // printf("%d %d %d %d %d %d %d\n", code, code & LOG_TRACE, code & 1653 // LOG_REGS, 1654 // code & kDebuggerTracingDirectivesMask, TRACE_ENABLE, 1655 // TRACE_DISABLE, kDebuggerTracingDirectivesMask); 1656 switch (code & kDebuggerTracingDirectivesMask) { 1657 case TRACE_ENABLE: 1658 if (code & LOG_TRACE) { 1659 FLAG_trace_sim = true; 1660 } 1661 if (code & LOG_REGS) { 1662 RiscvDebugger dbg(this); 1663 dbg.printAllRegs(); 1664 } 1665 break; 1666 case TRACE_DISABLE: 1667 if (code & LOG_TRACE) { 1668 FLAG_trace_sim = false; 1669 } 1670 break; 1671 default: 1672 UNREACHABLE(); 1673 } 1674 } else { 1675 increaseStopCounter(code); 1676 handleStop(code); 1677 } 1678 } else { 1679 // uint8_t code = get_ebreak_code(instr_.instr()) - kMaxStopCode - 1; 1680 // switch (LNode::Opcode(code)) { 1681 // #define EMIT_OP(OP, ...) \ 1682 // case LNode::Opcode::OP:\ 1683 // std::cout << #OP << std::endl; \ 1684 // break; 1685 // LIR_OPCODE_LIST(EMIT_OP); 1686 // #undef EMIT_OP 1687 // } 1688 DieOrDebug(); 1689 } 1690 } 1691 1692 // Stop helper functions. 1693 bool Simulator::isWatchpoint(uint32_t code) { 1694 return (code <= kMaxWatchpointCode); 1695 } 1696 1697 bool Simulator::IsTracepoint(uint32_t code) { 1698 return (code <= kMaxTracepointCode && code > kMaxWatchpointCode); 1699 } 1700 1701 void Simulator::printWatchpoint(uint32_t code) { 1702 RiscvDebugger dbg(this); 1703 ++break_count_; 1704 if (FLAG_riscv_print_watchpoint) { 1705 printf("\n---- break %d marker: %20" PRIi64 " (instr count: %20" PRIi64 1706 ") ----\n", 1707 code, break_count_, icount_); 1708 dbg.printAllRegs(); // Print registers and continue running. 1709 } 1710 } 1711 1712 void Simulator::handleStop(uint32_t code) { 1713 // Stop if it is enabled, otherwise go on jumping over the stop 1714 // and the message address. 1715 if (isEnabledStop(code)) { 1716 RiscvDebugger dbg(this); 1717 dbg.Debug(); 1718 } else { 1719 set_pc(get_pc() + 2 * kInstrSize); 1720 } 1721 } 1722 1723 bool Simulator::isStopInstruction(SimInstruction* instr) { 1724 if (instr->InstructionBits() != kBreakInstr) return false; 1725 int32_t code = get_ebreak_code(instr->instr()); 1726 return code != -1 && static_cast<uint32_t>(code) > kMaxWatchpointCode && 1727 static_cast<uint32_t>(code) <= kMaxStopCode; 1728 } 1729 1730 bool Simulator::isEnabledStop(uint32_t code) { 1731 MOZ_ASSERT(code <= kMaxStopCode); 1732 MOZ_ASSERT(code > kMaxWatchpointCode); 1733 return !(watchedStops_[code].count_ & kStopDisabledBit); 1734 } 1735 1736 void Simulator::enableStop(uint32_t code) { 1737 if (!isEnabledStop(code)) { 1738 watchedStops_[code].count_ &= ~kStopDisabledBit; 1739 } 1740 } 1741 1742 void Simulator::disableStop(uint32_t code) { 1743 if (isEnabledStop(code)) { 1744 watchedStops_[code].count_ |= kStopDisabledBit; 1745 } 1746 } 1747 1748 void Simulator::increaseStopCounter(uint32_t code) { 1749 MOZ_ASSERT(code <= kMaxStopCode); 1750 if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) { 1751 printf( 1752 "Stop counter for code %i has overflowed.\n" 1753 "Enabling this code and reseting the counter to 0.\n", 1754 code); 1755 watchedStops_[code].count_ = 0; 1756 enableStop(code); 1757 } else { 1758 watchedStops_[code].count_++; 1759 } 1760 } 1761 1762 // Print a stop status. 1763 void Simulator::printStopInfo(uint32_t code) { 1764 if (code <= kMaxWatchpointCode) { 1765 printf("That is a watchpoint, not a stop.\n"); 1766 return; 1767 } else if (code > kMaxStopCode) { 1768 printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1); 1769 return; 1770 } 1771 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; 1772 int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit; 1773 // Don't print the state of unused breakpoints. 1774 if (count != 0) { 1775 if (watchedStops_[code].desc_) { 1776 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state, 1777 count, watchedStops_[code].desc_); 1778 } else { 1779 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state, 1780 count); 1781 } 1782 } 1783 } 1784 1785 void Simulator::SignalException(Exception e) { 1786 printf("Error: Exception %i raised.", static_cast<int>(e)); 1787 MOZ_CRASH(); 1788 } 1789 1790 // TODO(plind): refactor this messy debug code when we do unaligned access. 1791 void Simulator::DieOrDebug() { 1792 if (FLAG_riscv_trap_to_simulator_debugger) { 1793 RiscvDebugger dbg(this); 1794 dbg.Debug(); 1795 } else { 1796 MOZ_CRASH("Die"); 1797 } 1798 } 1799 1800 // Executes the current instruction. 1801 void Simulator::InstructionDecode(Instruction* instr) { 1802 // if (FLAG_check_icache) { 1803 // CheckICache(SimulatorProcess::icache(), instr); 1804 // } 1805 pc_modified_ = false; 1806 1807 EmbeddedVector<char, 256> buffer; 1808 1809 if (FLAG_trace_sim || FLAG_debug_sim) { 1810 SNPrintF(trace_buf_, " "); 1811 disasm::NameConverter converter; 1812 disasm::Disassembler dasm(converter); 1813 // Use a reasonably large buffer. 1814 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); 1815 1816 // printf("EXECUTING 0x%08" PRIxPTR " %-44s\n", 1817 // reinterpret_cast<intptr_t>(instr), buffer.begin()); 1818 } 1819 1820 instr_ = instr; 1821 switch (instr_.InstructionType()) { 1822 case Instruction::kRType: 1823 DecodeRVRType(); 1824 break; 1825 case Instruction::kR4Type: 1826 DecodeRVR4Type(); 1827 break; 1828 case Instruction::kIType: 1829 DecodeRVIType(); 1830 break; 1831 case Instruction::kSType: 1832 DecodeRVSType(); 1833 break; 1834 case Instruction::kBType: 1835 DecodeRVBType(); 1836 break; 1837 case Instruction::kUType: 1838 DecodeRVUType(); 1839 break; 1840 case Instruction::kJType: 1841 DecodeRVJType(); 1842 break; 1843 case Instruction::kCRType: 1844 DecodeCRType(); 1845 break; 1846 case Instruction::kCAType: 1847 DecodeCAType(); 1848 break; 1849 case Instruction::kCJType: 1850 DecodeCJType(); 1851 break; 1852 case Instruction::kCBType: 1853 DecodeCBType(); 1854 break; 1855 case Instruction::kCIType: 1856 DecodeCIType(); 1857 break; 1858 case Instruction::kCIWType: 1859 DecodeCIWType(); 1860 break; 1861 case Instruction::kCSSType: 1862 DecodeCSSType(); 1863 break; 1864 case Instruction::kCLType: 1865 DecodeCLType(); 1866 break; 1867 case Instruction::kCSType: 1868 DecodeCSType(); 1869 break; 1870 # ifdef CAN_USE_RVV_INSTRUCTIONS 1871 case Instruction::kVType: 1872 DecodeVType(); 1873 break; 1874 # endif 1875 default: 1876 UNSUPPORTED(); 1877 } 1878 1879 if (FLAG_trace_sim) { 1880 printf(" 0x%012" PRIxPTR " %-44s\t%s\n", 1881 reinterpret_cast<intptr_t>(instr), buffer.start(), 1882 trace_buf_.start()); 1883 } 1884 1885 if (!pc_modified_) { 1886 setRegister(pc, reinterpret_cast<sreg_t>(instr) + instr->InstructionSize()); 1887 } 1888 1889 if (watch_address_ != nullptr) { 1890 printf(" 0x%012" PRIxPTR " : 0x%016" REGIx_FORMAT " %14" REGId_FORMAT 1891 " \n", 1892 reinterpret_cast<intptr_t>(watch_address_), I64(*watch_address_), 1893 I64(*watch_address_)); 1894 if (watch_value_ != *watch_address_) { 1895 RiscvDebugger dbg(this); 1896 dbg.Debug(); 1897 watch_value_ = *watch_address_; 1898 } 1899 } 1900 } 1901 1902 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) { 1903 single_stepping_ = true; 1904 single_step_callback_ = cb; 1905 single_step_callback_arg_ = arg; 1906 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 1907 } 1908 1909 void Simulator::disable_single_stepping() { 1910 if (!single_stepping_) { 1911 return; 1912 } 1913 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 1914 single_stepping_ = false; 1915 single_step_callback_ = nullptr; 1916 single_step_callback_arg_ = nullptr; 1917 } 1918 1919 template <bool enableStopSimAt> 1920 void Simulator::execute() { 1921 if (single_stepping_) { 1922 single_step_callback_(single_step_callback_arg_, this, nullptr); 1923 } 1924 1925 // Get the PC to simulate. Cannot use the accessor here as we need the 1926 // raw PC value and not the one used as input to arithmetic instructions. 1927 int64_t program_counter = get_pc(); 1928 1929 while (program_counter != end_sim_pc) { 1930 if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) { 1931 RiscvDebugger dbg(this); 1932 dbg.Debug(); 1933 } 1934 if (single_stepping_) { 1935 single_step_callback_(single_step_callback_arg_, this, 1936 (void*)program_counter); 1937 } 1938 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); 1939 InstructionDecode(instr); 1940 icount_++; 1941 program_counter = get_pc(); 1942 } 1943 1944 if (single_stepping_) { 1945 single_step_callback_(single_step_callback_arg_, this, nullptr); 1946 } 1947 } 1948 1949 // RISCV Instruction Decode Routine 1950 void Simulator::DecodeRVRType() { 1951 switch (instr_.InstructionBits() & kRTypeMask) { 1952 case RO_ADD: { 1953 set_rd(sext_xlen(rs1() + rs2())); 1954 break; 1955 } 1956 case RO_SUB: { 1957 set_rd(sext_xlen(rs1() - rs2())); 1958 break; 1959 } 1960 case RO_SLL: { 1961 set_rd(sext_xlen(rs1() << (rs2() & (xlen - 1)))); 1962 break; 1963 } 1964 case RO_SLT: { 1965 set_rd(sreg_t(rs1()) < sreg_t(rs2())); 1966 break; 1967 } 1968 case RO_SLTU: { 1969 set_rd(reg_t(rs1()) < reg_t(rs2())); 1970 break; 1971 } 1972 case RO_XOR: { 1973 set_rd(rs1() ^ rs2()); 1974 break; 1975 } 1976 case RO_SRL: { 1977 set_rd(sext_xlen(zext_xlen(rs1()) >> (rs2() & (xlen - 1)))); 1978 break; 1979 } 1980 case RO_SRA: { 1981 set_rd(sext_xlen(sext_xlen(rs1()) >> (rs2() & (xlen - 1)))); 1982 break; 1983 } 1984 case RO_OR: { 1985 set_rd(rs1() | rs2()); 1986 break; 1987 } 1988 case RO_AND: { 1989 set_rd(rs1() & rs2()); 1990 break; 1991 } 1992 case RO_ANDN: 1993 set_rd(rs1() & ~rs2()); 1994 break; 1995 case RO_ORN: 1996 set_rd(rs1() | (~rs2())); 1997 break; 1998 case RO_XNOR: 1999 set_rd((~rs1()) ^ (~rs2())); 2000 break; 2001 # ifdef JS_CODEGEN_RISCV64 2002 case RO_ADDW: { 2003 set_rd(sext32(rs1() + rs2())); 2004 break; 2005 } 2006 case RO_ADDUW: 2007 set_rd(zext32(rs1()) + rs2()); 2008 break; 2009 case RO_SUBW: { 2010 set_rd(sext32(rs1() - rs2())); 2011 break; 2012 } 2013 case RO_SLLW: { 2014 set_rd(sext32(rs1() << (rs2() & 0x1F))); 2015 break; 2016 } 2017 case RO_SRLW: { 2018 set_rd(sext32(uint32_t(rs1()) >> (rs2() & 0x1F))); 2019 break; 2020 } 2021 case RO_SRAW: { 2022 set_rd(sext32(int32_t(rs1()) >> (rs2() & 0x1F))); 2023 break; 2024 } 2025 case RO_SH1ADDUW: { 2026 set_rd(rs2() + (zext32(rs1()) << 1)); 2027 break; 2028 } 2029 case RO_SH2ADDUW: { 2030 set_rd(rs2() + (zext32(rs1()) << 2)); 2031 break; 2032 } 2033 case RO_SH3ADDUW: { 2034 set_rd(rs2() + (zext32(rs1()) << 3)); 2035 break; 2036 } 2037 case RO_ROLW: { 2038 reg_t extz_rs1 = zext32(rs1()); 2039 sreg_t shamt = rs2() & 31; 2040 set_rd(sext32((extz_rs1 << shamt) | (extz_rs1 >> (32 - shamt)))); 2041 break; 2042 } 2043 case RO_RORW: { 2044 reg_t extz_rs1 = zext32(rs1()); 2045 sreg_t shamt = rs2() & 31; 2046 set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt)))); 2047 break; 2048 } 2049 # endif /* JS_CODEGEN_RISCV64 */ 2050 // TODO(riscv): Add RISCV M extension macro 2051 case RO_MUL: { 2052 set_rd(rs1() * rs2()); 2053 break; 2054 } 2055 case RO_MULH: { 2056 set_rd(mulh(rs1(), rs2())); 2057 break; 2058 } 2059 case RO_MULHSU: { 2060 set_rd(mulhsu(rs1(), rs2())); 2061 break; 2062 } 2063 case RO_MULHU: { 2064 set_rd(mulhu(rs1(), rs2())); 2065 break; 2066 } 2067 case RO_DIV: { 2068 sreg_t lhs = sext_xlen(rs1()); 2069 sreg_t rhs = sext_xlen(rs2()); 2070 if (rhs == 0) { 2071 set_rd(-1); 2072 } else if (lhs == INTPTR_MIN && rhs == -1) { 2073 set_rd(lhs); 2074 } else { 2075 set_rd(sext_xlen(lhs / rhs)); 2076 } 2077 break; 2078 } 2079 case RO_DIVU: { 2080 reg_t lhs = zext_xlen(rs1()); 2081 reg_t rhs = zext_xlen(rs2()); 2082 if (rhs == 0) { 2083 set_rd(UINTPTR_MAX); 2084 } else { 2085 set_rd(zext_xlen(lhs / rhs)); 2086 } 2087 break; 2088 } 2089 case RO_REM: { 2090 sreg_t lhs = sext_xlen(rs1()); 2091 sreg_t rhs = sext_xlen(rs2()); 2092 if (rhs == 0) { 2093 set_rd(lhs); 2094 } else if (lhs == INTPTR_MIN && rhs == -1) { 2095 set_rd(0); 2096 } else { 2097 set_rd(sext_xlen(lhs % rhs)); 2098 } 2099 break; 2100 } 2101 case RO_REMU: { 2102 reg_t lhs = zext_xlen(rs1()); 2103 reg_t rhs = zext_xlen(rs2()); 2104 if (rhs == 0) { 2105 set_rd(lhs); 2106 } else { 2107 set_rd(zext_xlen(lhs % rhs)); 2108 } 2109 break; 2110 } 2111 # ifdef JS_CODEGEN_RISCV64 2112 case RO_MULW: { 2113 set_rd(sext32(sext32(rs1()) * sext32(rs2()))); 2114 break; 2115 } 2116 case RO_DIVW: { 2117 sreg_t lhs = sext32(rs1()); 2118 sreg_t rhs = sext32(rs2()); 2119 if (rhs == 0) { 2120 set_rd(-1); 2121 } else if (lhs == INT32_MIN && rhs == -1) { 2122 set_rd(lhs); 2123 } else { 2124 set_rd(sext32(lhs / rhs)); 2125 } 2126 break; 2127 } 2128 case RO_DIVUW: { 2129 reg_t lhs = zext32(rs1()); 2130 reg_t rhs = zext32(rs2()); 2131 if (rhs == 0) { 2132 set_rd(UINT32_MAX); 2133 } else { 2134 set_rd(zext32(lhs / rhs)); 2135 } 2136 break; 2137 } 2138 case RO_REMW: { 2139 sreg_t lhs = sext32(rs1()); 2140 sreg_t rhs = sext32(rs2()); 2141 if (rhs == 0) { 2142 set_rd(lhs); 2143 } else if (lhs == INT32_MIN && rhs == -1) { 2144 set_rd(0); 2145 } else { 2146 set_rd(sext32(lhs % rhs)); 2147 } 2148 break; 2149 } 2150 case RO_REMUW: { 2151 reg_t lhs = zext32(rs1()); 2152 reg_t rhs = zext32(rs2()); 2153 if (rhs == 0) { 2154 set_rd(zext32(lhs)); 2155 } else { 2156 set_rd(zext32(lhs % rhs)); 2157 } 2158 break; 2159 } 2160 # endif /*JS_CODEGEN_RISCV64*/ 2161 case RO_SH1ADD: 2162 set_rd(rs2() + (rs1() << 1)); 2163 break; 2164 case RO_SH2ADD: 2165 set_rd(rs2() + (rs1() << 2)); 2166 break; 2167 case RO_SH3ADD: 2168 set_rd(rs2() + (rs1() << 3)); 2169 break; 2170 case RO_MAX: 2171 set_rd(rs1() < rs2() ? rs2() : rs1()); 2172 break; 2173 case RO_MAXU: 2174 set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs2() 2175 : rs1()); 2176 break; 2177 case RO_MIN: 2178 set_rd(rs1() < rs2() ? rs1() : rs2()); 2179 break; 2180 case RO_MINU: 2181 set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs1() 2182 : rs2()); 2183 break; 2184 case RO_ZEXTH: 2185 set_rd(zext_xlen(uint16_t(rs1()))); 2186 break; 2187 case RO_ROL: { 2188 sreg_t shamt = rs2() & (xlen - 1); 2189 set_rd((static_cast<reg_t>(rs1()) << shamt) | 2190 (static_cast<reg_t>(rs1()) >> (xlen - shamt))); 2191 break; 2192 } 2193 case RO_ROR: { 2194 sreg_t shamt = rs2() & (xlen - 1); 2195 set_rd((static_cast<reg_t>(rs1()) >> shamt) | 2196 (static_cast<reg_t>(rs1()) << (xlen - shamt))); 2197 break; 2198 } 2199 case RO_BCLR: { 2200 sreg_t index = rs2() & (xlen - 1); 2201 set_rd(rs1() & ~(1l << index)); 2202 break; 2203 } 2204 case RO_BEXT: { 2205 sreg_t index = rs2() & (xlen - 1); 2206 set_rd((rs1() >> index) & 1); 2207 break; 2208 } 2209 case RO_BINV: { 2210 sreg_t index = rs2() & (xlen - 1); 2211 set_rd(rs1() ^ (1 << index)); 2212 break; 2213 } 2214 case RO_BSET: { 2215 sreg_t index = rs2() & (xlen - 1); 2216 set_rd(rs1() | (1 << index)); 2217 break; 2218 } 2219 // TODO(riscv): End Add RISCV M extension macro 2220 default: { 2221 switch (instr_.BaseOpcode()) { 2222 case AMO: 2223 DecodeRVRAType(); 2224 break; 2225 case OP_FP: 2226 DecodeRVRFPType(); 2227 break; 2228 default: 2229 UNSUPPORTED(); 2230 } 2231 } 2232 } 2233 } 2234 2235 template <typename T> 2236 T Simulator::FMaxMinHelper(T a, T b, MaxMinKind kind) { 2237 // set invalid bit for signaling nan 2238 if ((a == std::numeric_limits<T>::signaling_NaN()) || 2239 (b == std::numeric_limits<T>::signaling_NaN())) { 2240 set_csr_bits(csr_fflags, kInvalidOperation); 2241 } 2242 2243 T result = 0; 2244 if (std::isnan(a) && std::isnan(b)) { 2245 result = std::numeric_limits<float>::quiet_NaN(); 2246 } else if (std::isnan(a)) { 2247 result = b; 2248 } else if (std::isnan(b)) { 2249 result = a; 2250 } else if (b == a) { // Handle -0.0 == 0.0 case. 2251 if (kind == MaxMinKind::kMax) { 2252 result = std::signbit(b) ? a : b; 2253 } else { 2254 result = std::signbit(b) ? b : a; 2255 } 2256 } else { 2257 result = (kind == MaxMinKind::kMax) ? fmax(a, b) : fmin(a, b); 2258 } 2259 2260 return result; 2261 } 2262 2263 float Simulator::RoundF2FHelper(float input_val, int rmode) { 2264 if (rmode == DYN) rmode = get_dynamic_rounding_mode(); 2265 2266 float rounded = 0; 2267 switch (rmode) { 2268 case RNE: { // Round to Nearest, tiest to Even 2269 rounded = floorf(input_val); 2270 float error = input_val - rounded; 2271 2272 // Take care of correctly handling the range [-0.5, -0.0], which must 2273 // yield -0.0. 2274 if ((-0.5 <= input_val) && (input_val < 0.0)) { 2275 rounded = -0.0; 2276 2277 // If the error is greater than 0.5, or is equal to 0.5 and the integer 2278 // result is odd, round up. 2279 } else if ((error > 0.5) || 2280 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) { 2281 rounded++; 2282 } 2283 break; 2284 } 2285 case RTZ: // Round towards Zero 2286 rounded = std::truncf(input_val); 2287 break; 2288 case RDN: // Round Down (towards -infinity) 2289 rounded = floorf(input_val); 2290 break; 2291 case RUP: // Round Up (towards +infinity) 2292 rounded = ceilf(input_val); 2293 break; 2294 case RMM: // Round to Nearest, tiest to Max Magnitude 2295 rounded = std::roundf(input_val); 2296 break; 2297 default: 2298 UNREACHABLE(); 2299 } 2300 2301 return rounded; 2302 } 2303 2304 double Simulator::RoundF2FHelper(double input_val, int rmode) { 2305 if (rmode == DYN) rmode = get_dynamic_rounding_mode(); 2306 2307 double rounded = 0; 2308 switch (rmode) { 2309 case RNE: { // Round to Nearest, tiest to Even 2310 rounded = std::floor(input_val); 2311 double error = input_val - rounded; 2312 2313 // Take care of correctly handling the range [-0.5, -0.0], which must 2314 // yield -0.0. 2315 if ((-0.5 <= input_val) && (input_val < 0.0)) { 2316 rounded = -0.0; 2317 2318 // If the error is greater than 0.5, or is equal to 0.5 and the integer 2319 // result is odd, round up. 2320 } else if ((error > 0.5) || 2321 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) { 2322 rounded++; 2323 } 2324 break; 2325 } 2326 case RTZ: // Round towards Zero 2327 rounded = std::trunc(input_val); 2328 break; 2329 case RDN: // Round Down (towards -infinity) 2330 rounded = std::floor(input_val); 2331 break; 2332 case RUP: // Round Up (towards +infinity) 2333 rounded = std::ceil(input_val); 2334 break; 2335 case RMM: // Round to Nearest, tiest to Max Magnitude 2336 rounded = std::round(input_val); 2337 break; 2338 default: 2339 UNREACHABLE(); 2340 } 2341 return rounded; 2342 } 2343 2344 // convert rounded floating-point to integer types, handle input values that 2345 // are out-of-range, underflow, or NaN, and set appropriate fflags 2346 template <typename I_TYPE, typename F_TYPE> 2347 I_TYPE Simulator::RoundF2IHelper(F_TYPE original, int rmode) { 2348 MOZ_ASSERT(std::is_integral<I_TYPE>::value); 2349 2350 MOZ_ASSERT((std::is_same<F_TYPE, float>::value || 2351 std::is_same<F_TYPE, double>::value)); 2352 2353 I_TYPE max_i = std::numeric_limits<I_TYPE>::max(); 2354 I_TYPE min_i = std::numeric_limits<I_TYPE>::min(); 2355 2356 if (!std::isfinite(original)) { 2357 set_fflags(kInvalidOperation); 2358 if (std::isnan(original) || 2359 original == std::numeric_limits<F_TYPE>::infinity()) { 2360 return max_i; 2361 } else { 2362 MOZ_ASSERT(original == -std::numeric_limits<F_TYPE>::infinity()); 2363 return min_i; 2364 } 2365 } 2366 2367 F_TYPE rounded = RoundF2FHelper(original, rmode); 2368 if (original != rounded) set_fflags(kInexact); 2369 2370 if (!std::isfinite(rounded)) { 2371 set_fflags(kInvalidOperation); 2372 if (std::isnan(rounded) || 2373 rounded == std::numeric_limits<F_TYPE>::infinity()) { 2374 return max_i; 2375 } else { 2376 MOZ_ASSERT(rounded == -std::numeric_limits<F_TYPE>::infinity()); 2377 return min_i; 2378 } 2379 } 2380 2381 // Since integer max values are either all 1s (for unsigned) or all 1s 2382 // except for sign-bit (for signed), they cannot be represented precisely in 2383 // floating point, in order to precisely tell whether the rounded floating 2384 // point is within the max range, we compare against (max_i+1) which would 2385 // have a single 1 w/ many trailing zeros 2386 float max_i_plus_1 = 2387 std::is_same<uint64_t, I_TYPE>::value 2388 ? 0x1p64f // uint64_t::max + 1 cannot be represented in integers, 2389 // so use its float representation directly 2390 : static_cast<float>(static_cast<uint64_t>(max_i) + 1); 2391 if (rounded >= max_i_plus_1) { 2392 set_fflags(kOverflow | kInvalidOperation); 2393 return max_i; 2394 } 2395 2396 // Since min_i (either 0 for unsigned, or for signed) is represented 2397 // precisely in floating-point, comparing rounded directly against min_i 2398 if (rounded <= min_i) { 2399 if (rounded < min_i) set_fflags(kOverflow | kInvalidOperation); 2400 return min_i; 2401 } 2402 2403 F_TYPE underflow_fval = 2404 std::is_same<F_TYPE, float>::value ? FLT_MIN : DBL_MIN; 2405 if (rounded < underflow_fval && rounded > -underflow_fval && rounded != 0) { 2406 set_fflags(kUnderflow); 2407 } 2408 2409 return static_cast<I_TYPE>(rounded); 2410 } 2411 2412 template <typename T> 2413 static int64_t FclassHelper(T value) { 2414 switch (std::fpclassify(value)) { 2415 case FP_INFINITE: 2416 return (std::signbit(value) ? kNegativeInfinity : kPositiveInfinity); 2417 case FP_NAN: 2418 return (isSnan(value) ? kSignalingNaN : kQuietNaN); 2419 case FP_NORMAL: 2420 return (std::signbit(value) ? kNegativeNormalNumber 2421 : kPositiveNormalNumber); 2422 case FP_SUBNORMAL: 2423 return (std::signbit(value) ? kNegativeSubnormalNumber 2424 : kPositiveSubnormalNumber); 2425 case FP_ZERO: 2426 return (std::signbit(value) ? kNegativeZero : kPositiveZero); 2427 default: 2428 UNREACHABLE(); 2429 } 2430 UNREACHABLE(); 2431 return FP_ZERO; 2432 } 2433 2434 template <typename T> 2435 bool Simulator::CompareFHelper(T input1, T input2, FPUCondition cc) { 2436 MOZ_ASSERT(std::is_floating_point<T>::value); 2437 bool result = false; 2438 switch (cc) { 2439 case LT: 2440 case LE: 2441 // FLT, FLE are signaling compares 2442 if (std::isnan(input1) || std::isnan(input2)) { 2443 set_fflags(kInvalidOperation); 2444 result = false; 2445 } else { 2446 result = (cc == LT) ? (input1 < input2) : (input1 <= input2); 2447 } 2448 break; 2449 case EQ: 2450 if (std::numeric_limits<T>::signaling_NaN() == input1 || 2451 std::numeric_limits<T>::signaling_NaN() == input2) { 2452 set_fflags(kInvalidOperation); 2453 } 2454 if (std::isnan(input1) || std::isnan(input2)) { 2455 result = false; 2456 } else { 2457 result = (input1 == input2); 2458 } 2459 break; 2460 case NE: 2461 if (std::numeric_limits<T>::signaling_NaN() == input1 || 2462 std::numeric_limits<T>::signaling_NaN() == input2) { 2463 set_fflags(kInvalidOperation); 2464 } 2465 if (std::isnan(input1) || std::isnan(input2)) { 2466 result = true; 2467 } else { 2468 result = (input1 != input2); 2469 } 2470 break; 2471 default: 2472 UNREACHABLE(); 2473 } 2474 return result; 2475 } 2476 2477 template <typename T> 2478 static inline bool is_invalid_fmul(T src1, T src2) { 2479 return (isinf(src1) && src2 == static_cast<T>(0.0)) || 2480 (src1 == static_cast<T>(0.0) && isinf(src2)); 2481 } 2482 2483 template <typename T> 2484 static inline bool is_invalid_fadd(T src1, T src2) { 2485 return (isinf(src1) && isinf(src2) && 2486 std::signbit(src1) != std::signbit(src2)); 2487 } 2488 2489 template <typename T> 2490 static inline bool is_invalid_fsub(T src1, T src2) { 2491 return (isinf(src1) && isinf(src2) && 2492 std::signbit(src1) == std::signbit(src2)); 2493 } 2494 2495 template <typename T> 2496 static inline bool is_invalid_fdiv(T src1, T src2) { 2497 return ((src1 == 0 && src2 == 0) || (isinf(src1) && isinf(src2))); 2498 } 2499 2500 template <typename T> 2501 static inline bool is_invalid_fsqrt(T src1) { 2502 return (src1 < 0); 2503 } 2504 2505 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) { 2506 if ((addr & 3) == 0) { 2507 if (handleWasmSegFault(addr, 4)) { 2508 return -1; 2509 } 2510 2511 volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr); 2512 int32_t value = *ptr; 2513 lastLLValue_ = value; 2514 LLAddr_ = addr; 2515 // Note that any memory write or "external" interrupt should reset this 2516 // value to false. 2517 LLBit_ = true; 2518 return value; 2519 } 2520 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2521 reinterpret_cast<intptr_t>(instr)); 2522 MOZ_CRASH(); 2523 return 0; 2524 } 2525 2526 int Simulator::storeConditionalW(uint64_t addr, int value, 2527 SimInstruction* instr) { 2528 // Correct behavior in this case, as defined by architecture, is to just 2529 // return 0, but there is no point at allowing that. It is certainly an 2530 // indicator of a bug. 2531 if (addr != LLAddr_) { 2532 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR 2533 ", expected: 0x%016" PRIxPTR "\n", 2534 addr, reinterpret_cast<intptr_t>(instr), LLAddr_); 2535 MOZ_CRASH(); 2536 } 2537 2538 if ((addr & 3) == 0) { 2539 SharedMem<int32_t*> ptr = 2540 SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); 2541 2542 if (!LLBit_) { 2543 return 1; 2544 } 2545 2546 LLBit_ = false; 2547 LLAddr_ = 0; 2548 int32_t expected = int32_t(lastLLValue_); 2549 int32_t old = 2550 AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value)); 2551 return (old == expected) ? 0 : 1; 2552 } 2553 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2554 reinterpret_cast<intptr_t>(instr)); 2555 MOZ_CRASH(); 2556 return 0; 2557 } 2558 2559 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) { 2560 if ((addr & kPointerAlignmentMask) == 0) { 2561 if (handleWasmSegFault(addr, 8)) { 2562 return -1; 2563 } 2564 2565 volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr); 2566 int64_t value = *ptr; 2567 lastLLValue_ = value; 2568 LLAddr_ = addr; 2569 // Note that any memory write or "external" interrupt should reset this 2570 // value to false. 2571 LLBit_ = true; 2572 return value; 2573 } 2574 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2575 reinterpret_cast<intptr_t>(instr)); 2576 MOZ_CRASH(); 2577 return 0; 2578 } 2579 2580 int Simulator::storeConditionalD(uint64_t addr, int64_t value, 2581 SimInstruction* instr) { 2582 // Correct behavior in this case, as defined by architecture, is to just 2583 // return 0, but there is no point at allowing that. It is certainly an 2584 // indicator of a bug. 2585 if (addr != LLAddr_) { 2586 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR 2587 ", expected: 0x%016" PRIxPTR "\n", 2588 addr, reinterpret_cast<intptr_t>(instr), LLAddr_); 2589 MOZ_CRASH(); 2590 } 2591 2592 if ((addr & kPointerAlignmentMask) == 0) { 2593 SharedMem<int64_t*> ptr = 2594 SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr)); 2595 2596 if (!LLBit_) { 2597 return 1; 2598 } 2599 2600 LLBit_ = false; 2601 LLAddr_ = 0; 2602 int64_t expected = lastLLValue_; 2603 int64_t old = 2604 AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value)); 2605 return (old == expected) ? 0 : 1; 2606 } 2607 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2608 reinterpret_cast<intptr_t>(instr)); 2609 MOZ_CRASH(); 2610 return 0; 2611 } 2612 2613 void Simulator::DecodeRVRAType() { 2614 // TODO(riscv): Add macro for RISCV A extension 2615 // Special handling for A extension instructions because it uses func5 2616 // For all A extension instruction, V8 simulator is pure sequential. No 2617 // Memory address lock or other synchronizaiton behaviors. 2618 switch (instr_.InstructionBits() & kRATypeMask) { 2619 case RO_LR_W: { 2620 sreg_t addr = rs1(); 2621 set_rd(loadLinkedW(addr, &instr_)); 2622 TraceLr(addr, getRegister(rd_reg()), getRegister(rd_reg())); 2623 break; 2624 } 2625 case RO_SC_W: { 2626 sreg_t addr = rs1(); 2627 auto value = static_cast<int32_t>(rs2()); 2628 auto result = 2629 storeConditionalW(addr, static_cast<int32_t>(rs2()), &instr_); 2630 set_rd(result); 2631 if (!result) { 2632 TraceSc(addr, value); 2633 } 2634 break; 2635 } 2636 case RO_AMOSWAP_W: { 2637 if ((rs1() & 0x3) != 0) { 2638 DieOrDebug(); 2639 } 2640 set_rd(sext32(amo<uint32_t>( 2641 rs1(), [&](uint32_t lhs) { return (uint32_t)rs2(); }, instr_.instr(), 2642 WORD))); 2643 break; 2644 } 2645 case RO_AMOADD_W: { 2646 if ((rs1() & 0x3) != 0) { 2647 DieOrDebug(); 2648 } 2649 set_rd(sext32(amo<uint32_t>( 2650 rs1(), [&](uint32_t lhs) { return lhs + (uint32_t)rs2(); }, 2651 instr_.instr(), WORD))); 2652 break; 2653 } 2654 case RO_AMOXOR_W: { 2655 if ((rs1() & 0x3) != 0) { 2656 DieOrDebug(); 2657 } 2658 set_rd(sext32(amo<uint32_t>( 2659 rs1(), [&](uint32_t lhs) { return lhs ^ (uint32_t)rs2(); }, 2660 instr_.instr(), WORD))); 2661 break; 2662 } 2663 case RO_AMOAND_W: { 2664 if ((rs1() & 0x3) != 0) { 2665 DieOrDebug(); 2666 } 2667 set_rd(sext32(amo<uint32_t>( 2668 rs1(), [&](uint32_t lhs) { return lhs & (uint32_t)rs2(); }, 2669 instr_.instr(), WORD))); 2670 break; 2671 } 2672 case RO_AMOOR_W: { 2673 if ((rs1() & 0x3) != 0) { 2674 DieOrDebug(); 2675 } 2676 set_rd(sext32(amo<uint32_t>( 2677 rs1(), [&](uint32_t lhs) { return lhs | (uint32_t)rs2(); }, 2678 instr_.instr(), WORD))); 2679 break; 2680 } 2681 case RO_AMOMIN_W: { 2682 if ((rs1() & 0x3) != 0) { 2683 DieOrDebug(); 2684 } 2685 set_rd(sext32(amo<int32_t>( 2686 rs1(), [&](int32_t lhs) { return std::min(lhs, (int32_t)rs2()); }, 2687 instr_.instr(), WORD))); 2688 break; 2689 } 2690 case RO_AMOMAX_W: { 2691 if ((rs1() & 0x3) != 0) { 2692 DieOrDebug(); 2693 } 2694 set_rd(sext32(amo<int32_t>( 2695 rs1(), [&](int32_t lhs) { return std::max(lhs, (int32_t)rs2()); }, 2696 instr_.instr(), WORD))); 2697 break; 2698 } 2699 case RO_AMOMINU_W: { 2700 if ((rs1() & 0x3) != 0) { 2701 DieOrDebug(); 2702 } 2703 set_rd(sext32(amo<uint32_t>( 2704 rs1(), [&](uint32_t lhs) { return std::min(lhs, (uint32_t)rs2()); }, 2705 instr_.instr(), WORD))); 2706 break; 2707 } 2708 case RO_AMOMAXU_W: { 2709 if ((rs1() & 0x3) != 0) { 2710 DieOrDebug(); 2711 } 2712 set_rd(sext32(amo<uint32_t>( 2713 rs1(), [&](uint32_t lhs) { return std::max(lhs, (uint32_t)rs2()); }, 2714 instr_.instr(), WORD))); 2715 break; 2716 } 2717 # ifdef JS_CODEGEN_RISCV64 2718 case RO_LR_D: { 2719 sreg_t addr = rs1(); 2720 set_rd(loadLinkedD(addr, &instr_)); 2721 TraceLr(addr, getRegister(rd_reg()), getRegister(rd_reg())); 2722 break; 2723 } 2724 case RO_SC_D: { 2725 sreg_t addr = rs1(); 2726 auto value = static_cast<int64_t>(rs2()); 2727 auto result = 2728 storeConditionalD(addr, static_cast<int64_t>(rs2()), &instr_); 2729 set_rd(result); 2730 if (!result) { 2731 TraceSc(addr, value); 2732 } 2733 break; 2734 } 2735 case RO_AMOSWAP_D: { 2736 set_rd(amo<int64_t>( 2737 rs1(), [&](int64_t lhs) { return rs2(); }, instr_.instr(), DWORD)); 2738 break; 2739 } 2740 case RO_AMOADD_D: { 2741 set_rd(amo<int64_t>( 2742 rs1(), [&](int64_t lhs) { return lhs + rs2(); }, instr_.instr(), 2743 DWORD)); 2744 break; 2745 } 2746 case RO_AMOXOR_D: { 2747 set_rd(amo<int64_t>( 2748 rs1(), [&](int64_t lhs) { return lhs ^ rs2(); }, instr_.instr(), 2749 DWORD)); 2750 break; 2751 } 2752 case RO_AMOAND_D: { 2753 set_rd(amo<int64_t>( 2754 rs1(), [&](int64_t lhs) { return lhs & rs2(); }, instr_.instr(), 2755 DWORD)); 2756 break; 2757 } 2758 case RO_AMOOR_D: { 2759 set_rd(amo<int64_t>( 2760 rs1(), [&](int64_t lhs) { return lhs | rs2(); }, instr_.instr(), 2761 DWORD)); 2762 break; 2763 } 2764 case RO_AMOMIN_D: { 2765 set_rd(amo<int64_t>( 2766 rs1(), [&](int64_t lhs) { return std::min(lhs, rs2()); }, 2767 instr_.instr(), DWORD)); 2768 break; 2769 } 2770 case RO_AMOMAX_D: { 2771 set_rd(amo<int64_t>( 2772 rs1(), [&](int64_t lhs) { return std::max(lhs, rs2()); }, 2773 instr_.instr(), DWORD)); 2774 break; 2775 } 2776 case RO_AMOMINU_D: { 2777 set_rd(amo<uint64_t>( 2778 rs1(), [&](uint64_t lhs) { return std::min(lhs, (uint64_t)rs2()); }, 2779 instr_.instr(), DWORD)); 2780 break; 2781 } 2782 case RO_AMOMAXU_D: { 2783 set_rd(amo<uint64_t>( 2784 rs1(), [&](uint64_t lhs) { return std::max(lhs, (uint64_t)rs2()); }, 2785 instr_.instr(), DWORD)); 2786 break; 2787 } 2788 # endif /*JS_CODEGEN_RISCV64*/ 2789 // TODO(riscv): End Add macro for RISCV A extension 2790 default: { 2791 UNSUPPORTED(); 2792 } 2793 } 2794 } 2795 2796 void Simulator::DecodeRVRFPType() { 2797 // OP_FP instructions (F/D) uses func7 first. Some further uses func3 and 2798 // rs2() 2799 2800 // kRATypeMask is only for func7 2801 switch (instr_.InstructionBits() & kRFPTypeMask) { 2802 // TODO(riscv): Add macro for RISCV F extension 2803 case RO_FADD_S: { 2804 // TODO(riscv): use rm value (round mode) 2805 auto fn = [this](float frs1, float frs2) { 2806 if (is_invalid_fadd(frs1, frs2)) { 2807 this->set_fflags(kInvalidOperation); 2808 return std::numeric_limits<float>::quiet_NaN(); 2809 } else { 2810 return frs1 + frs2; 2811 } 2812 }; 2813 set_frd(CanonicalizeFPUOp2<float>(fn)); 2814 break; 2815 } 2816 case RO_FSUB_S: { 2817 // TODO(riscv): use rm value (round mode) 2818 auto fn = [this](float frs1, float frs2) { 2819 if (is_invalid_fsub(frs1, frs2)) { 2820 this->set_fflags(kInvalidOperation); 2821 return std::numeric_limits<float>::quiet_NaN(); 2822 } else { 2823 return frs1 - frs2; 2824 } 2825 }; 2826 set_frd(CanonicalizeFPUOp2<float>(fn)); 2827 break; 2828 } 2829 case RO_FMUL_S: { 2830 // TODO(riscv): use rm value (round mode) 2831 auto fn = [this](float frs1, float frs2) { 2832 if (is_invalid_fmul(frs1, frs2)) { 2833 this->set_fflags(kInvalidOperation); 2834 return std::numeric_limits<float>::quiet_NaN(); 2835 } else { 2836 return frs1 * frs2; 2837 } 2838 }; 2839 set_frd(CanonicalizeFPUOp2<float>(fn)); 2840 break; 2841 } 2842 case RO_FDIV_S: { 2843 // TODO(riscv): use rm value (round mode) 2844 auto fn = [this](float frs1, float frs2) { 2845 if (is_invalid_fdiv(frs1, frs2)) { 2846 this->set_fflags(kInvalidOperation); 2847 return std::numeric_limits<float>::quiet_NaN(); 2848 } else if (frs2 == 0.0f) { 2849 this->set_fflags(kDivideByZero); 2850 return (std::signbit(frs1) == std::signbit(frs2) 2851 ? std::numeric_limits<float>::infinity() 2852 : -std::numeric_limits<float>::infinity()); 2853 } else { 2854 return frs1 / frs2; 2855 } 2856 }; 2857 set_frd(CanonicalizeFPUOp2<float>(fn)); 2858 break; 2859 } 2860 case RO_FSQRT_S: { 2861 if (instr_.Rs2Value() == 0b00000) { 2862 // TODO(riscv): use rm value (round mode) 2863 auto fn = [this](float frs) { 2864 if (is_invalid_fsqrt(frs)) { 2865 this->set_fflags(kInvalidOperation); 2866 return std::numeric_limits<float>::quiet_NaN(); 2867 } else { 2868 return std::sqrt(frs); 2869 } 2870 }; 2871 set_frd(CanonicalizeFPUOp1<float>(fn)); 2872 } else { 2873 UNSUPPORTED(); 2874 } 2875 break; 2876 } 2877 case RO_FSGNJ_S: { // RO_FSGNJN_S RO_FSQNJX_S 2878 switch (instr_.Funct3Value()) { 2879 case 0b000: { // RO_FSGNJ_S 2880 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, false)); 2881 break; 2882 } 2883 case 0b001: { // RO_FSGNJN_S 2884 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), true, false)); 2885 break; 2886 } 2887 case 0b010: { // RO_FSQNJX_S 2888 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, true)); 2889 break; 2890 } 2891 default: { 2892 UNSUPPORTED(); 2893 } 2894 } 2895 break; 2896 } 2897 case RO_FMIN_S: { // RO_FMAX_S 2898 switch (instr_.Funct3Value()) { 2899 case 0b000: { // RO_FMIN_S 2900 set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMin)); 2901 break; 2902 } 2903 case 0b001: { // RO_FMAX_S 2904 set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMax)); 2905 break; 2906 } 2907 default: { 2908 UNSUPPORTED(); 2909 } 2910 } 2911 break; 2912 } 2913 case RO_FCVT_W_S: { // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S 2914 float original_val = frs1(); 2915 switch (instr_.Rs2Value()) { 2916 case 0b00000: { // RO_FCVT_W_S 2917 set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode())); 2918 break; 2919 } 2920 case 0b00001: { // RO_FCVT_WU_S 2921 set_rd(sext32( 2922 RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode()))); 2923 break; 2924 } 2925 # ifdef JS_CODEGEN_RISCV64 2926 case 0b00010: { // RO_FCVT_L_S 2927 set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode())); 2928 break; 2929 } 2930 case 0b00011: { // RO_FCVT_LU_S 2931 set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode())); 2932 break; 2933 } 2934 # endif /* JS_CODEGEN_RISCV64 */ 2935 default: { 2936 UNSUPPORTED(); 2937 } 2938 } 2939 break; 2940 } 2941 case RO_FMV: { // RO_FCLASS_S 2942 switch (instr_.Funct3Value()) { 2943 case 0b000: { 2944 if (instr_.Rs2Value() == 0b00000) { 2945 // RO_FMV_X_W 2946 set_rd(sext32(getFpuRegister(rs1_reg()))); 2947 } else { 2948 UNSUPPORTED(); 2949 } 2950 break; 2951 } 2952 case 0b001: { // RO_FCLASS_S 2953 set_rd(FclassHelper(frs1())); 2954 break; 2955 } 2956 default: { 2957 UNSUPPORTED(); 2958 } 2959 } 2960 break; 2961 } 2962 case RO_FLE_S: { // RO_FEQ_S RO_FLT_S RO_FLE_S 2963 switch (instr_.Funct3Value()) { 2964 case 0b010: { // RO_FEQ_S 2965 set_rd(CompareFHelper(frs1(), frs2(), EQ)); 2966 break; 2967 } 2968 case 0b001: { // RO_FLT_S 2969 set_rd(CompareFHelper(frs1(), frs2(), LT)); 2970 break; 2971 } 2972 case 0b000: { // RO_FLE_S 2973 set_rd(CompareFHelper(frs1(), frs2(), LE)); 2974 break; 2975 } 2976 default: { 2977 UNSUPPORTED(); 2978 } 2979 } 2980 break; 2981 } 2982 case RO_FCVT_S_W: { // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU 2983 switch (instr_.Rs2Value()) { 2984 case 0b00000: { // RO_FCVT_S_W 2985 set_frd(static_cast<float>((int32_t)rs1())); 2986 break; 2987 } 2988 case 0b00001: { // RO_FCVT_S_WU 2989 set_frd(static_cast<float>((uint32_t)rs1())); 2990 break; 2991 } 2992 # ifdef JS_CODEGEN_RISCV64 2993 case 0b00010: { // RO_FCVT_S_L 2994 set_frd(static_cast<float>((int64_t)rs1())); 2995 break; 2996 } 2997 case 0b00011: { // RO_FCVT_S_LU 2998 set_frd(static_cast<float>((uint64_t)rs1())); 2999 break; 3000 } 3001 # endif /* JS_CODEGEN_RISCV64 */ 3002 default: { 3003 UNSUPPORTED(); 3004 } 3005 } 3006 break; 3007 } 3008 case RO_FMV_W_X: { 3009 if (instr_.Funct3Value() == 0b000) { 3010 // since FMV preserves source bit-pattern, no need to canonize 3011 Float32 result = Float32::FromBits((uint32_t)rs1()); 3012 set_frd(result); 3013 } else { 3014 UNSUPPORTED(); 3015 } 3016 break; 3017 } 3018 // TODO(riscv): Add macro for RISCV D extension 3019 case RO_FADD_D: { 3020 // TODO(riscv): use rm value (round mode) 3021 auto fn = [this](double drs1, double drs2) { 3022 if (is_invalid_fadd(drs1, drs2)) { 3023 this->set_fflags(kInvalidOperation); 3024 return std::numeric_limits<double>::quiet_NaN(); 3025 } else { 3026 return drs1 + drs2; 3027 } 3028 }; 3029 set_drd(CanonicalizeFPUOp2<double>(fn)); 3030 break; 3031 } 3032 case RO_FSUB_D: { 3033 // TODO(riscv): use rm value (round mode) 3034 auto fn = [this](double drs1, double drs2) { 3035 if (is_invalid_fsub(drs1, drs2)) { 3036 this->set_fflags(kInvalidOperation); 3037 return std::numeric_limits<double>::quiet_NaN(); 3038 } else { 3039 return drs1 - drs2; 3040 } 3041 }; 3042 set_drd(CanonicalizeFPUOp2<double>(fn)); 3043 break; 3044 } 3045 case RO_FMUL_D: { 3046 // TODO(riscv): use rm value (round mode) 3047 auto fn = [this](double drs1, double drs2) { 3048 if (is_invalid_fmul(drs1, drs2)) { 3049 this->set_fflags(kInvalidOperation); 3050 return std::numeric_limits<double>::quiet_NaN(); 3051 } else { 3052 return drs1 * drs2; 3053 } 3054 }; 3055 set_drd(CanonicalizeFPUOp2<double>(fn)); 3056 break; 3057 } 3058 case RO_FDIV_D: { 3059 // TODO(riscv): use rm value (round mode) 3060 auto fn = [this](double drs1, double drs2) { 3061 if (is_invalid_fdiv(drs1, drs2)) { 3062 this->set_fflags(kInvalidOperation); 3063 return std::numeric_limits<double>::quiet_NaN(); 3064 } else if (drs2 == 0.0) { 3065 this->set_fflags(kDivideByZero); 3066 return (std::signbit(drs1) == std::signbit(drs2) 3067 ? std::numeric_limits<double>::infinity() 3068 : -std::numeric_limits<double>::infinity()); 3069 } else { 3070 return drs1 / drs2; 3071 } 3072 }; 3073 set_drd(CanonicalizeFPUOp2<double>(fn)); 3074 break; 3075 } 3076 case RO_FSQRT_D: { 3077 if (instr_.Rs2Value() == 0b00000) { 3078 // TODO(riscv): use rm value (round mode) 3079 auto fn = [this](double drs) { 3080 if (is_invalid_fsqrt(drs)) { 3081 this->set_fflags(kInvalidOperation); 3082 return std::numeric_limits<double>::quiet_NaN(); 3083 } else { 3084 return std::sqrt(drs); 3085 } 3086 }; 3087 set_drd(CanonicalizeFPUOp1<double>(fn)); 3088 } else { 3089 UNSUPPORTED(); 3090 } 3091 break; 3092 } 3093 case RO_FSGNJ_D: { // RO_FSGNJN_D RO_FSQNJX_D 3094 switch (instr_.Funct3Value()) { 3095 case 0b000: { // RO_FSGNJ_D 3096 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, false)); 3097 break; 3098 } 3099 case 0b001: { // RO_FSGNJN_D 3100 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), true, false)); 3101 break; 3102 } 3103 case 0b010: { // RO_FSQNJX_D 3104 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, true)); 3105 break; 3106 } 3107 default: { 3108 UNSUPPORTED(); 3109 } 3110 } 3111 break; 3112 } 3113 case RO_FMIN_D: { // RO_FMAX_D 3114 switch (instr_.Funct3Value()) { 3115 case 0b000: { // RO_FMIN_D 3116 set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMin)); 3117 break; 3118 } 3119 case 0b001: { // RO_FMAX_D 3120 set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMax)); 3121 break; 3122 } 3123 default: { 3124 UNSUPPORTED(); 3125 } 3126 } 3127 break; 3128 } 3129 case (RO_FCVT_S_D & kRFPTypeMask): { 3130 if (instr_.Rs2Value() == 0b00001) { 3131 auto fn = [](double drs) { return static_cast<float>(drs); }; 3132 set_frd(CanonicalizeDoubleToFloatOperation(fn)); 3133 } else { 3134 UNSUPPORTED(); 3135 } 3136 break; 3137 } 3138 case RO_FCVT_D_S: { 3139 if (instr_.Rs2Value() == 0b00000) { 3140 auto fn = [](float frs) { return static_cast<double>(frs); }; 3141 set_drd(CanonicalizeFloatToDoubleOperation(fn)); 3142 } else { 3143 UNSUPPORTED(); 3144 } 3145 break; 3146 } 3147 case RO_FLE_D: { // RO_FEQ_D RO_FLT_D RO_FLE_D 3148 switch (instr_.Funct3Value()) { 3149 case 0b010: { // RO_FEQ_S 3150 set_rd(CompareFHelper(drs1(), drs2(), EQ)); 3151 break; 3152 } 3153 case 0b001: { // RO_FLT_D 3154 set_rd(CompareFHelper(drs1(), drs2(), LT)); 3155 break; 3156 } 3157 case 0b000: { // RO_FLE_D 3158 set_rd(CompareFHelper(drs1(), drs2(), LE)); 3159 break; 3160 } 3161 default: { 3162 UNSUPPORTED(); 3163 } 3164 } 3165 break; 3166 } 3167 case (RO_FCLASS_D & kRFPTypeMask): { // RO_FCLASS_D , 64D RO_FMV_X_D 3168 if (instr_.Rs2Value() != 0b00000) { 3169 UNSUPPORTED(); 3170 } 3171 switch (instr_.Funct3Value()) { 3172 case 0b001: { // RO_FCLASS_D 3173 set_rd(FclassHelper(drs1())); 3174 break; 3175 } 3176 # ifdef JS_CODEGEN_RISCV64 3177 case 0b000: { // RO_FMV_X_D 3178 set_rd(bit_cast<int64_t>(drs1())); 3179 break; 3180 } 3181 # endif /* JS_CODEGEN_RISCV64 */ 3182 default: { 3183 UNSUPPORTED(); 3184 } 3185 } 3186 break; 3187 } 3188 case RO_FCVT_W_D: { // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D 3189 double original_val = drs1(); 3190 switch (instr_.Rs2Value()) { 3191 case 0b00000: { // RO_FCVT_W_D 3192 set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode())); 3193 break; 3194 } 3195 case 0b00001: { // RO_FCVT_WU_D 3196 set_rd(sext32( 3197 RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode()))); 3198 break; 3199 } 3200 # ifdef JS_CODEGEN_RISCV64 3201 case 0b00010: { // RO_FCVT_L_D 3202 set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode())); 3203 break; 3204 } 3205 case 0b00011: { // RO_FCVT_LU_D 3206 set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode())); 3207 break; 3208 } 3209 # endif /* JS_CODEGEN_RISCV64 */ 3210 default: { 3211 UNSUPPORTED(); 3212 } 3213 } 3214 break; 3215 } 3216 case RO_FCVT_D_W: { // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU 3217 switch (instr_.Rs2Value()) { 3218 case 0b00000: { // RO_FCVT_D_W 3219 set_drd((int32_t)rs1()); 3220 break; 3221 } 3222 case 0b00001: { // RO_FCVT_D_WU 3223 set_drd((uint32_t)rs1()); 3224 break; 3225 } 3226 # ifdef JS_CODEGEN_RISCV64 3227 case 0b00010: { // RO_FCVT_D_L 3228 set_drd((int64_t)rs1()); 3229 break; 3230 } 3231 case 0b00011: { // RO_FCVT_D_LU 3232 set_drd((uint64_t)rs1()); 3233 break; 3234 } 3235 # endif /* JS_CODEGEN_RISCV64 */ 3236 default: { 3237 UNSUPPORTED(); 3238 } 3239 } 3240 break; 3241 } 3242 # ifdef JS_CODEGEN_RISCV64 3243 case RO_FMV_D_X: { 3244 if (instr_.Funct3Value() == 0b000 && instr_.Rs2Value() == 0b00000) { 3245 // Since FMV preserves source bit-pattern, no need to canonize 3246 set_drd(bit_cast<double>(rs1())); 3247 } else { 3248 UNSUPPORTED(); 3249 } 3250 break; 3251 } 3252 # endif /* JS_CODEGEN_RISCV64 */ 3253 default: { 3254 UNSUPPORTED(); 3255 } 3256 } 3257 } 3258 3259 void Simulator::DecodeRVR4Type() { 3260 switch (instr_.InstructionBits() & kR4TypeMask) { 3261 // TODO(riscv): use F Extension macro block 3262 case RO_FMADD_S: { 3263 // TODO(riscv): use rm value (round mode) 3264 auto fn = [this](float frs1, float frs2, float frs3) { 3265 if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) { 3266 this->set_fflags(kInvalidOperation); 3267 return std::numeric_limits<float>::quiet_NaN(); 3268 } else { 3269 return std::fma(frs1, frs2, frs3); 3270 } 3271 }; 3272 set_frd(CanonicalizeFPUOp3<float>(fn)); 3273 break; 3274 } 3275 case RO_FMSUB_S: { 3276 // TODO(riscv): use rm value (round mode) 3277 auto fn = [this](float frs1, float frs2, float frs3) { 3278 if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs1 * frs2, frs3)) { 3279 this->set_fflags(kInvalidOperation); 3280 return std::numeric_limits<float>::quiet_NaN(); 3281 } else { 3282 return std::fma(frs1, frs2, -frs3); 3283 } 3284 }; 3285 set_frd(CanonicalizeFPUOp3<float>(fn)); 3286 break; 3287 } 3288 case RO_FNMSUB_S: { 3289 // TODO(riscv): use rm value (round mode) 3290 auto fn = [this](float frs1, float frs2, float frs3) { 3291 if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs3, frs1 * frs2)) { 3292 this->set_fflags(kInvalidOperation); 3293 return std::numeric_limits<float>::quiet_NaN(); 3294 } else { 3295 return -std::fma(frs1, frs2, -frs3); 3296 } 3297 }; 3298 set_frd(CanonicalizeFPUOp3<float>(fn)); 3299 break; 3300 } 3301 case RO_FNMADD_S: { 3302 // TODO(riscv): use rm value (round mode) 3303 auto fn = [this](float frs1, float frs2, float frs3) { 3304 if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) { 3305 this->set_fflags(kInvalidOperation); 3306 return std::numeric_limits<float>::quiet_NaN(); 3307 } else { 3308 return -std::fma(frs1, frs2, frs3); 3309 } 3310 }; 3311 set_frd(CanonicalizeFPUOp3<float>(fn)); 3312 break; 3313 } 3314 // TODO(riscv): use F Extension macro block 3315 case RO_FMADD_D: { 3316 // TODO(riscv): use rm value (round mode) 3317 auto fn = [this](double drs1, double drs2, double drs3) { 3318 if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) { 3319 this->set_fflags(kInvalidOperation); 3320 return std::numeric_limits<double>::quiet_NaN(); 3321 } else { 3322 return std::fma(drs1, drs2, drs3); 3323 } 3324 }; 3325 set_drd(CanonicalizeFPUOp3<double>(fn)); 3326 break; 3327 } 3328 case RO_FMSUB_D: { 3329 // TODO(riscv): use rm value (round mode) 3330 auto fn = [this](double drs1, double drs2, double drs3) { 3331 if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs1 * drs2, drs3)) { 3332 this->set_fflags(kInvalidOperation); 3333 return std::numeric_limits<double>::quiet_NaN(); 3334 } else { 3335 return std::fma(drs1, drs2, -drs3); 3336 } 3337 }; 3338 set_drd(CanonicalizeFPUOp3<double>(fn)); 3339 break; 3340 } 3341 case RO_FNMSUB_D: { 3342 // TODO(riscv): use rm value (round mode) 3343 auto fn = [this](double drs1, double drs2, double drs3) { 3344 if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs3, drs1 * drs2)) { 3345 this->set_fflags(kInvalidOperation); 3346 return std::numeric_limits<double>::quiet_NaN(); 3347 } else { 3348 return -std::fma(drs1, drs2, -drs3); 3349 } 3350 }; 3351 set_drd(CanonicalizeFPUOp3<double>(fn)); 3352 break; 3353 } 3354 case RO_FNMADD_D: { 3355 // TODO(riscv): use rm value (round mode) 3356 auto fn = [this](double drs1, double drs2, double drs3) { 3357 if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) { 3358 this->set_fflags(kInvalidOperation); 3359 return std::numeric_limits<double>::quiet_NaN(); 3360 } else { 3361 return -std::fma(drs1, drs2, drs3); 3362 } 3363 }; 3364 set_drd(CanonicalizeFPUOp3<double>(fn)); 3365 break; 3366 } 3367 default: 3368 UNSUPPORTED(); 3369 } 3370 } 3371 3372 # ifdef CAN_USE_RVV_INSTRUCTIONS 3373 bool Simulator::DecodeRvvVL() { 3374 uint32_t instr_temp = 3375 instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask); 3376 if (RO_V_VL == instr_temp) { 3377 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) { 3378 switch (instr_.vl_vs_width()) { 3379 case 8: { 3380 RVV_VI_LD(0, (i * nf + fn), int8, false); 3381 break; 3382 } 3383 case 16: { 3384 RVV_VI_LD(0, (i * nf + fn), int16, false); 3385 break; 3386 } 3387 case 32: { 3388 RVV_VI_LD(0, (i * nf + fn), int32, false); 3389 break; 3390 } 3391 case 64: { 3392 RVV_VI_LD(0, (i * nf + fn), int64, false); 3393 break; 3394 } 3395 default: 3396 UNIMPLEMENTED_RISCV(); 3397 break; 3398 } 3399 return true; 3400 } else { 3401 UNIMPLEMENTED_RISCV(); 3402 return true; 3403 } 3404 } else if (RO_V_VLS == instr_temp) { 3405 UNIMPLEMENTED_RISCV(); 3406 return true; 3407 } else if (RO_V_VLX == instr_temp) { 3408 UNIMPLEMENTED_RISCV(); 3409 return true; 3410 } else if (RO_V_VLSEG2 == instr_temp || RO_V_VLSEG3 == instr_temp || 3411 RO_V_VLSEG4 == instr_temp || RO_V_VLSEG5 == instr_temp || 3412 RO_V_VLSEG6 == instr_temp || RO_V_VLSEG7 == instr_temp || 3413 RO_V_VLSEG8 == instr_temp) { 3414 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) { 3415 UNIMPLEMENTED_RISCV(); 3416 return true; 3417 } else { 3418 UNIMPLEMENTED_RISCV(); 3419 return true; 3420 } 3421 } else if (RO_V_VLSSEG2 == instr_temp || RO_V_VLSSEG3 == instr_temp || 3422 RO_V_VLSSEG4 == instr_temp || RO_V_VLSSEG5 == instr_temp || 3423 RO_V_VLSSEG6 == instr_temp || RO_V_VLSSEG7 == instr_temp || 3424 RO_V_VLSSEG8 == instr_temp) { 3425 UNIMPLEMENTED_RISCV(); 3426 return true; 3427 } else if (RO_V_VLXSEG2 == instr_temp || RO_V_VLXSEG3 == instr_temp || 3428 RO_V_VLXSEG4 == instr_temp || RO_V_VLXSEG5 == instr_temp || 3429 RO_V_VLXSEG6 == instr_temp || RO_V_VLXSEG7 == instr_temp || 3430 RO_V_VLXSEG8 == instr_temp) { 3431 UNIMPLEMENTED_RISCV(); 3432 return true; 3433 } else { 3434 return false; 3435 } 3436 } 3437 3438 bool Simulator::DecodeRvvVS() { 3439 uint32_t instr_temp = 3440 instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask); 3441 if (RO_V_VS == instr_temp) { 3442 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) { 3443 switch (instr_.vl_vs_width()) { 3444 case 8: { 3445 RVV_VI_ST(0, (i * nf + fn), uint8, false); 3446 break; 3447 } 3448 case 16: { 3449 RVV_VI_ST(0, (i * nf + fn), uint16, false); 3450 break; 3451 } 3452 case 32: { 3453 RVV_VI_ST(0, (i * nf + fn), uint32, false); 3454 break; 3455 } 3456 case 64: { 3457 RVV_VI_ST(0, (i * nf + fn), uint64, false); 3458 break; 3459 } 3460 default: 3461 UNIMPLEMENTED_RISCV(); 3462 break; 3463 } 3464 } else { 3465 UNIMPLEMENTED_RISCV(); 3466 } 3467 return true; 3468 } else if (RO_V_VSS == instr_temp) { 3469 UNIMPLEMENTED_RISCV(); 3470 return true; 3471 } else if (RO_V_VSX == instr_temp) { 3472 UNIMPLEMENTED_RISCV(); 3473 return true; 3474 } else if (RO_V_VSU == instr_temp) { 3475 UNIMPLEMENTED_RISCV(); 3476 return true; 3477 } else if (RO_V_VSSEG2 == instr_temp || RO_V_VSSEG3 == instr_temp || 3478 RO_V_VSSEG4 == instr_temp || RO_V_VSSEG5 == instr_temp || 3479 RO_V_VSSEG6 == instr_temp || RO_V_VSSEG7 == instr_temp || 3480 RO_V_VSSEG8 == instr_temp) { 3481 UNIMPLEMENTED_RISCV(); 3482 return true; 3483 } else if (RO_V_VSSSEG2 == instr_temp || RO_V_VSSSEG3 == instr_temp || 3484 RO_V_VSSSEG4 == instr_temp || RO_V_VSSSEG5 == instr_temp || 3485 RO_V_VSSSEG6 == instr_temp || RO_V_VSSSEG7 == instr_temp || 3486 RO_V_VSSSEG8 == instr_temp) { 3487 UNIMPLEMENTED_RISCV(); 3488 return true; 3489 } else if (RO_V_VSXSEG2 == instr_temp || RO_V_VSXSEG3 == instr_temp || 3490 RO_V_VSXSEG4 == instr_temp || RO_V_VSXSEG5 == instr_temp || 3491 RO_V_VSXSEG6 == instr_temp || RO_V_VSXSEG7 == instr_temp || 3492 RO_V_VSXSEG8 == instr_temp) { 3493 UNIMPLEMENTED_RISCV(); 3494 return true; 3495 } else { 3496 return false; 3497 } 3498 } 3499 # endif 3500 3501 void Simulator::DecodeRVIType() { 3502 switch (instr_.InstructionBits() & kITypeMask) { 3503 case RO_JALR: { 3504 set_rd(get_pc() + kInstrSize); 3505 // Note: No need to shift 2 for JALR's imm12, but set lowest bit to 0. 3506 sreg_t next_pc = (rs1() + imm12()) & ~sreg_t(1); 3507 set_pc(next_pc); 3508 break; 3509 } 3510 case RO_LB: { 3511 sreg_t addr = rs1() + imm12(); 3512 int8_t val = ReadMem<int8_t>(addr, instr_.instr()); 3513 set_rd(sext_xlen(val), false); 3514 TraceMemRd(addr, val, getRegister(rd_reg())); 3515 break; 3516 } 3517 case RO_LH: { 3518 sreg_t addr = rs1() + imm12(); 3519 int16_t val = ReadMem<int16_t>(addr, instr_.instr()); 3520 set_rd(sext_xlen(val), false); 3521 TraceMemRd(addr, val, getRegister(rd_reg())); 3522 break; 3523 } 3524 case RO_LW: { 3525 sreg_t addr = rs1() + imm12(); 3526 int32_t val = ReadMem<int32_t>(addr, instr_.instr()); 3527 set_rd(sext_xlen(val), false); 3528 TraceMemRd(addr, val, getRegister(rd_reg())); 3529 break; 3530 } 3531 case RO_LBU: { 3532 sreg_t addr = rs1() + imm12(); 3533 uint8_t val = ReadMem<uint8_t>(addr, instr_.instr()); 3534 set_rd(zext_xlen(val), false); 3535 TraceMemRd(addr, val, getRegister(rd_reg())); 3536 break; 3537 } 3538 case RO_LHU: { 3539 sreg_t addr = rs1() + imm12(); 3540 uint16_t val = ReadMem<uint16_t>(addr, instr_.instr()); 3541 set_rd(zext_xlen(val), false); 3542 TraceMemRd(addr, val, getRegister(rd_reg())); 3543 break; 3544 } 3545 # ifdef JS_CODEGEN_RISCV64 3546 case RO_LWU: { 3547 int64_t addr = rs1() + imm12(); 3548 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr()); 3549 set_rd(zext_xlen(val), false); 3550 TraceMemRd(addr, val, getRegister(rd_reg())); 3551 break; 3552 } 3553 case RO_LD: { 3554 int64_t addr = rs1() + imm12(); 3555 int64_t val = ReadMem<int64_t>(addr, instr_.instr()); 3556 set_rd(sext_xlen(val), false); 3557 TraceMemRd(addr, val, getRegister(rd_reg())); 3558 break; 3559 } 3560 # endif /*JS_CODEGEN_RISCV64*/ 3561 case RO_ADDI: { 3562 set_rd(sext_xlen(rs1() + imm12())); 3563 break; 3564 } 3565 case RO_SLTI: { 3566 set_rd(sreg_t(rs1()) < sreg_t(imm12())); 3567 break; 3568 } 3569 case RO_SLTIU: { 3570 set_rd(reg_t(rs1()) < reg_t(imm12())); 3571 break; 3572 } 3573 case RO_XORI: { 3574 set_rd(imm12() ^ rs1()); 3575 break; 3576 } 3577 case RO_ORI: { 3578 set_rd(imm12() | rs1()); 3579 break; 3580 } 3581 case RO_ANDI: { 3582 set_rd(imm12() & rs1()); 3583 break; 3584 } 3585 case OP_SHL: { 3586 switch (instr_.Funct6FieldRaw() | OP_SHL) { 3587 case RO_SLLI: 3588 require(shamt6() < xlen); 3589 set_rd(sext_xlen(rs1() << shamt6())); 3590 break; 3591 case RO_BCLRI: { 3592 require(shamt6() < xlen); 3593 sreg_t index = shamt6() & (xlen - 1); 3594 set_rd(rs1() & ~(1l << index)); 3595 break; 3596 } 3597 case RO_BINVI: { 3598 require(shamt6() < xlen); 3599 sreg_t index = shamt6() & (xlen - 1); 3600 set_rd(rs1() ^ (1l << index)); 3601 break; 3602 } 3603 case RO_BSETI: { 3604 require(shamt6() < xlen); 3605 sreg_t index = shamt6() & (xlen - 1); 3606 set_rd(rs1() | (1l << index)); 3607 break; 3608 } 3609 case OP_COUNT: 3610 switch (instr_.Shamt()) { 3611 case 0: { // clz 3612 sreg_t x = rs1(); 3613 int highest_setbit = -1; 3614 for (auto i = xlen - 1; i >= 0; i--) { 3615 if ((x & (1l << i))) { 3616 highest_setbit = i; 3617 break; 3618 } 3619 } 3620 set_rd(xlen - 1 - highest_setbit); 3621 break; 3622 } 3623 case 1: { // ctz 3624 sreg_t x = rs1(); 3625 int lowest_setbit = xlen; 3626 for (auto i = 0; i < xlen; i++) { 3627 if ((x & (1l << i))) { 3628 lowest_setbit = i; 3629 break; 3630 } 3631 } 3632 set_rd(lowest_setbit); 3633 break; 3634 } 3635 case 2: { // cpop 3636 int i = 0; 3637 sreg_t n = rs1(); 3638 while (n) { 3639 n &= (n - 1); 3640 i++; 3641 } 3642 set_rd(i); 3643 break; 3644 } 3645 case 4: 3646 set_rd(static_cast<int8_t>(rs1())); 3647 break; 3648 case 5: 3649 set_rd(static_cast<int16_t>(rs1())); 3650 break; 3651 default: 3652 UNSUPPORTED(); 3653 } 3654 break; 3655 default: 3656 UNSUPPORTED(); 3657 } 3658 break; 3659 } 3660 case OP_SHR: { // RO_SRAI 3661 switch (instr_.Funct6FieldRaw() | OP_SHR) { 3662 case RO_SRLI: 3663 require(shamt6() < xlen); 3664 set_rd(sext_xlen(zext_xlen(rs1()) >> shamt6())); 3665 break; 3666 case RO_SRAI: 3667 require(shamt6() < xlen); 3668 set_rd(sext_xlen(sext_xlen(rs1()) >> shamt6())); 3669 break; 3670 case RO_BEXTI: { 3671 require(shamt6() < xlen); 3672 sreg_t index = shamt6() & (xlen - 1); 3673 set_rd((rs1() >> index) & 1); 3674 break; 3675 } 3676 case RO_ORCB&(kFunct6Mask | OP_SHR): { 3677 reg_t rs1_val = rs1(); 3678 reg_t result = 0; 3679 reg_t mask = 0xFF; 3680 reg_t step = 8; 3681 for (reg_t i = 0; i < xlen; i += step) { 3682 if ((rs1_val & mask) != 0) { 3683 result |= mask; 3684 } 3685 mask <<= step; 3686 } 3687 set_rd(result); 3688 break; 3689 } 3690 case RO_RORI: { 3691 # ifdef JS_CODEGEN_RISCV64 3692 int16_t shamt = shamt6(); 3693 # else 3694 int16_t shamt = shamt5(); 3695 # endif 3696 set_rd((static_cast<reg_t>(rs1()) >> shamt) | 3697 (static_cast<reg_t>(rs1()) << (xlen - shamt))); 3698 break; 3699 } 3700 case RO_REV8: { 3701 if (imm12() == RO_REV8_IMM12) { 3702 reg_t input = rs1(); 3703 reg_t output = 0; 3704 reg_t j = xlen - 1; 3705 for (int i = 0; i < xlen; i += 8) { 3706 output |= ((input >> (j - 7)) & 0xff) << i; 3707 j -= 8; 3708 } 3709 set_rd(output); 3710 break; 3711 } 3712 UNSUPPORTED(); 3713 } 3714 default: 3715 UNSUPPORTED(); 3716 } 3717 break; 3718 } 3719 # ifdef JS_CODEGEN_RISCV64 3720 case RO_ADDIW: { 3721 set_rd(sext32(rs1() + imm12())); 3722 break; 3723 } 3724 case OP_SHLW: 3725 switch (instr_.Funct7FieldRaw() | OP_SHLW) { 3726 case RO_SLLIW: 3727 set_rd(sext32(rs1() << shamt5())); 3728 break; 3729 case RO_SLLIUW: 3730 set_rd(zext32(rs1()) << shamt6()); 3731 break; 3732 case OP_COUNTW: { 3733 switch (instr_.Shamt()) { 3734 case 0: { // clzw 3735 sreg_t x = rs1(); 3736 int highest_setbit = -1; 3737 for (auto i = 31; i >= 0; i--) { 3738 if ((x & (1l << i))) { 3739 highest_setbit = i; 3740 break; 3741 } 3742 } 3743 set_rd(31 - highest_setbit); 3744 break; 3745 } 3746 case 1: { // ctzw 3747 sreg_t x = rs1(); 3748 int lowest_setbit = 32; 3749 for (auto i = 0; i < 32; i++) { 3750 if ((x & (1l << i))) { 3751 lowest_setbit = i; 3752 break; 3753 } 3754 } 3755 set_rd(lowest_setbit); 3756 break; 3757 } 3758 case 2: { // cpopw 3759 int i = 0; 3760 int32_t n = static_cast<int32_t>(rs1()); 3761 while (n) { 3762 n &= (n - 1); 3763 i++; 3764 } 3765 set_rd(i); 3766 break; 3767 } 3768 default: 3769 UNSUPPORTED(); 3770 } 3771 break; 3772 } 3773 default: 3774 UNSUPPORTED(); 3775 } 3776 break; 3777 case OP_SHRW: { // RO_SRAI 3778 switch (instr_.Funct7FieldRaw() | OP_SHRW) { 3779 case RO_SRLIW: 3780 set_rd(sext32(uint32_t(rs1()) >> shamt5())); 3781 break; 3782 case RO_SRAIW: 3783 set_rd(sext32(int32_t(rs1()) >> shamt5())); 3784 break; 3785 case RO_RORIW: { 3786 reg_t extz_rs1 = zext32(rs1()); 3787 int16_t shamt = shamt5(); 3788 set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt)))); 3789 break; 3790 } 3791 default: 3792 UNSUPPORTED(); 3793 } 3794 break; 3795 } 3796 # endif /*JS_CODEGEN_RISCV64*/ 3797 case RO_FENCE: { 3798 // DO nothing in sumulator 3799 break; 3800 } 3801 case RO_ECALL: { // RO_EBREAK 3802 if (instr_.Imm12Value() == 0) { // ECALL 3803 SoftwareInterrupt(); 3804 } else if (instr_.Imm12Value() == 1) { // EBREAK 3805 uint8_t code = get_ebreak_code(instr_.instr()); 3806 if (code == kWasmTrapCode) { 3807 HandleWasmTrap(); 3808 } 3809 SoftwareInterrupt(); 3810 } else { 3811 UNSUPPORTED(); 3812 } 3813 break; 3814 } 3815 // TODO(riscv): use Zifencei Standard Extension macro block 3816 case RO_FENCE_I: { 3817 // spike: flush icache. 3818 break; 3819 } 3820 // TODO(riscv): use Zicsr Standard Extension macro block 3821 case RO_CSRRW: { 3822 if (rd_reg() != zero_reg) { 3823 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3824 } 3825 write_csr_value(csr_reg(), rs1()); 3826 break; 3827 } 3828 case RO_CSRRS: { 3829 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3830 if (rs1_reg() != zero_reg) { 3831 set_csr_bits(csr_reg(), rs1()); 3832 } 3833 break; 3834 } 3835 case RO_CSRRC: { 3836 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3837 if (rs1_reg() != zero_reg) { 3838 clear_csr_bits(csr_reg(), rs1()); 3839 } 3840 break; 3841 } 3842 case RO_CSRRWI: { 3843 if (rd_reg() != zero_reg) { 3844 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3845 } 3846 if (csr_reg() == csr_cycle) { 3847 if (imm5CSR() == kWasmTrapCode) { 3848 HandleWasmTrap(); 3849 return; 3850 } 3851 } 3852 write_csr_value(csr_reg(), imm5CSR()); 3853 break; 3854 } 3855 case RO_CSRRSI: { 3856 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3857 if (imm5CSR() != 0) { 3858 set_csr_bits(csr_reg(), imm5CSR()); 3859 } 3860 break; 3861 } 3862 case RO_CSRRCI: { 3863 set_rd(zext_xlen(read_csr_value(csr_reg()))); 3864 if (imm5CSR() != 0) { 3865 clear_csr_bits(csr_reg(), imm5CSR()); 3866 } 3867 break; 3868 } 3869 // TODO(riscv): use F Extension macro block 3870 case RO_FLW: { 3871 sreg_t addr = rs1() + imm12(); 3872 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr()); 3873 set_frd(Float32::FromBits(val), false); 3874 TraceMemRdFloat(addr, Float32::FromBits(val), getFpuRegister(frd_reg())); 3875 break; 3876 } 3877 // TODO(riscv): use D Extension macro block 3878 case RO_FLD: { 3879 sreg_t addr = rs1() + imm12(); 3880 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr()); 3881 set_drd(Float64::FromBits(val), false); 3882 TraceMemRdDouble(addr, Float64::FromBits(val), getFpuRegister(frd_reg())); 3883 break; 3884 } 3885 default: { 3886 # ifdef CAN_USE_RVV_INSTRUCTIONS 3887 if (!DecodeRvvVL()) { 3888 UNSUPPORTED(); 3889 } 3890 break; 3891 # else 3892 UNSUPPORTED(); 3893 # endif 3894 } 3895 } 3896 } 3897 3898 void Simulator::DecodeRVSType() { 3899 switch (instr_.InstructionBits() & kSTypeMask) { 3900 case RO_SB: 3901 WriteMem<uint8_t>(rs1() + s_imm12(), (uint8_t)rs2(), instr_.instr()); 3902 break; 3903 case RO_SH: 3904 WriteMem<uint16_t>(rs1() + s_imm12(), (uint16_t)rs2(), instr_.instr()); 3905 break; 3906 case RO_SW: 3907 WriteMem<uint32_t>(rs1() + s_imm12(), (uint32_t)rs2(), instr_.instr()); 3908 break; 3909 # ifdef JS_CODEGEN_RISCV64 3910 case RO_SD: 3911 WriteMem<uint64_t>(rs1() + s_imm12(), (uint64_t)rs2(), instr_.instr()); 3912 break; 3913 # endif /*JS_CODEGEN_RISCV64*/ 3914 // TODO(riscv): use F Extension macro block 3915 case RO_FSW: { 3916 WriteMem<Float32>(rs1() + s_imm12(), getFpuRegisterFloat32(rs2_reg()), 3917 instr_.instr()); 3918 break; 3919 } 3920 // TODO(riscv): use D Extension macro block 3921 case RO_FSD: { 3922 WriteMem<Float64>(rs1() + s_imm12(), getFpuRegisterFloat64(rs2_reg()), 3923 instr_.instr()); 3924 break; 3925 } 3926 default: 3927 # ifdef CAN_USE_RVV_INSTRUCTIONS 3928 if (!DecodeRvvVS()) { 3929 UNSUPPORTED(); 3930 } 3931 break; 3932 # else 3933 UNSUPPORTED(); 3934 # endif 3935 } 3936 } 3937 3938 void Simulator::DecodeRVBType() { 3939 switch (instr_.InstructionBits() & kBTypeMask) { 3940 case RO_BEQ: 3941 if (rs1() == rs2()) { 3942 int64_t next_pc = get_pc() + boffset(); 3943 set_pc(next_pc); 3944 } 3945 break; 3946 case RO_BNE: 3947 if (rs1() != rs2()) { 3948 int64_t next_pc = get_pc() + boffset(); 3949 set_pc(next_pc); 3950 } 3951 break; 3952 case RO_BLT: 3953 if (rs1() < rs2()) { 3954 int64_t next_pc = get_pc() + boffset(); 3955 set_pc(next_pc); 3956 } 3957 break; 3958 case RO_BGE: 3959 if (rs1() >= rs2()) { 3960 int64_t next_pc = get_pc() + boffset(); 3961 set_pc(next_pc); 3962 } 3963 break; 3964 case RO_BLTU: 3965 if ((reg_t)rs1() < (reg_t)rs2()) { 3966 int64_t next_pc = get_pc() + boffset(); 3967 set_pc(next_pc); 3968 } 3969 break; 3970 case RO_BGEU: 3971 if ((reg_t)rs1() >= (reg_t)rs2()) { 3972 int64_t next_pc = get_pc() + boffset(); 3973 set_pc(next_pc); 3974 } 3975 break; 3976 default: 3977 UNSUPPORTED(); 3978 } 3979 } 3980 void Simulator::DecodeRVUType() { 3981 // U Type doesn't have additoinal mask 3982 switch (instr_.BaseOpcodeFieldRaw()) { 3983 case LUI: 3984 set_rd(u_imm20()); 3985 break; 3986 case AUIPC: 3987 set_rd(sext_xlen(u_imm20() + get_pc())); 3988 break; 3989 default: 3990 UNSUPPORTED(); 3991 } 3992 } 3993 void Simulator::DecodeRVJType() { 3994 // J Type doesn't have additional mask 3995 switch (instr_.BaseOpcodeValue()) { 3996 case JAL: { 3997 set_rd(get_pc() + kInstrSize); 3998 int64_t next_pc = get_pc() + imm20J(); 3999 set_pc(next_pc); 4000 break; 4001 } 4002 default: 4003 UNSUPPORTED(); 4004 } 4005 } 4006 void Simulator::DecodeCRType() { 4007 switch (instr_.RvcFunct4Value()) { 4008 case 0b1000: 4009 if (instr_.RvcRs1Value() != 0 && instr_.RvcRs2Value() == 0) { // c.jr 4010 set_pc(rvc_rs1()); 4011 } else if (instr_.RvcRdValue() != 0 && 4012 instr_.RvcRs2Value() != 0) { // c.mv 4013 set_rvc_rd(sext_xlen(rvc_rs2())); 4014 } else { 4015 UNSUPPORTED(); 4016 } 4017 break; 4018 case 0b1001: 4019 if (instr_.RvcRs1Value() == 0 && instr_.RvcRs2Value() == 0) { // c.ebreak 4020 DieOrDebug(); 4021 } else if (instr_.RvcRdValue() != 0 && 4022 instr_.RvcRs2Value() == 0) { // c.jalr 4023 setRegister(ra, get_pc() + kShortInstrSize); 4024 set_pc(rvc_rs1()); 4025 } else if (instr_.RvcRdValue() != 0 && 4026 instr_.RvcRs2Value() != 0) { // c.add 4027 set_rvc_rd(sext_xlen(rvc_rs1() + rvc_rs2())); 4028 } else { 4029 UNSUPPORTED(); 4030 } 4031 break; 4032 default: 4033 UNSUPPORTED(); 4034 } 4035 } 4036 4037 void Simulator::DecodeCAType() { 4038 switch (instr_.InstructionBits() & kCATypeMask) { 4039 case RO_C_SUB: 4040 set_rvc_rs1s(sext_xlen(rvc_rs1s() - rvc_rs2s())); 4041 break; 4042 case RO_C_XOR: 4043 set_rvc_rs1s(rvc_rs1s() ^ rvc_rs2s()); 4044 break; 4045 case RO_C_OR: 4046 set_rvc_rs1s(rvc_rs1s() | rvc_rs2s()); 4047 break; 4048 case RO_C_AND: 4049 set_rvc_rs1s(rvc_rs1s() & rvc_rs2s()); 4050 break; 4051 # if JS_CODEGEN_RISCV64 4052 case RO_C_SUBW: 4053 set_rvc_rs1s(sext32(rvc_rs1s() - rvc_rs2s())); 4054 break; 4055 case RO_C_ADDW: 4056 set_rvc_rs1s(sext32(rvc_rs1s() + rvc_rs2s())); 4057 break; 4058 # endif 4059 default: 4060 UNSUPPORTED(); 4061 } 4062 } 4063 4064 void Simulator::DecodeCIType() { 4065 switch (instr_.RvcOpcode()) { 4066 case RO_C_NOP_ADDI: 4067 if (instr_.RvcRdValue() == 0) // c.nop 4068 break; 4069 else // c.addi 4070 set_rvc_rd(sext_xlen(rvc_rs1() + rvc_imm6())); 4071 break; 4072 # if JS_CODEGEN_RISCV64 4073 case RO_C_ADDIW: 4074 set_rvc_rd(sext32(rvc_rs1() + rvc_imm6())); 4075 break; 4076 # endif 4077 case RO_C_LI: 4078 set_rvc_rd(sext_xlen(rvc_imm6())); 4079 break; 4080 case RO_C_LUI_ADD: 4081 if (instr_.RvcRdValue() == 2) { 4082 // c.addi16sp 4083 int64_t value = getRegister(sp) + rvc_imm6_addi16sp(); 4084 setRegister(sp, value); 4085 } else if (instr_.RvcRdValue() != 0 && instr_.RvcRdValue() != 2) { 4086 // c.lui 4087 set_rvc_rd(rvc_u_imm6()); 4088 } else { 4089 UNSUPPORTED(); 4090 } 4091 break; 4092 case RO_C_SLLI: 4093 set_rvc_rd(sext_xlen(rvc_rs1() << rvc_shamt6())); 4094 break; 4095 case RO_C_FLDSP: { 4096 sreg_t addr = getRegister(sp) + rvc_imm6_ldsp(); 4097 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr()); 4098 set_rvc_drd(Float64::FromBits(val), false); 4099 TraceMemRdDouble(addr, Float64::FromBits(val), 4100 getFpuRegister(rvc_frd_reg())); 4101 break; 4102 } 4103 # if JS_CODEGEN_RISCV64 4104 case RO_C_LWSP: { 4105 sreg_t addr = getRegister(sp) + rvc_imm6_lwsp(); 4106 int64_t val = ReadMem<int32_t>(addr, instr_.instr()); 4107 set_rvc_rd(sext_xlen(val), false); 4108 TraceMemRd(addr, val, getRegister(rvc_rd_reg())); 4109 break; 4110 } 4111 case RO_C_LDSP: { 4112 sreg_t addr = getRegister(sp) + rvc_imm6_ldsp(); 4113 int64_t val = ReadMem<int64_t>(addr, instr_.instr()); 4114 set_rvc_rd(sext_xlen(val), false); 4115 TraceMemRd(addr, val, getRegister(rvc_rd_reg())); 4116 break; 4117 } 4118 # elif JS_CODEGEN_RISCV32 4119 case RO_C_FLWSP: { 4120 sreg_t addr = getRegister(sp) + rvc_imm6_ldsp(); 4121 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr()); 4122 set_rvc_frd(Float32::FromBits(val), false); 4123 TraceMemRdFloat(addr, Float32::FromBits(val), 4124 getFpuRegister(rvc_frd_reg())); 4125 break; 4126 } 4127 case RO_C_LWSP: { 4128 sreg_t addr = getRegister(sp) + rvc_imm6_lwsp(); 4129 int32_t val = ReadMem<int32_t>(addr, instr_.instr()); 4130 set_rvc_rd(sext_xlen(val), false); 4131 TraceMemRd(addr, val, getRegister(rvc_rd_reg())); 4132 break; 4133 } 4134 # endif 4135 default: 4136 UNSUPPORTED(); 4137 } 4138 } 4139 4140 void Simulator::DecodeCIWType() { 4141 switch (instr_.RvcOpcode()) { 4142 case RO_C_ADDI4SPN: { 4143 set_rvc_rs2s(getRegister(sp) + rvc_imm8_addi4spn()); 4144 break; 4145 default: 4146 UNSUPPORTED(); 4147 } 4148 } 4149 } 4150 4151 void Simulator::DecodeCSSType() { 4152 switch (instr_.RvcOpcode()) { 4153 case RO_C_FSDSP: { 4154 sreg_t addr = getRegister(sp) + rvc_imm6_sdsp(); 4155 WriteMem<Float64>(addr, getFpuRegisterFloat64(rvc_rs2_reg()), 4156 instr_.instr()); 4157 break; 4158 } 4159 # if JS_CODEGEN_RISCV32 4160 case RO_C_FSWSP: { 4161 sreg_t addr = getRegister(sp) + rvc_imm6_sdsp(); 4162 WriteMem<Float32>(addr, getFpuRegisterFloat32(rvc_rs2_reg()), 4163 instr_.instr()); 4164 break; 4165 } 4166 # endif 4167 case RO_C_SWSP: { 4168 sreg_t addr = getRegister(sp) + rvc_imm6_swsp(); 4169 WriteMem<int32_t>(addr, (int32_t)rvc_rs2(), instr_.instr()); 4170 break; 4171 } 4172 # if JS_CODEGEN_RISCV64 4173 case RO_C_SDSP: { 4174 sreg_t addr = getRegister(sp) + rvc_imm6_sdsp(); 4175 WriteMem<int64_t>(addr, (int64_t)rvc_rs2(), instr_.instr()); 4176 break; 4177 } 4178 # endif 4179 default: 4180 UNSUPPORTED(); 4181 } 4182 } 4183 4184 void Simulator::DecodeCLType() { 4185 switch (instr_.RvcOpcode()) { 4186 case RO_C_LW: { 4187 sreg_t addr = rvc_rs1s() + rvc_imm5_w(); 4188 int64_t val = ReadMem<int32_t>(addr, instr_.instr()); 4189 set_rvc_rs2s(sext_xlen(val), false); 4190 TraceMemRd(addr, val, getRegister(rvc_rs2s_reg())); 4191 break; 4192 } 4193 case RO_C_FLD: { 4194 sreg_t addr = rvc_rs1s() + rvc_imm5_d(); 4195 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr()); 4196 set_rvc_drs2s(Float64::FromBits(val), false); 4197 break; 4198 } 4199 # if JS_CODEGEN_RISCV64 4200 case RO_C_LD: { 4201 sreg_t addr = rvc_rs1s() + rvc_imm5_d(); 4202 int64_t val = ReadMem<int64_t>(addr, instr_.instr()); 4203 set_rvc_rs2s(sext_xlen(val), false); 4204 TraceMemRd(addr, val, getRegister(rvc_rs2s_reg())); 4205 break; 4206 } 4207 # elif JS_CODEGEN_RISCV32 4208 case RO_C_FLW: { 4209 sreg_t addr = rvc_rs1s() + rvc_imm5_d(); 4210 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr()); 4211 set_rvc_frs2s(Float32::FromBits(val), false); 4212 break; 4213 } 4214 # endif 4215 default: 4216 UNSUPPORTED(); 4217 } 4218 } 4219 4220 void Simulator::DecodeCSType() { 4221 switch (instr_.RvcOpcode()) { 4222 case RO_C_SW: { 4223 sreg_t addr = rvc_rs1s() + rvc_imm5_w(); 4224 WriteMem<int32_t>(addr, (int32_t)rvc_rs2s(), instr_.instr()); 4225 break; 4226 } 4227 # if JS_CODEGEN_RISCV64 4228 case RO_C_SD: { 4229 sreg_t addr = rvc_rs1s() + rvc_imm5_d(); 4230 WriteMem<int64_t>(addr, (int64_t)rvc_rs2s(), instr_.instr()); 4231 break; 4232 } 4233 # endif 4234 case RO_C_FSD: { 4235 sreg_t addr = rvc_rs1s() + rvc_imm5_d(); 4236 WriteMem<double>(addr, static_cast<double>(rvc_drs2s()), instr_.instr()); 4237 break; 4238 } 4239 default: 4240 UNSUPPORTED(); 4241 } 4242 } 4243 4244 void Simulator::DecodeCJType() { 4245 switch (instr_.RvcOpcode()) { 4246 case RO_C_J: { 4247 set_pc(get_pc() + instr_.RvcImm11CJValue()); 4248 break; 4249 } 4250 default: 4251 UNSUPPORTED(); 4252 } 4253 } 4254 4255 void Simulator::DecodeCBType() { 4256 switch (instr_.RvcOpcode()) { 4257 case RO_C_BNEZ: 4258 if (rvc_rs1() != 0) { 4259 sreg_t next_pc = get_pc() + rvc_imm8_b(); 4260 set_pc(next_pc); 4261 } 4262 break; 4263 case RO_C_BEQZ: 4264 if (rvc_rs1() == 0) { 4265 sreg_t next_pc = get_pc() + rvc_imm8_b(); 4266 set_pc(next_pc); 4267 } 4268 break; 4269 case RO_C_MISC_ALU: 4270 if (instr_.RvcFunct2BValue() == 0b00) { // c.srli 4271 set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6())); 4272 } else if (instr_.RvcFunct2BValue() == 0b01) { // c.srai 4273 require(rvc_shamt6() < xlen); 4274 set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6())); 4275 } else if (instr_.RvcFunct2BValue() == 0b10) { // c.andi 4276 set_rvc_rs1s(rvc_imm6() & rvc_rs1s()); 4277 } else { 4278 UNSUPPORTED(); 4279 } 4280 break; 4281 default: 4282 UNSUPPORTED(); 4283 } 4284 } 4285 4286 void Simulator::callInternal(uint8_t* entry) { 4287 // Prepare to execute the code at entry. 4288 setRegister(pc, reinterpret_cast<int64_t>(entry)); 4289 // Put down marker for end of simulation. The simulator will stop simulation 4290 // when the PC reaches this value. By saving the "end simulation" value into 4291 // the LR the simulation stops when returning to this call point. 4292 setRegister(ra, end_sim_pc); 4293 // Remember the values of callee-saved registers. 4294 intptr_t s0_val = getRegister(Simulator::Register::fp); 4295 intptr_t s1_val = getRegister(Simulator::Register::s1); 4296 intptr_t s2_val = getRegister(Simulator::Register::s2); 4297 intptr_t s3_val = getRegister(Simulator::Register::s3); 4298 intptr_t s4_val = getRegister(Simulator::Register::s4); 4299 intptr_t s5_val = getRegister(Simulator::Register::s5); 4300 intptr_t s6_val = getRegister(Simulator::Register::s6); 4301 intptr_t s7_val = getRegister(Simulator::Register::s7); 4302 intptr_t s8_val = getRegister(Simulator::Register::s8); 4303 intptr_t s9_val = getRegister(Simulator::Register::s9); 4304 intptr_t s10_val = getRegister(Simulator::Register::s10); 4305 intptr_t s11_val = getRegister(Simulator::Register::s11); 4306 intptr_t gp_val = getRegister(Simulator::Register::gp); 4307 intptr_t sp_val = getRegister(Simulator::Register::sp); 4308 4309 // Set up the callee-saved registers with a known value. To be able to check 4310 // that they are preserved properly across JS execution. If this value is 4311 // small int, it should be SMI. 4312 intptr_t callee_saved_value = icount_; 4313 setRegister(Simulator::Register::fp, callee_saved_value); 4314 setRegister(Simulator::Register::s1, callee_saved_value); 4315 setRegister(Simulator::Register::s2, callee_saved_value); 4316 setRegister(Simulator::Register::s3, callee_saved_value); 4317 setRegister(Simulator::Register::s4, callee_saved_value); 4318 setRegister(Simulator::Register::s5, callee_saved_value); 4319 setRegister(Simulator::Register::s6, callee_saved_value); 4320 setRegister(Simulator::Register::s7, callee_saved_value); 4321 setRegister(Simulator::Register::s8, callee_saved_value); 4322 setRegister(Simulator::Register::s9, callee_saved_value); 4323 setRegister(Simulator::Register::s10, callee_saved_value); 4324 setRegister(Simulator::Register::s11, callee_saved_value); 4325 setRegister(Simulator::Register::gp, callee_saved_value); 4326 4327 // Start the simulation. 4328 if (Simulator::StopSimAt != -1) { 4329 execute<true>(); 4330 } else { 4331 execute<false>(); 4332 } 4333 4334 // Check that the callee-saved registers have been preserved. 4335 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::fp)); 4336 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s1)); 4337 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s2)); 4338 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s3)); 4339 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s4)); 4340 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s5)); 4341 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s6)); 4342 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s7)); 4343 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s8)); 4344 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s9)); 4345 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s10)); 4346 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s11)); 4347 MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::gp)); 4348 4349 // Restore callee-saved registers with the original value. 4350 setRegister(Simulator::Register::fp, s0_val); 4351 setRegister(Simulator::Register::s1, s1_val); 4352 setRegister(Simulator::Register::s2, s2_val); 4353 setRegister(Simulator::Register::s3, s3_val); 4354 setRegister(Simulator::Register::s4, s4_val); 4355 setRegister(Simulator::Register::s5, s5_val); 4356 setRegister(Simulator::Register::s6, s6_val); 4357 setRegister(Simulator::Register::s7, s7_val); 4358 setRegister(Simulator::Register::s8, s8_val); 4359 setRegister(Simulator::Register::s9, s9_val); 4360 setRegister(Simulator::Register::s10, s10_val); 4361 setRegister(Simulator::Register::s11, s11_val); 4362 setRegister(Simulator::Register::gp, gp_val); 4363 setRegister(Simulator::Register::sp, sp_val); 4364 } 4365 4366 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) { 4367 va_list parameters; 4368 va_start(parameters, argument_count); 4369 4370 int64_t original_stack = getRegister(sp); 4371 // Compute position of stack on entry to generated code. 4372 int64_t entry_stack = original_stack; 4373 if (argument_count > kCArgSlotCount) { 4374 entry_stack = entry_stack - argument_count * sizeof(int64_t); 4375 } else { 4376 entry_stack = entry_stack - kCArgsSlotsSize; 4377 } 4378 4379 entry_stack &= ~U64(ABIStackAlignment - 1); 4380 4381 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); 4382 4383 // Setup the arguments. 4384 for (int i = 0; i < argument_count; i++) { 4385 js::jit::Register argReg; 4386 if (GetIntArgReg(i, &argReg)) { 4387 setRegister(argReg.code(), va_arg(parameters, int64_t)); 4388 } else { 4389 stack_argument[i] = va_arg(parameters, int64_t); 4390 } 4391 } 4392 4393 va_end(parameters); 4394 setRegister(sp, entry_stack); 4395 4396 callInternal(entry); 4397 4398 // Pop stack passed arguments. 4399 MOZ_ASSERT(entry_stack == getRegister(sp)); 4400 setRegister(sp, original_stack); 4401 4402 int64_t result = getRegister(a0); 4403 return result; 4404 } 4405 4406 uintptr_t Simulator::pushAddress(uintptr_t address) { 4407 int new_sp = getRegister(sp) - sizeof(uintptr_t); 4408 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); 4409 *stack_slot = address; 4410 setRegister(sp, new_sp); 4411 return new_sp; 4412 } 4413 4414 uintptr_t Simulator::popAddress() { 4415 int current_sp = getRegister(sp); 4416 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); 4417 uintptr_t address = *stack_slot; 4418 setRegister(sp, current_sp + sizeof(uintptr_t)); 4419 return address; 4420 } 4421 4422 } // namespace jit 4423 } // namespace js 4424 4425 js::jit::Simulator* JSContext::simulator() const { return simulator_; } 4426 4427 #endif // JS_SIMULATOR_RISCV64