simulator-a64.h revision ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dc8
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.h"
31#include "utils.h"
32#include "a64/instructions-a64.h"
33#include "a64/assembler-a64.h"
34#include "a64/disasm-a64.h"
35
36namespace vixl {
37
38enum ReverseByteMode {
39  Reverse16 = 0,
40  Reverse32 = 1,
41  Reverse64 = 2
42};
43
44// Printf. See debugger-a64.h for more informations on pseudo instructions.
45//  - type: CPURegister::RegisterType stored as a uint32_t.
46//
47// Simulate a call to printf.
48//
49// Floating-point and integer arguments are passed in separate sets of
50// registers in AAPCS64 (even for varargs functions), so it is not possible to
51// determine the type of location of each argument without some information
52// about the values that were passed in. This information could be retrieved
53// from the printf format string, but the format string is not trivial to
54// parse so we encode the relevant information with the HLT instruction under
55// the type argument. Therefore the interface is:
56//    x0: The format string
57// x1-x7: Optional arguments, if type == CPURegister::kRegister
58// d0-d7: Optional arguments, if type == CPURegister::kFPRegister
59const Instr kPrintfOpcode = 0xdeb1;
60const unsigned kPrintfTypeOffset = 1 * kInstructionSize;
61const unsigned kPrintfLength = 2 * kInstructionSize;
62
63class Simulator : public DecoderVisitor {
64 public:
65  explicit Simulator(Decoder* decoder, FILE* stream = stdout);
66  ~Simulator();
67
68  void ResetState();
69
70  // TODO: We assume little endianness, and the way in which the members of this
71  // union overlay. Add tests to ensure this, or fix accessors to no longer
72  // require this assumption.
73  union SimRegister {
74    int64_t x;
75    int32_t w;
76  };
77
78  union SimFPRegister {
79    double d;
80    float s;
81  };
82
83  // Run the simulator.
84  virtual void Run();
85  void RunFrom(Instruction* first);
86
87  // Simulation helpers.
88  inline Instruction* pc() { return pc_; }
89  inline void set_pc(Instruction* new_pc) {
90    pc_ = new_pc;
91    pc_modified_ = true;
92  }
93
94  inline void increment_pc() {
95    if (!pc_modified_) {
96      pc_ = pc_->NextInstruction();
97    }
98
99    pc_modified_ = false;
100  }
101
102  inline void ExecuteInstruction() {
103    // The program counter should always be aligned.
104    ASSERT(IsWordAligned(pc_));
105    decoder_->Decode(pc_);
106    increment_pc();
107  }
108
109  // Declare all Visitor functions.
110  #define DECLARE(A)  void Visit##A(Instruction* instr);
111  VISITOR_LIST(DECLARE)
112  #undef DECLARE
113
114  // Register accessors.
115  inline int32_t wreg(unsigned code,
116                      Reg31Mode r31mode = Reg31IsZeroRegister) const {
117    ASSERT(code < kNumberOfRegisters);
118    if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
119      return 0;
120    }
121    return registers_[code].w;
122  }
123
124  inline int64_t xreg(unsigned code,
125                      Reg31Mode r31mode = Reg31IsZeroRegister) const {
126    ASSERT(code < kNumberOfRegisters);
127    if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
128      return 0;
129    }
130    return registers_[code].x;
131  }
132
133  inline int64_t reg(unsigned size,
134                     unsigned code,
135                     Reg31Mode r31mode = Reg31IsZeroRegister) const {
136    switch (size) {
137      case kWRegSize: return wreg(code, r31mode) & kWRegMask;
138      case kXRegSize: return xreg(code, r31mode);
139      default:
140        UNREACHABLE();
141        return 0;
142    }
143  }
144
145  inline void set_wreg(unsigned code, int32_t value,
146                       Reg31Mode r31mode = Reg31IsZeroRegister) {
147    ASSERT(code < kNumberOfRegisters);
148    if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
149      return;
150    }
151    registers_[code].x = 0;  // First clear the register top bits.
152    registers_[code].w = value;
153  }
154
155  inline void set_xreg(unsigned code, int64_t value,
156                       Reg31Mode r31mode = Reg31IsZeroRegister) {
157    ASSERT(code < kNumberOfRegisters);
158    if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
159      return;
160    }
161    registers_[code].x = value;
162  }
163
164  inline void set_reg(unsigned size, unsigned code, int64_t value,
165                      Reg31Mode r31mode = Reg31IsZeroRegister) {
166    switch (size) {
167      case kWRegSize:
168        return set_wreg(code, static_cast<int32_t>(value & 0xffffffff),
169                        r31mode);
170      case kXRegSize:
171        return set_xreg(code, value, r31mode);
172      default:
173        UNREACHABLE();
174        break;
175    }
176  }
177
178  #define REG_ACCESSORS(N)                                 \
179  inline int32_t w##N() { return wreg(N); }                \
180  inline int64_t x##N() { return xreg(N); }                \
181  inline void set_w##N(int32_t val) { set_wreg(N, val); }  \
182  inline void set_x##N(int64_t val) { set_xreg(N, val); }
183  REGISTER_CODE_LIST(REG_ACCESSORS)
184  #undef REG_ACCESSORS
185
186  // Aliases.
187  #define REG_ALIAS_ACCESSORS(N, wname, xname)                \
188  inline int32_t wname() { return wreg(N); }                  \
189  inline int64_t xname() { return xreg(N); }                  \
190  inline void set_##wname(int32_t val) { set_wreg(N, val); }  \
191  inline void set_##xname(int64_t val) { set_xreg(N, val); }
192  REG_ALIAS_ACCESSORS(30, wlr, lr);
193  #undef REG_ALIAS_ACCESSORS
194
195  // The stack is a special case in aarch64.
196  inline int32_t wsp() { return wreg(31, Reg31IsStackPointer); }
197  inline int64_t sp() { return xreg(31, Reg31IsStackPointer); }
198  inline void set_wsp(int32_t val) {
199    set_wreg(31, val, Reg31IsStackPointer);
200  }
201  inline void set_sp(int64_t val) {
202    set_xreg(31, val, Reg31IsStackPointer);
203  }
204
205  // FPRegister accessors.
206  inline float sreg(unsigned code) const {
207    ASSERT(code < kNumberOfFPRegisters);
208    return fpregisters_[code].s;
209  }
210
211  inline uint32_t sreg_bits(unsigned code) const {
212    return float_to_rawbits(sreg(code));
213  }
214
215  inline double dreg(unsigned code) const {
216    ASSERT(code < kNumberOfFPRegisters);
217    return fpregisters_[code].d;
218  }
219
220  inline uint64_t dreg_bits(unsigned code) const {
221    return double_to_rawbits(dreg(code));
222  }
223
224  inline double fpreg(unsigned size, unsigned code) const {
225    switch (size) {
226      case kSRegSize: return sreg(code);
227      case kDRegSize: return dreg(code);
228      default: {
229        UNREACHABLE();
230        return 0.0;
231      }
232    }
233  }
234
235  inline void set_sreg(unsigned code, float val) {
236    ASSERT(code < kNumberOfFPRegisters);
237    // Ensure that the upper word is set to 0.
238    set_dreg_bits(code, 0);
239
240    fpregisters_[code].s = val;
241  }
242
243  inline void set_sreg_bits(unsigned code, uint32_t rawbits) {
244    ASSERT(code < kNumberOfFPRegisters);
245    // Ensure that the upper word is set to 0.
246    set_dreg_bits(code, 0);
247
248    set_sreg(code, rawbits_to_float(rawbits));
249  }
250
251  inline void set_dreg(unsigned code, double val) {
252    ASSERT(code < kNumberOfFPRegisters);
253    fpregisters_[code].d = val;
254  }
255
256  inline void set_dreg_bits(unsigned code, uint64_t rawbits) {
257    ASSERT(code < kNumberOfFPRegisters);
258    set_dreg(code, rawbits_to_double(rawbits));
259  }
260
261  inline void set_fpreg(unsigned size, unsigned code, double value) {
262    switch (size) {
263      case kSRegSize:
264        return set_sreg(code, value);
265      case kDRegSize:
266        return set_dreg(code, value);
267      default:
268        UNREACHABLE();
269        break;
270    }
271  }
272
273  #define FPREG_ACCESSORS(N)                             \
274  inline float s##N() { return sreg(N); }                \
275  inline double d##N() { return dreg(N); }               \
276  inline void set_s##N(float val) { set_sreg(N, val); }  \
277  inline void set_d##N(double val) { set_dreg(N, val); }
278  REGISTER_CODE_LIST(FPREG_ACCESSORS)
279  #undef FPREG_ACCESSORS
280
281  bool N() { return (psr_ & NFlag) != 0; }
282  bool Z() { return (psr_ & ZFlag) != 0; }
283  bool C() { return (psr_ & CFlag) != 0; }
284  bool V() { return (psr_ & VFlag) != 0; }
285  uint32_t nzcv() { return psr_ & (NFlag | ZFlag | CFlag | VFlag); }
286
287  // Debug helpers
288  void PrintFlags(bool print_all = false);
289  void PrintRegisters(bool print_all_regs = false);
290  void PrintFPRegisters(bool print_all_regs = false);
291  void PrintProcessorState();
292
293  static const char* WRegNameForCode(unsigned code,
294                                     Reg31Mode mode = Reg31IsZeroRegister);
295  static const char* XRegNameForCode(unsigned code,
296                                     Reg31Mode mode = Reg31IsZeroRegister);
297  static const char* SRegNameForCode(unsigned code);
298  static const char* DRegNameForCode(unsigned code);
299  static const char* VRegNameForCode(unsigned code);
300
301  inline bool coloured_trace() { return coloured_trace_; }
302  inline void set_coloured_trace(bool value) { coloured_trace_ = value; }
303
304  inline bool disasm_trace() { return disasm_trace_; }
305  inline void set_disasm_trace(bool value) {
306    if (value != disasm_trace_) {
307      if (value) {
308        decoder_->InsertVisitorBefore(print_disasm_, this);
309      } else {
310        decoder_->RemoveVisitor(print_disasm_);
311      }
312      disasm_trace_ = value;
313    }
314  }
315
316 protected:
317  // Simulation helpers ------------------------------------
318  bool ConditionPassed(Condition cond) {
319    switch (cond) {
320      case eq:
321        return Z();
322      case ne:
323        return !Z();
324      case hs:
325        return C();
326      case lo:
327        return !C();
328      case mi:
329        return N();
330      case pl:
331        return !N();
332      case vs:
333        return V();
334      case vc:
335        return !V();
336      case hi:
337        return C() && !Z();
338      case ls:
339        return !(C() && !Z());
340      case ge:
341        return N() == V();
342      case lt:
343        return N() != V();
344      case gt:
345        return !Z() && (N() == V());
346      case le:
347        return !(!Z() && (N() == V()));
348      case al:
349        return true;
350      default:
351        UNREACHABLE();
352        return false;
353    }
354  }
355
356  bool ConditionFailed(Condition cond) {
357    return !ConditionPassed(cond);
358  }
359
360  void AddSubHelper(Instruction* instr, int64_t op2);
361  int64_t AddWithCarry(unsigned reg_size,
362                       bool set_flags,
363                       int64_t src1,
364                       int64_t src2,
365                       int64_t carry_in = 0);
366  void LogicalHelper(Instruction* instr, int64_t op2);
367  void ConditionalCompareHelper(Instruction* instr, int64_t op2);
368  void LoadStoreHelper(Instruction* instr,
369                       int64_t offset,
370                       AddrMode addrmode);
371  void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
372  uint8_t* AddressModeHelper(unsigned addr_reg,
373                             int64_t offset,
374                             AddrMode addrmode);
375
376  uint64_t MemoryRead(const uint8_t* address, unsigned num_bytes);
377  uint8_t MemoryRead8(uint8_t* address);
378  uint16_t MemoryRead16(uint8_t* address);
379  uint32_t MemoryRead32(uint8_t* address);
380  float MemoryReadFP32(uint8_t* address);
381  uint64_t MemoryRead64(uint8_t* address);
382  double MemoryReadFP64(uint8_t* address);
383
384  void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes);
385  void MemoryWrite32(uint8_t* address, uint32_t value);
386  void MemoryWriteFP32(uint8_t* address, float value);
387  void MemoryWrite64(uint8_t* address, uint64_t value);
388  void MemoryWriteFP64(uint8_t* address, double value);
389
390  int64_t ShiftOperand(unsigned reg_size,
391                       int64_t value,
392                       Shift shift_type,
393                       unsigned amount);
394  int64_t Rotate(unsigned reg_width,
395                 int64_t value,
396                 Shift shift_type,
397                 unsigned amount);
398  int64_t ExtendValue(unsigned reg_width,
399                      int64_t value,
400                      Extend extend_type,
401                      unsigned left_shift = 0);
402
403  uint64_t ReverseBits(uint64_t value, unsigned num_bits);
404  uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
405
406  void FPCompare(double val0, double val1);
407  double FPRoundInt(double value, FPRounding round_mode);
408  int32_t FPToInt32(double value, FPRounding rmode);
409  int64_t FPToInt64(double value, FPRounding rmode);
410  uint32_t FPToUInt32(double value, FPRounding rmode);
411  uint64_t FPToUInt64(double value, FPRounding rmode);
412  double FPMax(double a, double b);
413  double FPMin(double a, double b);
414
415  // Pseudo Printf instruction
416  void DoPrintf(Instruction* instr);
417
418  // Processor state ---------------------------------------
419
420  // Output stream.
421  FILE* stream_;
422  PrintDisassembler* print_disasm_;
423
424  // General purpose registers. Register 31 is the stack pointer.
425  SimRegister registers_[kNumberOfRegisters];
426
427  // Floating point registers
428  SimFPRegister fpregisters_[kNumberOfFPRegisters];
429
430  // Program Status Register.
431  // bits[31, 27]: Condition flags N, Z, C, and V.
432  //               (Negative, Zero, Carry, Overflow)
433  uint32_t psr_;
434
435  // Condition flags.
436  void SetFlags(uint32_t new_flags);
437
438  static inline uint32_t CalcNFlag(int64_t result, unsigned reg_size) {
439    return ((result >> (reg_size - 1)) & 1) * NFlag;
440  }
441
442  static inline uint32_t CalcZFlag(int64_t result) {
443    return (result == 0) ? static_cast<uint32_t>(ZFlag) : 0;
444  }
445
446  static const uint32_t kConditionFlagsMask = 0xf0000000;
447
448  // Stack
449  byte* stack_;
450  static const int stack_protection_size_ = 256;
451  // 2 KB stack.
452  static const int stack_size_ = 2 * 1024 + 2 * stack_protection_size_;
453  byte* stack_limit_;
454
455  Decoder* decoder_;
456  // Indicates if the pc has been modified by the instruction and should not be
457  // automatically incremented.
458  bool pc_modified_;
459  Instruction* pc_;
460
461  static const char* xreg_names[];
462  static const char* wreg_names[];
463  static const char* sreg_names[];
464  static const char* dreg_names[];
465  static const char* vreg_names[];
466
467  static const Instruction* kEndOfSimAddress;
468
469 private:
470  bool coloured_trace_;
471  // Indicates whether the disassembly trace is active.
472  bool disasm_trace_;
473};
474}  // namespace vixl
475
476#endif  // VIXL_A64_SIMULATOR_A64_H_
477