Home | History | Annotate | Download | only in mips
      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 
     43   CachePage() {
     44     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
     45   }
     46 
     47   char* ValidityByte(int offset) {
     48     return &validity_map_[offset >> kLineShift];
     49   }
     50 
     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:
     63   Type InstructionType() const { return type_; }
     64   inline Instruction* instr() const { return instr_; }
     65   inline int32_t operand() const { return operand_; }
     66 
     67  protected:
     68   SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
     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:
     81   SimInstruction() {}
     82 
     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 
    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>
    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);
    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 
    395   inline int32_t rs_reg() const { return instr_.RsValue(); }
    396   inline int32_t rs() const { return get_register(rs_reg()); }
    397   inline uint32_t rs_u() const {
    398     return static_cast<uint32_t>(get_register(rs_reg()));
    399   }
    400   inline int32_t rt_reg() const { return instr_.RtValue(); }
    401   inline int32_t rt() const { return get_register(rt_reg()); }
    402   inline uint32_t rt_u() const {
    403     return static_cast<uint32_t>(get_register(rt_reg()));
    404   }
    405   inline int32_t rd_reg() const { return instr_.RdValue(); }
    406   inline int32_t fr_reg() const { return instr_.FrValue(); }
    407   inline int32_t fs_reg() const { return instr_.FsValue(); }
    408   inline int32_t ft_reg() const { return instr_.FtValue(); }
    409   inline int32_t fd_reg() const { return instr_.FdValue(); }
    410   inline int32_t sa() const { return instr_.SaValue(); }
    411   inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
    412   inline int32_t ws_reg() const { return instr_.WsValue(); }
    413   inline int32_t wt_reg() const { return instr_.WtValue(); }
    414   inline int32_t wd_reg() const { return instr_.WdValue(); }
    415 
    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 
    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 
    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 
    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 
    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.
    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.
    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