Home | History | Annotate | Download | only in a64
      1 // Copyright 2013, ARM Limited
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //
      7 //   * Redistributions of source code must retain the above copyright notice,
      8 //     this list of conditions and the following disclaimer.
      9 //   * Redistributions in binary form must reproduce the above copyright notice,
     10 //     this list of conditions and the following disclaimer in the documentation
     11 //     and/or other materials provided with the distribution.
     12 //   * Neither the name of ARM Limited nor the names of its contributors may be
     13 //     used to endorse or promote products derived from this software without
     14 //     specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
     17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
     20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27 #ifndef VIXL_A64_SIMULATOR_A64_H_
     28 #define VIXL_A64_SIMULATOR_A64_H_
     29 
     30 #include "globals-vixl.h"
     31 #include "utils-vixl.h"
     32 #include "a64/instructions-a64.h"
     33 #include "a64/assembler-a64.h"
     34 #include "a64/disasm-a64.h"
     35 #include "a64/instrument-a64.h"
     36 
     37 namespace vixl {
     38 
     39 enum ReverseByteMode {
     40   Reverse16 = 0,
     41   Reverse32 = 1,
     42   Reverse64 = 2
     43 };
     44 
     45 // Printf. See debugger-a64.h for more information on pseudo instructions.
     46 //  - arg_count: The number of arguments.
     47 //  - arg_pattern: A set of PrintfArgPattern values, packed into two-bit fields.
     48 //
     49 // Simulate a call to printf.
     50 //
     51 // Floating-point and integer arguments are passed in separate sets of registers
     52 // in AAPCS64 (even for varargs functions), so it is not possible to determine
     53 // the type of each argument without some information about the values that were
     54 // passed in. This information could be retrieved from the printf format string,
     55 // but the format string is not trivial to parse so we encode the relevant
     56 // information with the HLT instruction.
     57 //
     58 // The interface is as follows:
     59 //    x0: The format string
     60 // x1-x7: Optional arguments, if type == CPURegister::kRegister
     61 // d0-d7: Optional arguments, if type == CPURegister::kFPRegister
     62 const Instr kPrintfOpcode = 0xdeb1;
     63 const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
     64 const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
     65 const unsigned kPrintfLength = 3 * kInstructionSize;
     66 
     67 const unsigned kPrintfMaxArgCount = 4;
     68 
     69 // The argument pattern is a set of two-bit-fields, each with one of the
     70 // following values:
     71 enum PrintfArgPattern {
     72   kPrintfArgW = 1,
     73   kPrintfArgX = 2,
     74   // There is no kPrintfArgS because floats are always converted to doubles in C
     75   // varargs calls.
     76   kPrintfArgD = 3
     77 };
     78 static const unsigned kPrintfArgPatternBits = 2;
     79 
     80 
     81 // The proper way to initialize a simulated system register (such as NZCV) is as
     82 // follows:
     83 //  SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV);
     84 class SimSystemRegister {
     85  public:
     86   // The default constructor represents a register which has no writable bits.
     87   // It is not possible to set its value to anything other than 0.
     88   SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }
     89 
     90   inline uint32_t RawValue() const {
     91     return value_;
     92   }
     93 
     94   inline void SetRawValue(uint32_t new_value) {
     95     value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
     96   }
     97 
     98   inline uint32_t Bits(int msb, int lsb) const {
     99     return unsigned_bitextract_32(msb, lsb, value_);
    100   }
    101 
    102   inline int32_t SignedBits(int msb, int lsb) const {
    103     return signed_bitextract_32(msb, lsb, value_);
    104   }
    105 
    106   void SetBits(int msb, int lsb, uint32_t bits);
    107 
    108   // Default system register values.
    109   static SimSystemRegister DefaultValueFor(SystemRegister id);
    110 
    111 #define DEFINE_GETTER(Name, HighBit, LowBit, Func)                            \
    112   inline uint32_t Name() const { return Func(HighBit, LowBit); }              \
    113   inline void Set##Name(uint32_t bits) { SetBits(HighBit, LowBit, bits); }
    114 #define DEFINE_WRITE_IGNORE_MASK(Name, Mask)                                  \
    115   static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
    116 
    117   SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK)
    118 
    119 #undef DEFINE_ZERO_BITS
    120 #undef DEFINE_GETTER
    121 
    122  protected:
    123   // Most system registers only implement a few of the bits in the word. Other
    124   // bits are "read-as-zero, write-ignored". The write_ignore_mask argument
    125   // describes the bits which are not modifiable.
    126   SimSystemRegister(uint32_t value, uint32_t write_ignore_mask)
    127       : value_(value), write_ignore_mask_(write_ignore_mask) { }
    128 
    129   uint32_t value_;
    130   uint32_t write_ignore_mask_;
    131 };
    132 
    133 
    134 // Represent a register (r0-r31, v0-v31).
    135 template<int kSizeInBytes>
    136 class SimRegisterBase {
    137  public:
    138   template<typename T>
    139   void Set(T new_value, unsigned size = sizeof(T)) {
    140     VIXL_ASSERT(size <= kSizeInBytes);
    141     VIXL_ASSERT(size <= sizeof(new_value));
    142     // All AArch64 registers are zero-extending; Writing a W register clears the
    143     // top bits of the corresponding X register.
    144     memset(value_, 0, kSizeInBytes);
    145     memcpy(value_, &new_value, size);
    146   }
    147 
    148   // Copy 'size' bytes of the register to the result, and zero-extend to fill
    149   // the result.
    150   template<typename T>
    151   T Get(unsigned size = sizeof(T)) const {
    152     VIXL_ASSERT(size <= kSizeInBytes);
    153     T result;
    154     memset(&result, 0, sizeof(result));
    155     memcpy(&result, value_, size);
    156     return result;
    157   }
    158 
    159  protected:
    160   uint8_t value_[kSizeInBytes];
    161 };
    162 typedef SimRegisterBase<kXRegSizeInBytes> SimRegister;      // r0-r31
    163 typedef SimRegisterBase<kDRegSizeInBytes> SimFPRegister;    // v0-v31
    164 
    165 
    166 class Simulator : public DecoderVisitor {
    167  public:
    168   explicit Simulator(Decoder* decoder, FILE* stream = stdout);
    169   ~Simulator();
    170 
    171   void ResetState();
    172 
    173   // Run the simulator.
    174   virtual void Run();
    175   void RunFrom(Instruction* first);
    176 
    177   // Simulation helpers.
    178   inline Instruction* pc() { return pc_; }
    179   inline void set_pc(Instruction* new_pc) {
    180     pc_ = new_pc;
    181     pc_modified_ = true;
    182   }
    183 
    184   inline void increment_pc() {
    185     if (!pc_modified_) {
    186       pc_ = pc_->NextInstruction();
    187     }
    188 
    189     pc_modified_ = false;
    190   }
    191 
    192   inline void ExecuteInstruction() {
    193     // The program counter should always be aligned.
    194     VIXL_ASSERT(IsWordAligned(pc_));
    195     decoder_->Decode(pc_);
    196     increment_pc();
    197   }
    198 
    199   // Declare all Visitor functions.
    200   #define DECLARE(A)  void Visit##A(Instruction* instr);
    201   VISITOR_LIST(DECLARE)
    202   #undef DECLARE
    203 
    204   // Register accessors.
    205 
    206   // Return 'size' bits of the value of an integer register, as the specified
    207   // type. The value is zero-extended to fill the result.
    208   //
    209   // The only supported values of 'size' are kXRegSize and kWRegSize.
    210   template<typename T>
    211   inline T reg(unsigned size, unsigned code,
    212                Reg31Mode r31mode = Reg31IsZeroRegister) const {
    213     unsigned size_in_bytes = size / 8;
    214     VIXL_ASSERT(size_in_bytes <= sizeof(T));
    215     VIXL_ASSERT((size == kXRegSize) || (size == kWRegSize));
    216     VIXL_ASSERT(code < kNumberOfRegisters);
    217 
    218     if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
    219       T result;
    220       memset(&result, 0, sizeof(result));
    221       return result;
    222     }
    223     return registers_[code].Get<T>(size_in_bytes);
    224   }
    225 
    226   // Like reg(), but infer the access size from the template type.
    227   template<typename T>
    228   inline T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
    229     return reg<T>(sizeof(T) * 8, code, r31mode);
    230   }
    231 
    232   // Common specialized accessors for the reg() template.
    233   inline int32_t wreg(unsigned code,
    234                       Reg31Mode r31mode = Reg31IsZeroRegister) const {
    235     return reg<int32_t>(code, r31mode);
    236   }
    237 
    238   inline int64_t xreg(unsigned code,
    239                       Reg31Mode r31mode = Reg31IsZeroRegister) const {
    240     return reg<int64_t>(code, r31mode);
    241   }
    242 
    243   inline int64_t reg(unsigned size, unsigned code,
    244                      Reg31Mode r31mode = Reg31IsZeroRegister) const {
    245     return reg<int64_t>(size, code, r31mode);
    246   }
    247 
    248   // Write 'size' bits of 'value' into an integer register. The value is
    249   // zero-extended. This behaviour matches AArch64 register writes.
    250   //
    251   // The only supported values of 'size' are kXRegSize and kWRegSize.
    252   template<typename T>
    253   inline void set_reg(unsigned size, unsigned code, T value,
    254                       Reg31Mode r31mode = Reg31IsZeroRegister) {
    255     unsigned size_in_bytes = size / 8;
    256     VIXL_ASSERT(size_in_bytes <= sizeof(T));
    257     VIXL_ASSERT((size == kXRegSize) || (size == kWRegSize));
    258     VIXL_ASSERT(code < kNumberOfRegisters);
    259 
    260     if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
    261       return;
    262     }
    263     return registers_[code].Set(value, size_in_bytes);
    264   }
    265 
    266   // Like set_reg(), but infer the access size from the template type.
    267   template<typename T>
    268   inline void set_reg(unsigned code, T value,
    269                       Reg31Mode r31mode = Reg31IsZeroRegister) {
    270     set_reg(sizeof(value) * 8, code, value, r31mode);
    271   }
    272 
    273   // Common specialized accessors for the set_reg() template.
    274   inline void set_wreg(unsigned code, int32_t value,
    275                        Reg31Mode r31mode = Reg31IsZeroRegister) {
    276     set_reg(kWRegSize, code, value, r31mode);
    277   }
    278 
    279   inline void set_xreg(unsigned code, int64_t value,
    280                        Reg31Mode r31mode = Reg31IsZeroRegister) {
    281     set_reg(kXRegSize, code, value, r31mode);
    282   }
    283 
    284   // Commonly-used special cases.
    285   template<typename T>
    286   inline void set_lr(T value) {
    287     set_reg(kLinkRegCode, value);
    288   }
    289 
    290   template<typename T>
    291   inline void set_sp(T value) {
    292     set_reg(31, value, Reg31IsStackPointer);
    293   }
    294 
    295   // Return 'size' bits of the value of a floating-point register, as the
    296   // specified type. The value is zero-extended to fill the result.
    297   //
    298   // The only supported values of 'size' are kDRegSize and kSRegSize.
    299   template<typename T>
    300   inline T fpreg(unsigned size, unsigned code) const {
    301     unsigned size_in_bytes = size / 8;
    302     VIXL_ASSERT(size_in_bytes <= sizeof(T));
    303     VIXL_ASSERT((size == kDRegSize) || (size == kSRegSize));
    304     VIXL_ASSERT(code < kNumberOfFPRegisters);
    305     return fpregisters_[code].Get<T>(size_in_bytes);
    306   }
    307 
    308   // Like fpreg(), but infer the access size from the template type.
    309   template<typename T>
    310   inline T fpreg(unsigned code) const {
    311     return fpreg<T>(sizeof(T) * 8, code);
    312   }
    313 
    314   // Common specialized accessors for the fpreg() template.
    315   inline float sreg(unsigned code) const {
    316     return fpreg<float>(code);
    317   }
    318 
    319   inline uint32_t sreg_bits(unsigned code) const {
    320     return fpreg<uint32_t>(code);
    321   }
    322 
    323   inline double dreg(unsigned code) const {
    324     return fpreg<double>(code);
    325   }
    326 
    327   inline uint64_t dreg_bits(unsigned code) const {
    328     return fpreg<uint64_t>(code);
    329   }
    330 
    331   inline double fpreg(unsigned size, unsigned code) const {
    332     switch (size) {
    333       case kSRegSize: return sreg(code);
    334       case kDRegSize: return dreg(code);
    335       default:
    336         VIXL_UNREACHABLE();
    337         return 0.0;
    338     }
    339   }
    340 
    341   // Write 'value' into a floating-point register. The value is zero-extended.
    342   // This behaviour matches AArch64 register writes.
    343   template<typename T>
    344   inline void set_fpreg(unsigned code, T value) {
    345     VIXL_ASSERT((sizeof(value) == kDRegSizeInBytes) ||
    346            (sizeof(value) == kSRegSizeInBytes));
    347     VIXL_ASSERT(code < kNumberOfFPRegisters);
    348     fpregisters_[code].Set(value, sizeof(value));
    349   }
    350 
    351   // Common specialized accessors for the set_fpreg() template.
    352   inline void set_sreg(unsigned code, float value) {
    353     set_fpreg(code, value);
    354   }
    355 
    356   inline void set_sreg_bits(unsigned code, uint32_t value) {
    357     set_fpreg(code, value);
    358   }
    359 
    360   inline void set_dreg(unsigned code, double value) {
    361     set_fpreg(code, value);
    362   }
    363 
    364   inline void set_dreg_bits(unsigned code, uint64_t value) {
    365     set_fpreg(code, value);
    366   }
    367 
    368   bool N() { return nzcv_.N() != 0; }
    369   bool Z() { return nzcv_.Z() != 0; }
    370   bool C() { return nzcv_.C() != 0; }
    371   bool V() { return nzcv_.V() != 0; }
    372   SimSystemRegister& nzcv() { return nzcv_; }
    373 
    374   // TODO(jbramley): Find a way to make the fpcr_ members return the proper
    375   // types, so these accessors are not necessary.
    376   FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
    377   bool DN() { return fpcr_.DN() != 0; }
    378   SimSystemRegister& fpcr() { return fpcr_; }
    379 
    380   // Debug helpers
    381   void PrintSystemRegisters(bool print_all = false);
    382   void PrintRegisters(bool print_all_regs = false);
    383   void PrintFPRegisters(bool print_all_regs = false);
    384   void PrintProcessorState();
    385 
    386   static const char* WRegNameForCode(unsigned code,
    387                                      Reg31Mode mode = Reg31IsZeroRegister);
    388   static const char* XRegNameForCode(unsigned code,
    389                                      Reg31Mode mode = Reg31IsZeroRegister);
    390   static const char* SRegNameForCode(unsigned code);
    391   static const char* DRegNameForCode(unsigned code);
    392   static const char* VRegNameForCode(unsigned code);
    393 
    394   inline bool coloured_trace() { return coloured_trace_; }
    395   void set_coloured_trace(bool value);
    396 
    397   inline bool disasm_trace() { return disasm_trace_; }
    398   inline void set_disasm_trace(bool value) {
    399     if (value != disasm_trace_) {
    400       if (value) {
    401         decoder_->InsertVisitorBefore(print_disasm_, this);
    402       } else {
    403         decoder_->RemoveVisitor(print_disasm_);
    404       }
    405       disasm_trace_ = value;
    406     }
    407   }
    408   inline void set_instruction_stats(bool value) {
    409     if (value != instruction_stats_) {
    410       if (value) {
    411         decoder_->AppendVisitor(instrumentation_);
    412       } else {
    413         decoder_->RemoveVisitor(instrumentation_);
    414       }
    415       instruction_stats_ = value;
    416     }
    417   }
    418 
    419  protected:
    420   const char* clr_normal;
    421   const char* clr_flag_name;
    422   const char* clr_flag_value;
    423   const char* clr_reg_name;
    424   const char* clr_reg_value;
    425   const char* clr_fpreg_name;
    426   const char* clr_fpreg_value;
    427   const char* clr_memory_value;
    428   const char* clr_memory_address;
    429   const char* clr_debug_number;
    430   const char* clr_debug_message;
    431   const char* clr_printf;
    432 
    433   // Simulation helpers ------------------------------------
    434   bool ConditionPassed(Condition cond) {
    435     switch (cond) {
    436       case eq:
    437         return Z();
    438       case ne:
    439         return !Z();
    440       case hs:
    441         return C();
    442       case lo:
    443         return !C();
    444       case mi:
    445         return N();
    446       case pl:
    447         return !N();
    448       case vs:
    449         return V();
    450       case vc:
    451         return !V();
    452       case hi:
    453         return C() && !Z();
    454       case ls:
    455         return !(C() && !Z());
    456       case ge:
    457         return N() == V();
    458       case lt:
    459         return N() != V();
    460       case gt:
    461         return !Z() && (N() == V());
    462       case le:
    463         return !(!Z() && (N() == V()));
    464       case nv:  // Fall through.
    465       case al:
    466         return true;
    467       default:
    468         VIXL_UNREACHABLE();
    469         return false;
    470     }
    471   }
    472 
    473   bool ConditionFailed(Condition cond) {
    474     return !ConditionPassed(cond);
    475   }
    476 
    477   void AddSubHelper(Instruction* instr, int64_t op2);
    478   int64_t AddWithCarry(unsigned reg_size,
    479                        bool set_flags,
    480                        int64_t src1,
    481                        int64_t src2,
    482                        int64_t carry_in = 0);
    483   void LogicalHelper(Instruction* instr, int64_t op2);
    484   void ConditionalCompareHelper(Instruction* instr, int64_t op2);
    485   void LoadStoreHelper(Instruction* instr,
    486                        int64_t offset,
    487                        AddrMode addrmode);
    488   void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
    489   uint8_t* AddressModeHelper(unsigned addr_reg,
    490                              int64_t offset,
    491                              AddrMode addrmode);
    492 
    493   uint64_t MemoryRead(const uint8_t* address, unsigned num_bytes);
    494   uint8_t MemoryRead8(uint8_t* address);
    495   uint16_t MemoryRead16(uint8_t* address);
    496   uint32_t MemoryRead32(uint8_t* address);
    497   float MemoryReadFP32(uint8_t* address);
    498   uint64_t MemoryRead64(uint8_t* address);
    499   double MemoryReadFP64(uint8_t* address);
    500 
    501   void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes);
    502   void MemoryWrite32(uint8_t* address, uint32_t value);
    503   void MemoryWriteFP32(uint8_t* address, float value);
    504   void MemoryWrite64(uint8_t* address, uint64_t value);
    505   void MemoryWriteFP64(uint8_t* address, double value);
    506 
    507   int64_t ShiftOperand(unsigned reg_size,
    508                        int64_t value,
    509                        Shift shift_type,
    510                        unsigned amount);
    511   int64_t Rotate(unsigned reg_width,
    512                  int64_t value,
    513                  Shift shift_type,
    514                  unsigned amount);
    515   int64_t ExtendValue(unsigned reg_width,
    516                       int64_t value,
    517                       Extend extend_type,
    518                       unsigned left_shift = 0);
    519 
    520   uint64_t ReverseBits(uint64_t value, unsigned num_bits);
    521   uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
    522 
    523   template <typename T>
    524   T FPDefaultNaN() const;
    525 
    526   void FPCompare(double val0, double val1);
    527   double FPRoundInt(double value, FPRounding round_mode);
    528   double FPToDouble(float value);
    529   float FPToFloat(double value, FPRounding round_mode);
    530   double FixedToDouble(int64_t src, int fbits, FPRounding round_mode);
    531   double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode);
    532   float FixedToFloat(int64_t src, int fbits, FPRounding round_mode);
    533   float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode);
    534   int32_t FPToInt32(double value, FPRounding rmode);
    535   int64_t FPToInt64(double value, FPRounding rmode);
    536   uint32_t FPToUInt32(double value, FPRounding rmode);
    537   uint64_t FPToUInt64(double value, FPRounding rmode);
    538 
    539   template <typename T>
    540   T FPAdd(T op1, T op2);
    541 
    542   template <typename T>
    543   T FPDiv(T op1, T op2);
    544 
    545   template <typename T>
    546   T FPMax(T a, T b);
    547 
    548   template <typename T>
    549   T FPMaxNM(T a, T b);
    550 
    551   template <typename T>
    552   T FPMin(T a, T b);
    553 
    554   template <typename T>
    555   T FPMinNM(T a, T b);
    556 
    557   template <typename T>
    558   T FPMul(T op1, T op2);
    559 
    560   template <typename T>
    561   T FPMulAdd(T a, T op1, T op2);
    562 
    563   template <typename T>
    564   T FPSqrt(T op);
    565 
    566   template <typename T>
    567   T FPSub(T op1, T op2);
    568 
    569   // This doesn't do anything at the moment. We'll need it if we want support
    570   // for cumulative exception bits or floating-point exceptions.
    571   void FPProcessException() { }
    572 
    573   // Standard NaN processing.
    574   template <typename T>
    575   T FPProcessNaN(T op);
    576 
    577   bool FPProcessNaNs(Instruction* instr);
    578 
    579   template <typename T>
    580   T FPProcessNaNs(T op1, T op2);
    581 
    582   template <typename T>
    583   T FPProcessNaNs3(T op1, T op2, T op3);
    584 
    585   // Pseudo Printf instruction
    586   void DoPrintf(Instruction* instr);
    587 
    588   // Processor state ---------------------------------------
    589 
    590   // Output stream.
    591   FILE* stream_;
    592   PrintDisassembler* print_disasm_;
    593 
    594   // Instruction statistics instrumentation.
    595   Instrument* instrumentation_;
    596 
    597   // General purpose registers. Register 31 is the stack pointer.
    598   SimRegister registers_[kNumberOfRegisters];
    599 
    600   // Floating point registers
    601   SimFPRegister fpregisters_[kNumberOfFPRegisters];
    602 
    603   // Program Status Register.
    604   // bits[31, 27]: Condition flags N, Z, C, and V.
    605   //               (Negative, Zero, Carry, Overflow)
    606   SimSystemRegister nzcv_;
    607 
    608   // Floating-Point Control Register
    609   SimSystemRegister fpcr_;
    610 
    611   // Only a subset of FPCR features are supported by the simulator. This helper
    612   // checks that the FPCR settings are supported.
    613   //
    614   // This is checked when floating-point instructions are executed, not when
    615   // FPCR is set. This allows generated code to modify FPCR for external
    616   // functions, or to save and restore it when entering and leaving generated
    617   // code.
    618   void AssertSupportedFPCR() {
    619     VIXL_ASSERT(fpcr().FZ() == 0);             // No flush-to-zero support.
    620     VIXL_ASSERT(fpcr().RMode() == FPTieEven);  // Ties-to-even rounding only.
    621 
    622     // The simulator does not support half-precision operations so fpcr().AHP()
    623     // is irrelevant, and is not checked here.
    624   }
    625 
    626   static inline int CalcNFlag(uint64_t result, unsigned reg_size) {
    627     return (result >> (reg_size - 1)) & 1;
    628   }
    629 
    630   static inline int CalcZFlag(uint64_t result) {
    631     return result == 0;
    632   }
    633 
    634   static const uint32_t kConditionFlagsMask = 0xf0000000;
    635 
    636   // Stack
    637   byte* stack_;
    638   static const int stack_protection_size_ = 256;
    639   // 2 KB stack.
    640   static const int stack_size_ = 2 * 1024 + 2 * stack_protection_size_;
    641   byte* stack_limit_;
    642 
    643   Decoder* decoder_;
    644   // Indicates if the pc has been modified by the instruction and should not be
    645   // automatically incremented.
    646   bool pc_modified_;
    647   Instruction* pc_;
    648 
    649   static const char* xreg_names[];
    650   static const char* wreg_names[];
    651   static const char* sreg_names[];
    652   static const char* dreg_names[];
    653   static const char* vreg_names[];
    654 
    655   static const Instruction* kEndOfSimAddress;
    656 
    657  private:
    658   bool coloured_trace_;
    659 
    660   // Indicates whether the disassembly trace is active.
    661   bool disasm_trace_;
    662 
    663   // Indicates whether the instruction instrumentation is active.
    664   bool instruction_stats_;
    665 };
    666 }  // namespace vixl
    667 
    668 #endif  // VIXL_A64_SIMULATOR_A64_H_
    669