1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Declares a Simulator for MIPS instructions if we are not generating a native 6 // MIPS binary. This Simulator allows us to run and debug MIPS code generation 7 // on regular desktop machines. 8 // V8 calls into generated code via the GeneratedCode wrapper, 9 // which will start execution in the Simulator or forwards to the real entry 10 // on a MIPS HW platform. 11 12 #ifndef V8_MIPS64_SIMULATOR_MIPS64_H_ 13 #define V8_MIPS64_SIMULATOR_MIPS64_H_ 14 15 #include "src/allocation.h" 16 #include "src/mips64/constants-mips64.h" 17 18 #if defined(USE_SIMULATOR) 19 // Running with a simulator. 20 21 #include "src/assembler.h" 22 #include "src/base/hashmap.h" 23 #include "src/simulator-base.h" 24 25 namespace v8 { 26 namespace internal { 27 28 // ----------------------------------------------------------------------------- 29 // Utility functions 30 31 class CachePage { 32 public: 33 static const int LINE_VALID = 0; 34 static const int LINE_INVALID = 1; 35 36 static const int kPageShift = 12; 37 static const int kPageSize = 1 << kPageShift; 38 static const int kPageMask = kPageSize - 1; 39 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 40 static const int kLineLength = 1 << kLineShift; 41 static const int kLineMask = kLineLength - 1; 42 CachePage()43 CachePage() { 44 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 45 } 46 ValidityByte(int offset)47 char* ValidityByte(int offset) { 48 return &validity_map_[offset >> kLineShift]; 49 } 50 CachedData(int offset)51 char* CachedData(int offset) { 52 return &data_[offset]; 53 } 54 55 private: 56 char data_[kPageSize]; // The cached data. 57 static const int kValidityMapSize = kPageSize >> kLineShift; 58 char validity_map_[kValidityMapSize]; // One byte per line. 59 }; 60 61 class SimInstructionBase : public InstructionBase { 62 public: InstructionType()63 Type InstructionType() const { return type_; } instr()64 inline Instruction* instr() const { return instr_; } operand()65 inline int32_t operand() const { return operand_; } 66 67 protected: SimInstructionBase()68 SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {} SimInstructionBase(Instruction * instr)69 explicit SimInstructionBase(Instruction* instr) {} 70 71 int32_t operand_; 72 Instruction* instr_; 73 Type type_; 74 75 private: 76 DISALLOW_ASSIGN(SimInstructionBase); 77 }; 78 79 class SimInstruction : public InstructionGetters<SimInstructionBase> { 80 public: SimInstruction()81 SimInstruction() {} 82 SimInstruction(Instruction * instr)83 explicit SimInstruction(Instruction* instr) { *this = instr; } 84 85 SimInstruction& operator=(Instruction* instr) { 86 operand_ = *reinterpret_cast<const int32_t*>(instr); 87 instr_ = instr; 88 type_ = InstructionBase::InstructionType(); 89 DCHECK(reinterpret_cast<void*>(&operand_) == this); 90 return *this; 91 } 92 }; 93 94 class Simulator : public SimulatorBase { 95 public: 96 friend class MipsDebugger; 97 98 // Registers are declared in order. See SMRL chapter 2. 99 enum Register { 100 no_reg = -1, 101 zero_reg = 0, 102 at, 103 v0, v1, 104 a0, a1, a2, a3, a4, a5, a6, a7, 105 t0, t1, t2, t3, 106 s0, s1, s2, s3, s4, s5, s6, s7, 107 t8, t9, 108 k0, k1, 109 gp, 110 sp, 111 s8, 112 ra, 113 // LO, HI, and pc. 114 LO, 115 HI, 116 pc, // pc must be the last register. 117 kNumSimuRegisters, 118 // aliases 119 fp = s8 120 }; 121 122 // Coprocessor registers. 123 // Generated code will always use doubles. So we will only use even registers. 124 enum FPURegister { 125 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, 126 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters. 127 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, 128 f26, f27, f28, f29, f30, f31, 129 kNumFPURegisters 130 }; 131 132 // MSA registers 133 enum MSARegister { 134 w0, 135 w1, 136 w2, 137 w3, 138 w4, 139 w5, 140 w6, 141 w7, 142 w8, 143 w9, 144 w10, 145 w11, 146 w12, 147 w13, 148 w14, 149 w15, 150 w16, 151 w17, 152 w18, 153 w19, 154 w20, 155 w21, 156 w22, 157 w23, 158 w24, 159 w25, 160 w26, 161 w27, 162 w28, 163 w29, 164 w30, 165 w31, 166 kNumMSARegisters 167 }; 168 169 explicit Simulator(Isolate* isolate); 170 ~Simulator(); 171 172 // The currently executing Simulator instance. Potentially there can be one 173 // for each native thread. 174 V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate); 175 176 // Accessors for register state. Reading the pc value adheres to the MIPS 177 // architecture specification and is off by a 8 from the currently executing 178 // instruction. 179 void set_register(int reg, int64_t value); 180 void set_register_word(int reg, int32_t value); 181 void set_dw_register(int dreg, const int* dbl); 182 int64_t get_register(int reg) const; 183 double get_double_from_register_pair(int reg); 184 // Same for FPURegisters. 185 void set_fpu_register(int fpureg, int64_t value); 186 void set_fpu_register_word(int fpureg, int32_t value); 187 void set_fpu_register_hi_word(int fpureg, int32_t value); 188 void set_fpu_register_float(int fpureg, float value); 189 void set_fpu_register_double(int fpureg, double value); 190 void set_fpu_register_invalid_result64(float original, float rounded); 191 void set_fpu_register_invalid_result(float original, float rounded); 192 void set_fpu_register_word_invalid_result(float original, float rounded); 193 void set_fpu_register_invalid_result64(double original, double rounded); 194 void set_fpu_register_invalid_result(double original, double rounded); 195 void set_fpu_register_word_invalid_result(double original, double rounded); 196 int64_t get_fpu_register(int fpureg) const; 197 int32_t get_fpu_register_word(int fpureg) const; 198 int32_t get_fpu_register_signed_word(int fpureg) const; 199 int32_t get_fpu_register_hi_word(int fpureg) const; 200 float get_fpu_register_float(int fpureg) const; 201 double get_fpu_register_double(int fpureg) const; 202 template <typename T> 203 void get_msa_register(int wreg, T* value); 204 template <typename T> 205 void set_msa_register(int wreg, const T* value); 206 void set_fcsr_bit(uint32_t cc, bool value); 207 bool test_fcsr_bit(uint32_t cc); 208 bool set_fcsr_round_error(double original, double rounded); 209 bool set_fcsr_round64_error(double original, double rounded); 210 bool set_fcsr_round_error(float original, float rounded); 211 bool set_fcsr_round64_error(float original, float rounded); 212 void round_according_to_fcsr(double toRound, double& rounded, 213 int32_t& rounded_int, double fs); 214 void round64_according_to_fcsr(double toRound, double& rounded, 215 int64_t& rounded_int, double fs); 216 void round_according_to_fcsr(float toRound, float& rounded, 217 int32_t& rounded_int, float fs); 218 void round64_according_to_fcsr(float toRound, float& rounded, 219 int64_t& rounded_int, float fs); 220 template <typename T_fp, typename T_int> 221 void round_according_to_msacsr(T_fp toRound, T_fp& rounded, 222 T_int& rounded_int); 223 void set_fcsr_rounding_mode(FPURoundingMode mode); 224 void set_msacsr_rounding_mode(FPURoundingMode mode); 225 unsigned int get_fcsr_rounding_mode(); 226 unsigned int get_msacsr_rounding_mode(); 227 // Special case of set_register and get_register to access the raw PC value. 228 void set_pc(int64_t value); 229 int64_t get_pc() const; 230 get_sp()231 Address get_sp() const { return static_cast<Address>(get_register(sp)); } 232 233 // Accessor to the internal simulator stack area. 234 uintptr_t StackLimit(uintptr_t c_limit) const; 235 236 // Executes MIPS instructions until the PC reaches end_sim_pc. 237 void Execute(); 238 239 template <typename Return, typename... Args> Call(Address entry,Args...args)240 Return Call(Address entry, Args... args) { 241 return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...); 242 } 243 244 // Alternative: call a 2-argument double function. 245 double CallFP(Address entry, double d0, double d1); 246 247 // Push an address onto the JS stack. 248 uintptr_t PushAddress(uintptr_t address); 249 250 // Pop an address from the JS stack. 251 uintptr_t PopAddress(); 252 253 // Debugger input. 254 void set_last_debugger_input(char* input); last_debugger_input()255 char* last_debugger_input() { return last_debugger_input_; } 256 257 // Redirection support. 258 static void SetRedirectInstruction(Instruction* instruction); 259 260 // ICache checking. 261 static bool ICacheMatch(void* one, void* two); 262 static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start, 263 size_t size); 264 265 // Returns true if pc register contains one of the 'special_values' defined 266 // below (bad_ra, end_sim_pc). 267 bool has_bad_pc() const; 268 269 private: 270 enum special_values { 271 // Known bad pc value to ensure that the simulator does not execute 272 // without being properly setup. 273 bad_ra = -1, 274 // A pc value used to signal the simulator to stop execution. Generally 275 // the ra is set to this value on transition from native C code to 276 // simulated execution, so that the simulator can "return" to the native 277 // C code. 278 end_sim_pc = -2, 279 // Unpredictable value. 280 Unpredictable = 0xbadbeaf 281 }; 282 283 V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count, 284 const intptr_t* arguments); 285 286 // Unsupported instructions use Format to print an error and stop execution. 287 void Format(Instruction* instr, const char* format); 288 289 // Helpers for data value tracing. 290 enum TraceType { 291 BYTE, 292 HALF, 293 WORD, 294 DWORD, 295 FLOAT, 296 DOUBLE, 297 FLOAT_DOUBLE, 298 WORD_DWORD 299 }; 300 301 // MSA Data Format 302 enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD }; 303 typedef union { 304 int8_t b[kMSALanesByte]; 305 uint8_t ub[kMSALanesByte]; 306 int16_t h[kMSALanesHalf]; 307 uint16_t uh[kMSALanesHalf]; 308 int32_t w[kMSALanesWord]; 309 uint32_t uw[kMSALanesWord]; 310 int64_t d[kMSALanesDword]; 311 uint64_t ud[kMSALanesDword]; 312 } msa_reg_t; 313 314 // Read and write memory. 315 inline uint32_t ReadBU(int64_t addr); 316 inline int32_t ReadB(int64_t addr); 317 inline void WriteB(int64_t addr, uint8_t value); 318 inline void WriteB(int64_t addr, int8_t value); 319 320 inline uint16_t ReadHU(int64_t addr, Instruction* instr); 321 inline int16_t ReadH(int64_t addr, Instruction* instr); 322 // Note: Overloaded on the sign of the value. 323 inline void WriteH(int64_t addr, uint16_t value, Instruction* instr); 324 inline void WriteH(int64_t addr, int16_t value, Instruction* instr); 325 326 inline uint32_t ReadWU(int64_t addr, Instruction* instr); 327 inline int32_t ReadW(int64_t addr, Instruction* instr, TraceType t = WORD); 328 inline void WriteW(int64_t addr, int32_t value, Instruction* instr); 329 inline int64_t Read2W(int64_t addr, Instruction* instr); 330 inline void Write2W(int64_t addr, int64_t value, Instruction* instr); 331 332 inline double ReadD(int64_t addr, Instruction* instr); 333 inline void WriteD(int64_t addr, double value, Instruction* instr); 334 335 template <typename T> 336 T ReadMem(int64_t addr, Instruction* instr); 337 template <typename T> 338 void WriteMem(int64_t addr, T value, Instruction* instr); 339 340 // Helper for debugging memory access. 341 inline void DieOrDebug(); 342 343 void TraceRegWr(int64_t value, TraceType t = DWORD); 344 template <typename T> 345 void TraceMSARegWr(T* value, TraceType t); 346 template <typename T> 347 void TraceMSARegWr(T* value); 348 void TraceMemWr(int64_t addr, int64_t value, TraceType t); 349 void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD); 350 template <typename T> 351 void TraceMemRd(int64_t addr, T value); 352 template <typename T> 353 void TraceMemWr(int64_t addr, T value); 354 355 // Operations depending on endianness. 356 // Get Double Higher / Lower word. 357 inline int32_t GetDoubleHIW(double* addr); 358 inline int32_t GetDoubleLOW(double* addr); 359 // Set Double Higher / Lower word. 360 inline int32_t SetDoubleHIW(double* addr); 361 inline int32_t SetDoubleLOW(double* addr); 362 363 SimInstruction instr_; 364 365 // functions called from DecodeTypeRegister. 366 void DecodeTypeRegisterCOP1(); 367 368 void DecodeTypeRegisterCOP1X(); 369 370 void DecodeTypeRegisterSPECIAL(); 371 372 373 void DecodeTypeRegisterSPECIAL2(); 374 375 void DecodeTypeRegisterSPECIAL3(); 376 377 void DecodeTypeRegisterSRsType(); 378 379 void DecodeTypeRegisterDRsType(); 380 381 void DecodeTypeRegisterWRsType(); 382 383 void DecodeTypeRegisterLRsType(); 384 385 int DecodeMsaDataFormat(); 386 void DecodeTypeMsaI8(); 387 void DecodeTypeMsaI5(); 388 void DecodeTypeMsaI10(); 389 void DecodeTypeMsaELM(); 390 void DecodeTypeMsaBIT(); 391 void DecodeTypeMsaMI10(); 392 void DecodeTypeMsa3R(); 393 void DecodeTypeMsa3RF(); 394 void DecodeTypeMsaVec(); 395 void DecodeTypeMsa2R(); 396 void DecodeTypeMsa2RF(); 397 template <typename T> 398 T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5); 399 template <typename T> 400 T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m); 401 template <typename T> 402 T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt); 403 404 // Executing is handled based on the instruction type. 405 void DecodeTypeRegister(); 406 rs_reg()407 inline int32_t rs_reg() const { return instr_.RsValue(); } rs()408 inline int64_t rs() const { return get_register(rs_reg()); } rs_u()409 inline uint64_t rs_u() const { 410 return static_cast<uint64_t>(get_register(rs_reg())); 411 } rt_reg()412 inline int32_t rt_reg() const { return instr_.RtValue(); } rt()413 inline int64_t rt() const { return get_register(rt_reg()); } rt_u()414 inline uint64_t rt_u() const { 415 return static_cast<uint64_t>(get_register(rt_reg())); 416 } rd_reg()417 inline int32_t rd_reg() const { return instr_.RdValue(); } fr_reg()418 inline int32_t fr_reg() const { return instr_.FrValue(); } fs_reg()419 inline int32_t fs_reg() const { return instr_.FsValue(); } ft_reg()420 inline int32_t ft_reg() const { return instr_.FtValue(); } fd_reg()421 inline int32_t fd_reg() const { return instr_.FdValue(); } sa()422 inline int32_t sa() const { return instr_.SaValue(); } lsa_sa()423 inline int32_t lsa_sa() const { return instr_.LsaSaValue(); } ws_reg()424 inline int32_t ws_reg() const { return instr_.WsValue(); } wt_reg()425 inline int32_t wt_reg() const { return instr_.WtValue(); } wd_reg()426 inline int32_t wd_reg() const { return instr_.WdValue(); } 427 SetResult(const int32_t rd_reg,const int64_t alu_out)428 inline void SetResult(const int32_t rd_reg, const int64_t alu_out) { 429 set_register(rd_reg, alu_out); 430 TraceRegWr(alu_out); 431 } 432 SetFPUWordResult(int32_t fd_reg,int32_t alu_out)433 inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) { 434 set_fpu_register_word(fd_reg, alu_out); 435 TraceRegWr(get_fpu_register(fd_reg), WORD); 436 } 437 SetFPUWordResult2(int32_t fd_reg,int32_t alu_out)438 inline void SetFPUWordResult2(int32_t fd_reg, int32_t alu_out) { 439 set_fpu_register_word(fd_reg, alu_out); 440 TraceRegWr(get_fpu_register(fd_reg)); 441 } 442 SetFPUResult(int32_t fd_reg,int64_t alu_out)443 inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) { 444 set_fpu_register(fd_reg, alu_out); 445 TraceRegWr(get_fpu_register(fd_reg)); 446 } 447 SetFPUResult2(int32_t fd_reg,int64_t alu_out)448 inline void SetFPUResult2(int32_t fd_reg, int64_t alu_out) { 449 set_fpu_register(fd_reg, alu_out); 450 TraceRegWr(get_fpu_register(fd_reg), DOUBLE); 451 } 452 SetFPUFloatResult(int32_t fd_reg,float alu_out)453 inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) { 454 set_fpu_register_float(fd_reg, alu_out); 455 TraceRegWr(get_fpu_register(fd_reg), FLOAT); 456 } 457 SetFPUDoubleResult(int32_t fd_reg,double alu_out)458 inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) { 459 set_fpu_register_double(fd_reg, alu_out); 460 TraceRegWr(get_fpu_register(fd_reg), DOUBLE); 461 } 462 463 void DecodeTypeImmediate(); 464 void DecodeTypeJump(); 465 466 // Used for breakpoints and traps. 467 void SoftwareInterrupt(); 468 469 // Compact branch guard. CheckForbiddenSlot(int64_t current_pc)470 void CheckForbiddenSlot(int64_t current_pc) { 471 Instruction* instr_after_compact_branch = 472 reinterpret_cast<Instruction*>(current_pc + kInstrSize); 473 if (instr_after_compact_branch->IsForbiddenAfterBranch()) { 474 FATAL( 475 "Error: Unexpected instruction 0x%08x immediately after a " 476 "compact branch instruction.", 477 *reinterpret_cast<uint32_t*>(instr_after_compact_branch)); 478 } 479 } 480 481 // Stop helper functions. 482 bool IsWatchpoint(uint64_t code); 483 void PrintWatchpoint(uint64_t code); 484 void HandleStop(uint64_t code, Instruction* instr); 485 bool IsStopInstruction(Instruction* instr); 486 bool IsEnabledStop(uint64_t code); 487 void EnableStop(uint64_t code); 488 void DisableStop(uint64_t code); 489 void IncreaseStopCounter(uint64_t code); 490 void PrintStopInfo(uint64_t code); 491 492 493 // Executes one instruction. 494 void InstructionDecode(Instruction* instr); 495 // Execute one instruction placed in a branch delay slot. BranchDelayInstructionDecode(Instruction * instr)496 void BranchDelayInstructionDecode(Instruction* instr) { 497 if (instr->InstructionBits() == nopInstr) { 498 // Short-cut generic nop instructions. They are always valid and they 499 // never change the simulator state. 500 return; 501 } 502 503 if (instr->IsForbiddenAfterBranch()) { 504 FATAL("Eror:Unexpected %i opcode in a branch delay slot.", 505 instr->OpcodeValue()); 506 } 507 InstructionDecode(instr); 508 SNPrintF(trace_buf_, " "); 509 } 510 511 // ICache. 512 static void CheckICache(base::CustomMatcherHashMap* i_cache, 513 Instruction* instr); 514 static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, 515 size_t size); 516 static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, 517 void* page); 518 519 enum Exception { 520 none, 521 kIntegerOverflow, 522 kIntegerUnderflow, 523 kDivideByZero, 524 kNumExceptions 525 }; 526 527 // Exceptions. 528 void SignalException(Exception e); 529 530 // Handle arguments and return value for runtime FP functions. 531 void GetFpArgs(double* x, double* y, int32_t* z); 532 void SetFpResult(const double& result); 533 534 void CallInternal(Address entry); 535 536 // Architecture state. 537 // Registers. 538 int64_t registers_[kNumSimuRegisters]; 539 // Coprocessor Registers. 540 // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in 541 // order to support MSA registers 542 int64_t FPUregisters_[kNumFPURegisters * 2]; 543 // FPU control register. 544 uint32_t FCSR_; 545 // MSA control register. 546 uint32_t MSACSR_; 547 548 // Simulator support. 549 // Allocate 1MB for stack. 550 size_t stack_size_; 551 char* stack_; 552 bool pc_modified_; 553 int64_t icount_; 554 int break_count_; 555 EmbeddedVector<char, 128> trace_buf_; 556 557 // Debugger input. 558 char* last_debugger_input_; 559 560 v8::internal::Isolate* isolate_; 561 562 // Registered breakpoints. 563 Instruction* break_pc_; 564 Instr break_instr_; 565 566 // Stop is disabled if bit 31 is set. 567 static const uint32_t kStopDisabledBit = 1 << 31; 568 569 // A stop is enabled, meaning the simulator will stop when meeting the 570 // instruction, if bit 31 of watched_stops_[code].count is unset. 571 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 572 // the breakpoint was hit or gone through. 573 struct StopCountAndDesc { 574 uint32_t count; 575 char* desc; 576 }; 577 StopCountAndDesc watched_stops_[kMaxStopCode + 1]; 578 }; 579 580 } // namespace internal 581 } // namespace v8 582 583 #endif // defined(USE_SIMULATOR) 584 #endif // V8_MIPS64_SIMULATOR_MIPS64_H_ 585