• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
SimSystemRegister()88   SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }
89 
RawValue()90   inline uint32_t RawValue() const {
91     return value_;
92   }
93 
SetRawValue(uint32_t new_value)94   inline void SetRawValue(uint32_t new_value) {
95     value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
96   }
97 
Bits(int msb,int lsb)98   inline uint32_t Bits(int msb, int lsb) const {
99     return unsigned_bitextract_32(msb, lsb, value_);
100   }
101 
SignedBits(int msb,int lsb)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 
SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER,DEFINE_WRITE_IGNORE_MASK)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.
pc()178   inline Instruction* pc() { return pc_; }
set_pc(Instruction * new_pc)179   inline void set_pc(Instruction* new_pc) {
180     pc_ = new_pc;
181     pc_modified_ = true;
182   }
183 
increment_pc()184   inline void increment_pc() {
185     if (!pc_modified_) {
186       pc_ = pc_->NextInstruction();
187     }
188 
189     pc_modified_ = false;
190   }
191 
ExecuteInstruction()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);
VISITOR_LIST(DECLARE)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>
set_lr(T value)286   inline void set_lr(T value) {
287     set_reg(kLinkRegCode, value);
288   }
289 
290   template<typename T>
set_sp(T value)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>
fpreg(unsigned size,unsigned code)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>
fpreg(unsigned code)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.
sreg(unsigned code)315   inline float sreg(unsigned code) const {
316     return fpreg<float>(code);
317   }
318 
sreg_bits(unsigned code)319   inline uint32_t sreg_bits(unsigned code) const {
320     return fpreg<uint32_t>(code);
321   }
322 
dreg(unsigned code)323   inline double dreg(unsigned code) const {
324     return fpreg<double>(code);
325   }
326 
dreg_bits(unsigned code)327   inline uint64_t dreg_bits(unsigned code) const {
328     return fpreg<uint64_t>(code);
329   }
330 
fpreg(unsigned size,unsigned code)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>
set_fpreg(unsigned code,T value)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.
set_sreg(unsigned code,float value)352   inline void set_sreg(unsigned code, float value) {
353     set_fpreg(code, value);
354   }
355 
set_sreg_bits(unsigned code,uint32_t value)356   inline void set_sreg_bits(unsigned code, uint32_t value) {
357     set_fpreg(code, value);
358   }
359 
set_dreg(unsigned code,double value)360   inline void set_dreg(unsigned code, double value) {
361     set_fpreg(code, value);
362   }
363 
set_dreg_bits(unsigned code,uint64_t value)364   inline void set_dreg_bits(unsigned code, uint64_t value) {
365     set_fpreg(code, value);
366   }
367 
N()368   bool N() { return nzcv_.N() != 0; }
Z()369   bool Z() { return nzcv_.Z() != 0; }
C()370   bool C() { return nzcv_.C() != 0; }
V()371   bool V() { return nzcv_.V() != 0; }
nzcv()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.
RMode()376   FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
DN()377   bool DN() { return fpcr_.DN() != 0; }
fpcr()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 
coloured_trace()394   inline bool coloured_trace() { return coloured_trace_; }
395   void set_coloured_trace(bool value);
396 
disasm_trace()397   inline bool disasm_trace() { return disasm_trace_; }
set_disasm_trace(bool value)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   }
set_instruction_stats(bool value)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 ------------------------------------
ConditionPassed(Condition cond)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 
ConditionFailed(Condition cond)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.
FPProcessException()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.
AssertSupportedFPCR()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 
CalcNFlag(uint64_t result,unsigned reg_size)626   static inline int CalcNFlag(uint64_t result, unsigned reg_size) {
627     return (result >> (reg_size - 1)) & 1;
628   }
629 
CalcZFlag(uint64_t result)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