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_MIPS_SIMULATOR_MIPS_H_ 13 #define V8_MIPS_SIMULATOR_MIPS_H_ 14 15 #include "src/allocation.h" 16 #include "src/mips/constants-mips.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, 105 t0, t1, t2, t3, t4, t5, t6, t7, 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, int32_t value); 180 void set_dw_register(int dreg, const int* dbl); 181 int32_t get_register(int reg) const; 182 double get_double_from_register_pair(int reg); 183 // Same for FPURegisters. 184 void set_fpu_register(int fpureg, int64_t value); 185 void set_fpu_register_word(int fpureg, int32_t value); 186 void set_fpu_register_hi_word(int fpureg, int32_t value); 187 void set_fpu_register_float(int fpureg, float value); 188 void set_fpu_register_double(int fpureg, double value); 189 void set_fpu_register_invalid_result64(float original, float rounded); 190 void set_fpu_register_invalid_result(float original, float rounded); 191 void set_fpu_register_word_invalid_result(float original, float rounded); 192 void set_fpu_register_invalid_result64(double original, double rounded); 193 void set_fpu_register_invalid_result(double original, double rounded); 194 void set_fpu_register_word_invalid_result(double original, double rounded); 195 int64_t get_fpu_register(int fpureg) const; 196 int32_t get_fpu_register_word(int fpureg) const; 197 int32_t get_fpu_register_signed_word(int fpureg) const; 198 int32_t get_fpu_register_hi_word(int fpureg) const; 199 float get_fpu_register_float(int fpureg) const; 200 double get_fpu_register_double(int fpureg) const; 201 template <typename T> 202 void get_msa_register(int wreg, T* value); 203 template <typename T> 204 void set_msa_register(int wreg, const T* value); 205 void set_fcsr_bit(uint32_t cc, bool value); 206 bool test_fcsr_bit(uint32_t cc); 207 void set_fcsr_rounding_mode(FPURoundingMode mode); 208 void set_msacsr_rounding_mode(FPURoundingMode mode); 209 unsigned int get_fcsr_rounding_mode(); 210 unsigned int get_msacsr_rounding_mode(); 211 bool set_fcsr_round_error(double original, double rounded); 212 bool set_fcsr_round_error(float original, float rounded); 213 bool set_fcsr_round64_error(double original, double rounded); 214 bool set_fcsr_round64_error(float original, float rounded); 215 void round_according_to_fcsr(double toRound, double& rounded, 216 int32_t& rounded_int, double fs); 217 void round_according_to_fcsr(float toRound, float& rounded, 218 int32_t& rounded_int, float fs); 219 template <typename Tfp, typename Tint> 220 void round_according_to_msacsr(Tfp toRound, Tfp& rounded, Tint& rounded_int); 221 void round64_according_to_fcsr(double toRound, double& rounded, 222 int64_t& rounded_int, double fs); 223 void round64_according_to_fcsr(float toRound, float& rounded, 224 int64_t& rounded_int, float fs); 225 // Special case of set_register and get_register to access the raw PC value. 226 void set_pc(int32_t value); 227 int32_t get_pc() const; 228 get_sp()229 Address get_sp() const { return static_cast<Address>(get_register(sp)); } 230 231 // Accessor to the internal simulator stack area. 232 uintptr_t StackLimit(uintptr_t c_limit) const; 233 234 // Executes MIPS instructions until the PC reaches end_sim_pc. 235 void Execute(); 236 237 template <typename Return, typename... Args> Call(Address entry,Args...args)238 Return Call(Address entry, Args... args) { 239 return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...); 240 } 241 242 // Alternative: call a 2-argument double function. 243 double CallFP(Address entry, double d0, double d1); 244 245 // Push an address onto the JS stack. 246 uintptr_t PushAddress(uintptr_t address); 247 248 // Pop an address from the JS stack. 249 uintptr_t PopAddress(); 250 251 // Debugger input. 252 void set_last_debugger_input(char* input); last_debugger_input()253 char* last_debugger_input() { return last_debugger_input_; } 254 255 // Redirection support. 256 static void SetRedirectInstruction(Instruction* instruction); 257 258 // ICache checking. 259 static bool ICacheMatch(void* one, void* two); 260 static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start, 261 size_t size); 262 263 // Returns true if pc register contains one of the 'special_values' defined 264 // below (bad_ra, end_sim_pc). 265 bool has_bad_pc() const; 266 267 private: 268 enum special_values { 269 // Known bad pc value to ensure that the simulator does not execute 270 // without being properly setup. 271 bad_ra = -1, 272 // A pc value used to signal the simulator to stop execution. Generally 273 // the ra is set to this value on transition from native C code to 274 // simulated execution, so that the simulator can "return" to the native 275 // C code. 276 end_sim_pc = -2, 277 // Unpredictable value. 278 Unpredictable = 0xbadbeaf 279 }; 280 281 V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count, 282 const intptr_t* arguments); 283 284 // Unsupported instructions use Format to print an error and stop execution. 285 void Format(Instruction* instr, const char* format); 286 287 // Helpers for data value tracing. 288 enum TraceType { BYTE, HALF, WORD, DWORD, FLOAT, DOUBLE, FLOAT_DOUBLE }; 289 290 // MSA Data Format 291 enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD }; 292 typedef union { 293 int8_t b[kMSALanesByte]; 294 uint8_t ub[kMSALanesByte]; 295 int16_t h[kMSALanesHalf]; 296 uint16_t uh[kMSALanesHalf]; 297 int32_t w[kMSALanesWord]; 298 uint32_t uw[kMSALanesWord]; 299 int64_t d[kMSALanesDword]; 300 uint64_t ud[kMSALanesDword]; 301 } msa_reg_t; 302 303 // Read and write memory. 304 inline uint32_t ReadBU(int32_t addr); 305 inline int32_t ReadB(int32_t addr); 306 inline void WriteB(int32_t addr, uint8_t value); 307 inline void WriteB(int32_t addr, int8_t value); 308 309 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 310 inline int16_t ReadH(int32_t addr, Instruction* instr); 311 // Note: Overloaded on the sign of the value. 312 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 313 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 314 315 inline int ReadW(int32_t addr, Instruction* instr, TraceType t = WORD); 316 inline void WriteW(int32_t addr, int value, Instruction* instr); 317 318 inline double ReadD(int32_t addr, Instruction* instr); 319 inline void WriteD(int32_t addr, double value, Instruction* instr); 320 321 template <typename T> 322 T ReadMem(int32_t addr, Instruction* instr); 323 324 template <typename T> 325 void WriteMem(int32_t addr, T value, Instruction* instr); 326 327 void TraceRegWr(int32_t value, TraceType t = WORD); 328 void TraceRegWr(int64_t value, TraceType t = DWORD); 329 template <typename T> 330 void TraceMSARegWr(T* value, TraceType t); 331 template <typename T> 332 void TraceMSARegWr(T* value); 333 void TraceMemWr(int32_t addr, int32_t value, TraceType t = WORD); 334 void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD); 335 void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD); 336 void TraceMemRd(int32_t addr, int64_t value, TraceType t = DWORD); 337 template <typename T> 338 void TraceMemRd(int32_t addr, T value); 339 template <typename T> 340 void TraceMemWr(int32_t addr, T value); 341 EmbeddedVector<char, 128> trace_buf_; 342 343 // Operations depending on endianness. 344 // Get Double Higher / Lower word. 345 inline int32_t GetDoubleHIW(double* addr); 346 inline int32_t GetDoubleLOW(double* addr); 347 // Set Double Higher / Lower word. 348 inline int32_t SetDoubleHIW(double* addr); 349 inline int32_t SetDoubleLOW(double* addr); 350 351 SimInstruction instr_; 352 353 // Executing is handled based on the instruction type. 354 void DecodeTypeRegister(); 355 356 // Functions called from DecodeTypeRegister. 357 void DecodeTypeRegisterCOP1(); 358 359 void DecodeTypeRegisterCOP1X(); 360 361 void DecodeTypeRegisterSPECIAL(); 362 363 void DecodeTypeRegisterSPECIAL2(); 364 365 void DecodeTypeRegisterSPECIAL3(); 366 367 // Called from DecodeTypeRegisterCOP1. 368 void DecodeTypeRegisterSRsType(); 369 370 void DecodeTypeRegisterDRsType(); 371 372 void DecodeTypeRegisterWRsType(); 373 374 void DecodeTypeRegisterLRsType(); 375 376 int DecodeMsaDataFormat(); 377 void DecodeTypeMsaI8(); 378 void DecodeTypeMsaI5(); 379 void DecodeTypeMsaI10(); 380 void DecodeTypeMsaELM(); 381 void DecodeTypeMsaBIT(); 382 void DecodeTypeMsaMI10(); 383 void DecodeTypeMsa3R(); 384 void DecodeTypeMsa3RF(); 385 void DecodeTypeMsaVec(); 386 void DecodeTypeMsa2R(); 387 void DecodeTypeMsa2RF(); 388 template <typename T> 389 T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5); 390 template <typename T> 391 T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m); 392 template <typename T> 393 T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt); 394 rs_reg()395 inline int32_t rs_reg() const { return instr_.RsValue(); } rs()396 inline int32_t rs() const { return get_register(rs_reg()); } rs_u()397 inline uint32_t rs_u() const { 398 return static_cast<uint32_t>(get_register(rs_reg())); 399 } rt_reg()400 inline int32_t rt_reg() const { return instr_.RtValue(); } rt()401 inline int32_t rt() const { return get_register(rt_reg()); } rt_u()402 inline uint32_t rt_u() const { 403 return static_cast<uint32_t>(get_register(rt_reg())); 404 } rd_reg()405 inline int32_t rd_reg() const { return instr_.RdValue(); } fr_reg()406 inline int32_t fr_reg() const { return instr_.FrValue(); } fs_reg()407 inline int32_t fs_reg() const { return instr_.FsValue(); } ft_reg()408 inline int32_t ft_reg() const { return instr_.FtValue(); } fd_reg()409 inline int32_t fd_reg() const { return instr_.FdValue(); } sa()410 inline int32_t sa() const { return instr_.SaValue(); } lsa_sa()411 inline int32_t lsa_sa() const { return instr_.LsaSaValue(); } ws_reg()412 inline int32_t ws_reg() const { return instr_.WsValue(); } wt_reg()413 inline int32_t wt_reg() const { return instr_.WtValue(); } wd_reg()414 inline int32_t wd_reg() const { return instr_.WdValue(); } 415 SetResult(int32_t rd_reg,int32_t alu_out)416 inline void SetResult(int32_t rd_reg, int32_t alu_out) { 417 set_register(rd_reg, alu_out); 418 TraceRegWr(alu_out); 419 } 420 SetFPUWordResult(int32_t fd_reg,int32_t alu_out)421 inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) { 422 set_fpu_register_word(fd_reg, alu_out); 423 TraceRegWr(get_fpu_register_word(fd_reg)); 424 } 425 SetFPUResult(int32_t fd_reg,int64_t alu_out)426 inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) { 427 set_fpu_register(fd_reg, alu_out); 428 TraceRegWr(get_fpu_register(fd_reg)); 429 } 430 SetFPUFloatResult(int32_t fd_reg,float alu_out)431 inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) { 432 set_fpu_register_float(fd_reg, alu_out); 433 TraceRegWr(get_fpu_register_word(fd_reg), FLOAT); 434 } 435 SetFPUDoubleResult(int32_t fd_reg,double alu_out)436 inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) { 437 set_fpu_register_double(fd_reg, alu_out); 438 TraceRegWr(get_fpu_register(fd_reg), DOUBLE); 439 } 440 441 void DecodeTypeImmediate(); 442 void DecodeTypeJump(); 443 444 // Used for breakpoints and traps. 445 void SoftwareInterrupt(); 446 447 // Compact branch guard. CheckForbiddenSlot(int32_t current_pc)448 void CheckForbiddenSlot(int32_t current_pc) { 449 Instruction* instr_after_compact_branch = 450 reinterpret_cast<Instruction*>(current_pc + kInstrSize); 451 if (instr_after_compact_branch->IsForbiddenAfterBranch()) { 452 FATAL( 453 "Error: Unexpected instruction 0x%08x immediately after a " 454 "compact branch instruction.", 455 *reinterpret_cast<uint32_t*>(instr_after_compact_branch)); 456 } 457 } 458 459 // Stop helper functions. 460 bool IsWatchpoint(uint32_t code); 461 void PrintWatchpoint(uint32_t code); 462 void HandleStop(uint32_t code, Instruction* instr); 463 bool IsStopInstruction(Instruction* instr); 464 bool IsEnabledStop(uint32_t code); 465 void EnableStop(uint32_t code); 466 void DisableStop(uint32_t code); 467 void IncreaseStopCounter(uint32_t code); 468 void PrintStopInfo(uint32_t code); 469 470 471 // Executes one instruction. 472 void InstructionDecode(Instruction* instr); 473 // Execute one instruction placed in a branch delay slot. BranchDelayInstructionDecode(Instruction * instr)474 void BranchDelayInstructionDecode(Instruction* instr) { 475 if (instr->InstructionBits() == nopInstr) { 476 // Short-cut generic nop instructions. They are always valid and they 477 // never change the simulator state. 478 return; 479 } 480 481 if (instr->IsForbiddenInBranchDelay()) { 482 FATAL("Eror:Unexpected %i opcode in a branch delay slot.", 483 instr->OpcodeValue()); 484 } 485 InstructionDecode(instr); 486 SNPrintF(trace_buf_, " "); 487 } 488 489 // ICache. 490 static void CheckICache(base::CustomMatcherHashMap* i_cache, 491 Instruction* instr); 492 static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, 493 int size); 494 static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, 495 void* page); 496 497 enum Exception { 498 none, 499 kIntegerOverflow, 500 kIntegerUnderflow, 501 kDivideByZero, 502 kNumExceptions 503 }; 504 505 // Exceptions. 506 void SignalException(Exception e); 507 508 // Handle arguments and return value for runtime FP functions. 509 void GetFpArgs(double* x, double* y, int32_t* z); 510 void SetFpResult(const double& result); 511 512 void CallInternal(Address entry); 513 514 // Architecture state. 515 // Registers. 516 int32_t registers_[kNumSimuRegisters]; 517 // Coprocessor Registers. 518 // Note: FP32 mode uses only the lower 32-bit part of each element, 519 // the upper 32-bit is unpredictable. 520 // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in 521 // order to support MSA registers 522 int64_t FPUregisters_[kNumFPURegisters * 2]; 523 // FPU control register. 524 uint32_t FCSR_; 525 // MSA control register. 526 uint32_t MSACSR_; 527 528 // Simulator support. 529 // Allocate 1MB for stack. 530 static const size_t stack_size_ = 1 * 1024*1024; 531 char* stack_; 532 bool pc_modified_; 533 uint64_t icount_; 534 int break_count_; 535 536 // Debugger input. 537 char* last_debugger_input_; 538 539 v8::internal::Isolate* isolate_; 540 541 // Registered breakpoints. 542 Instruction* break_pc_; 543 Instr break_instr_; 544 545 // Stop is disabled if bit 31 is set. 546 static const uint32_t kStopDisabledBit = 1 << 31; 547 548 // A stop is enabled, meaning the simulator will stop when meeting the 549 // instruction, if bit 31 of watched_stops_[code].count is unset. 550 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 551 // the breakpoint was hit or gone through. 552 struct StopCountAndDesc { 553 uint32_t count; 554 char* desc; 555 }; 556 StopCountAndDesc watched_stops_[kMaxStopCode + 1]; 557 }; 558 559 } // namespace internal 560 } // namespace v8 561 562 #endif // defined(USE_SIMULATOR) 563 #endif // V8_MIPS_SIMULATOR_MIPS_H_ 564