1 // Copyright 2013, ARM Limited
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
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.
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.
27 #ifndef VIXL_A64_SIMULATOR_A64_H_
28 #define VIXL_A64_SIMULATOR_A64_H_
33 #include "hphp/vixl/globals.h"
34 #include "hphp/vixl/utils.h"
35 #include "hphp/vixl/a64/instructions-a64.h"
36 #include "hphp/vixl/a64/assembler-a64.h"
37 #include "hphp/vixl/a64/disasm-a64.h"
38 #include "hphp/vixl/a64/instrument-a64.h"
42 enum ReverseByteMode
{
48 // Printf. See debugger-a64.h for more information on pseudo instructions.
49 // - type: CPURegister::RegisterType stored as a uint32_t.
51 // Simulate a call to printf.
53 // Floating-point and integer arguments are passed in separate sets of
54 // registers in AAPCS64 (even for varargs functions), so it is not possible to
55 // determine the type of location of each argument without some information
56 // about the values that were passed in. This information could be retrieved
57 // from the printf format string, but the format string is not trivial to
58 // parse so we encode the relevant information with the HLT instruction under
59 // the type argument. Therefore the interface is:
60 // x0: The format string
61 // x1-x7: Optional arguments, if type == CPURegister::kRegister
62 // d0-d7: Optional arguments, if type == CPURegister::kFPRegister
63 constexpr Instr kPrintfOpcode
= 0xdeb1;
64 constexpr unsigned kPrintfTypeOffset
= 1 * kInstructionSize
;
65 constexpr unsigned kPrintfLength
= 2 * kInstructionSize
;
67 constexpr Instr kHostCallOpcode
= 0xdeb4;
68 constexpr unsigned kHostCallCountOffset
= 1 * kInstructionSize
;
70 // The proper way to initialize a simulated system register (such as NZCV) is as
72 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV);
73 class SimSystemRegister
{
75 // The default constructor represents a register which has no writable bits.
76 // It is not possible to set its value to anything other than 0.
77 SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }
79 inline uint32_t RawValue() const {
83 inline void SetRawValue(uint32_t new_value
) {
84 value_
= (value_
& write_ignore_mask_
) | (new_value
& ~write_ignore_mask_
);
87 inline uint32_t Bits(int msb
, int lsb
) const {
88 return unsigned_bitextract_32(msb
, lsb
, value_
);
91 inline int32_t SignedBits(int msb
, int lsb
) const {
92 return signed_bitextract_32(msb
, lsb
, value_
);
95 void SetBits(int msb
, int lsb
, uint32_t bits
);
97 // Default system register values.
98 static SimSystemRegister
DefaultValueFor(SystemRegister id
);
100 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
101 inline uint32_t Name() const { return Func(HighBit, LowBit); } \
102 inline void Set##Name(uint32_t bits) { SetBits(HighBit, LowBit, bits); }
103 #define DEFINE_WRITE_IGNORE_MASK(Name, Mask) \
104 static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
106 SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER
, DEFINE_WRITE_IGNORE_MASK
)
108 #undef DEFINE_ZERO_BITS
112 // Most system registers only implement a few of the bits in the word. Other
113 // bits are "read-as-zero, write-ignored". The write_ignore_mask argument
114 // describes the bits which are not modifiable.
115 SimSystemRegister(uint32_t value
, uint32_t write_ignore_mask
)
116 : value_(value
), write_ignore_mask_(write_ignore_mask
) { }
119 uint32_t write_ignore_mask_
;
122 class Simulator
: public DecoderVisitor
{
124 explicit Simulator(Decoder
* decoder
, std::ostream
& stream
);
125 ~Simulator() override
;
129 // TODO: We assume little endianness, and the way in which the members of this
130 // union overlay. Add tests to ensure this, or fix accessors to no longer
131 // require this assumption.
137 union SimFPRegister
{
142 // When an exception is thrown through simulated code, call this hook. The
143 // hook returns a new instruction pointer at which to resume execution, or
144 // nullptr to continue execution normally.
145 typedef Instruction
*(*ExceptionHook
)(Simulator
*, std::exception_ptr
);
146 void set_exception_hook(ExceptionHook hook
) {
147 exception_hook_
= hook
;
150 void resume_last_exception() {
151 auto exn
= exns_in_flight_
.top();
152 exns_in_flight_
.pop();
153 std::rethrow_exception(exn
);
156 // Run the simulator.
158 void RunFrom(Instruction
* first
);
160 // Simulation helpers.
161 inline Instruction
* pc() const { return pc_
; }
162 inline void set_pc(Instruction
* new_pc
) {
167 inline void increment_pc() {
169 pc_
= pc_
->NextInstruction();
172 pc_modified_
= false;
175 inline void ExecuteInstruction() {
176 // The program counter should always be aligned.
177 assert(IsWordAligned(pc_
));
178 decoder_
->Decode(pc_
);
182 // Declare all Visitor functions.
183 #define DECLARE(A) void Visit##A(Instruction* instr) override;
184 VISITOR_LIST(DECLARE
)
187 // Register accessors.
188 inline int32_t wreg(unsigned code
,
189 Reg31Mode r31mode
= Reg31IsZeroRegister
) const {
190 assert(code
< kNumberOfRegisters
);
191 if ((code
== 31) && (r31mode
== Reg31IsZeroRegister
)) {
194 return registers_
[code
].w
;
197 inline int64_t xreg(unsigned code
,
198 Reg31Mode r31mode
= Reg31IsZeroRegister
) const {
199 assert(code
< kNumberOfRegisters
);
200 if ((code
== 31) && (r31mode
== Reg31IsZeroRegister
)) {
203 return registers_
[code
].x
;
206 inline int64_t reg(unsigned size
,
208 Reg31Mode r31mode
= Reg31IsZeroRegister
) const {
210 case kWRegSize
: return wreg(code
, r31mode
) & kWRegMask
;
211 case kXRegSize
: return xreg(code
, r31mode
);
218 inline void set_wreg(unsigned code
, int32_t value
,
219 Reg31Mode r31mode
= Reg31IsZeroRegister
) {
220 assert(code
< kNumberOfRegisters
);
221 if ((code
== kZeroRegCode
) && (r31mode
== Reg31IsZeroRegister
)) {
224 registers_
[code
].x
= 0; // First clear the register top bits.
225 registers_
[code
].w
= value
;
229 inline void set_xreg(unsigned code
, T
* value
,
230 Reg31Mode r31mode
= Reg31IsZeroRegister
) {
231 set_xreg(code
, reinterpret_cast<int64_t>(value
), r31mode
);
234 inline void set_xreg(unsigned code
, int64_t value
,
235 Reg31Mode r31mode
= Reg31IsZeroRegister
) {
236 assert(code
< kNumberOfRegisters
);
237 if ((code
== kZeroRegCode
) && (r31mode
== Reg31IsZeroRegister
)) {
240 registers_
[code
].x
= value
;
243 inline void set_reg(unsigned size
, unsigned code
, int64_t value
,
244 Reg31Mode r31mode
= Reg31IsZeroRegister
) {
247 return set_wreg(code
, static_cast<int32_t>(value
& 0xffffffff),
250 return set_xreg(code
, value
, r31mode
);
257 #define REG_ACCESSORS(N) \
258 inline int32_t w##N() { return wreg(N); } \
259 inline int64_t x##N() { return xreg(N); } \
260 inline void set_w##N(int32_t val) { set_wreg(N, val); } \
261 inline void set_x##N(int64_t val) { set_xreg(N, val); }
262 REGISTER_CODE_LIST(REG_ACCESSORS
)
266 #define REG_ALIAS_ACCESSORS(N, wname, xname) \
267 inline int32_t wname() { return wreg(N); } \
268 inline int64_t xname() { return xreg(N); } \
269 inline void set_##wname(int32_t val) { set_wreg(N, val); } \
270 inline void set_##xname(int64_t val) { set_xreg(N, val); }
271 REG_ALIAS_ACCESSORS(30, wlr
, lr
);
272 #undef REG_ALIAS_ACCESSORS
274 // The stack is a special case in aarch64.
275 inline int32_t wsp() { return wreg(31, Reg31IsStackPointer
); }
276 inline int64_t sp() { return xreg(31, Reg31IsStackPointer
); }
277 inline void set_wsp(int32_t val
) {
278 set_wreg(31, val
, Reg31IsStackPointer
);
280 inline void set_sp(int64_t val
) {
281 set_xreg(31, val
, Reg31IsStackPointer
);
284 // FPRegister accessors.
285 inline float sreg(unsigned code
) const {
286 assert(code
< kNumberOfFPRegisters
);
287 return fpregisters_
[code
].s
;
290 inline uint32_t sreg_bits(unsigned code
) const {
291 return float_to_rawbits(sreg(code
));
294 inline double dreg(unsigned code
) const {
295 assert(code
< kNumberOfFPRegisters
);
296 return fpregisters_
[code
].d
;
299 inline uint64_t dreg_bits(unsigned code
) const {
300 return double_to_rawbits(dreg(code
));
303 inline double fpreg(unsigned size
, unsigned code
) const {
305 case kSRegSize
: return sreg(code
);
306 case kDRegSize
: return dreg(code
);
314 inline void set_sreg(unsigned code
, float val
) {
315 assert(code
< kNumberOfFPRegisters
);
316 // Ensure that the upper word is set to 0.
317 set_dreg_bits(code
, 0);
319 fpregisters_
[code
].s
= val
;
322 inline void set_sreg_bits(unsigned code
, uint32_t rawbits
) {
323 assert(code
< kNumberOfFPRegisters
);
324 // Ensure that the upper word is set to 0.
325 set_dreg_bits(code
, 0);
327 set_sreg(code
, rawbits_to_float(rawbits
));
330 inline void set_dreg(unsigned code
, double val
) {
331 assert(code
< kNumberOfFPRegisters
);
332 fpregisters_
[code
].d
= val
;
335 inline void set_dreg_bits(unsigned code
, uint64_t rawbits
) {
336 assert(code
< kNumberOfFPRegisters
);
337 set_dreg(code
, rawbits_to_double(rawbits
));
340 inline void set_fpreg(unsigned size
, unsigned code
, double value
) {
343 return set_sreg(code
, value
);
345 return set_dreg(code
, value
);
352 #define FPREG_ACCESSORS(N) \
353 inline float s##N() { return sreg(N); } \
354 inline double d##N() { return dreg(N); } \
355 inline void set_s##N(float val) { set_sreg(N, val); } \
356 inline void set_d##N(double val) { set_dreg(N, val); }
357 REGISTER_CODE_LIST(FPREG_ACCESSORS
)
358 #undef FPREG_ACCESSORS
360 bool N() { return nzcv_
.N() != 0; }
361 bool Z() { return nzcv_
.Z() != 0; }
362 bool C() { return nzcv_
.C() != 0; }
363 bool V() { return nzcv_
.V() != 0; }
364 SimSystemRegister
& nzcv() { return nzcv_
; }
366 // TODO(jbramley): Find a way to make the fpcr_ members return the proper
367 // types, so this accessor is not necessary.
368 FPRounding
RMode() { return static_cast<FPRounding
>(fpcr_
.RMode()); }
369 SimSystemRegister
& fpcr() { return fpcr_
; }
372 void PrintSystemRegisters(bool print_all
= false);
373 void PrintRegisters(bool print_all_regs
= false);
374 void PrintFPRegisters(bool print_all_regs
= false);
375 void PrintProcessorState();
377 static const char* WRegNameForCode(unsigned code
,
378 Reg31Mode mode
= Reg31IsZeroRegister
);
379 static const char* XRegNameForCode(unsigned code
,
380 Reg31Mode mode
= Reg31IsZeroRegister
);
381 static const char* SRegNameForCode(unsigned code
);
382 static const char* DRegNameForCode(unsigned code
);
383 static const char* VRegNameForCode(unsigned code
);
385 inline bool coloured_trace() { return coloured_trace_
; }
386 inline void set_coloured_trace(bool value
) { coloured_trace_
= value
; }
388 inline bool disasm_trace() { return disasm_trace_
; }
389 inline void set_disasm_trace(bool value
) {
390 if (value
!= disasm_trace_
) {
392 decoder_
->InsertVisitorBefore(print_disasm_
, this);
394 decoder_
->RemoveVisitor(print_disasm_
);
396 disasm_trace_
= value
;
400 bool is_on_stack(void* ptr
) const {
401 return uint64_t((byte
*)ptr
- stack_
) < (uint64_t)stack_size_
;
404 uint64_t load_count() const { return load_count_
; }
405 uint64_t store_count() const { return store_count_
; }
406 uint64_t instr_count() const { return instr_count_
; }
409 // Simulation helpers ------------------------------------
410 bool ConditionPassed(Condition cond
) {
431 return !(C() && !Z());
437 return !Z() && (N() == V());
439 return !(!Z() && (N() == V()));
440 case nv
: // Fall through.
449 bool ConditionFailed(Condition cond
) {
450 return !ConditionPassed(cond
);
453 void AddSubHelper(Instruction
* instr
, int64_t op2
);
454 int64_t AddWithCarry(unsigned reg_size
,
458 int64_t carry_in
= 0);
459 void LogicalHelper(Instruction
* instr
, int64_t op2
);
460 void ConditionalCompareHelper(Instruction
* instr
, int64_t op2
);
461 void LoadStoreHelper(Instruction
* instr
,
464 void LoadStorePairHelper(Instruction
* instr
, AddrMode addrmode
);
465 uint8_t* AddressModeHelper(unsigned addr_reg
,
469 uint64_t MemoryRead(const uint8_t* address
, unsigned num_bytes
);
470 uint8_t MemoryRead8(uint8_t* address
);
471 uint16_t MemoryRead16(uint8_t* address
);
472 uint32_t MemoryRead32(uint8_t* address
);
473 float MemoryReadFP32(uint8_t* address
);
474 uint64_t MemoryRead64(uint8_t* address
);
475 double MemoryReadFP64(uint8_t* address
);
477 void MemoryWrite(uint8_t* address
, uint64_t value
, unsigned num_bytes
);
478 void MemoryWrite32(uint8_t* address
, uint32_t value
);
479 void MemoryWriteFP32(uint8_t* address
, float value
);
480 void MemoryWrite64(uint8_t* address
, uint64_t value
);
481 void MemoryWriteFP64(uint8_t* address
, double value
);
483 int64_t ShiftOperand(unsigned reg_size
,
487 int64_t Rotate(unsigned reg_width
,
491 int64_t ExtendValue(unsigned reg_width
,
494 unsigned left_shift
= 0);
496 uint64_t ReverseBits(uint64_t value
, unsigned num_bits
);
497 uint64_t ReverseBytes(uint64_t value
, ReverseByteMode mode
);
499 void FPCompare(double val0
, double val1
);
500 double FPRoundInt(double value
, FPRounding round_mode
);
501 double FPToDouble(float value
);
502 float FPToFloat(double value
, FPRounding round_mode
);
503 double FixedToDouble(int64_t src
, int fbits
, FPRounding round_mode
);
504 double UFixedToDouble(uint64_t src
, int fbits
, FPRounding round_mode
);
505 float FixedToFloat(int64_t src
, int fbits
, FPRounding round_mode
);
506 float UFixedToFloat(uint64_t src
, int fbits
, FPRounding round_mode
);
507 int32_t FPToInt32(double value
, FPRounding rmode
);
508 int64_t FPToInt64(double value
, FPRounding rmode
);
509 uint32_t FPToUInt32(double value
, FPRounding rmode
);
510 uint64_t FPToUInt64(double value
, FPRounding rmode
);
511 double FPMax(double a
, double b
);
512 double FPMin(double a
, double b
);
514 // Pseudo Printf instruction
515 void DoPrintf(Instruction
* instr
);
516 // Pseudo HostCall instruction
517 void DoHostCall(Instruction
* instr
);
519 // Processor state ---------------------------------------
522 std::ostream
& stream_
;
523 PrintDisassembler
* print_disasm_
;
525 // Instruction statistics instrumentation.
526 Instrument
* instrumentation_
;
528 // Hook to handle exceptions being thrown through simulated code.
529 ExceptionHook exception_hook_
= nullptr;
530 std::stack
<std::exception_ptr
> exns_in_flight_
;
532 // General purpose registers. Register 31 is the stack pointer.
533 SimRegister registers_
[kNumberOfRegisters
];
535 // Floating point registers
536 SimFPRegister fpregisters_
[kNumberOfFPRegisters
];
538 // Program Status Register.
539 // bits[31, 27]: Condition flags N, Z, C, and V.
540 // (Negative, Zero, Carry, Overflow)
541 SimSystemRegister nzcv_
;
543 // Floating-Point Control Register
544 SimSystemRegister fpcr_
;
546 // Only a subset of FPCR features are supported by the simulator. This helper
547 // checks that the FPCR settings are supported.
549 // This is checked when floating-point instructions are executed, not when
550 // FPCR is set. This allows generated code to modify FPCR for external
551 // functions, or to save and restore it when entering and leaving generated
553 void AssertSupportedFPCR() {
554 assert(fpcr().DN() == 0); // No default-NaN support.
555 assert(fpcr().FZ() == 0); // No flush-to-zero support.
556 assert(fpcr().RMode() == FPTieEven
); // Ties-to-even rounding only.
558 // The simulator does not support half-precision operations so fpcr().AHP()
559 // is irrelevant, and is not checked here.
562 static inline int CalcNFlag(uint64_t result
, unsigned reg_size
) {
563 return (result
>> (reg_size
- 1)) & 1;
566 static inline int CalcZFlag(uint64_t result
) {
570 static const uint32_t kConditionFlagsMask
= 0xf0000000;
574 static const int stack_protection_size_
= 256;
576 static const int stack_size_
= (512 << 10) + 2 * stack_protection_size_
;
580 // Indicates if the pc has been modified by the instruction and should not be
581 // automatically incremented.
585 // Counters for basic simulated-system events. Note that the load counter does
586 // not count instruction fetches, only explicit loads.
587 uint64_t load_count_
= 0;
588 uint64_t store_count_
= 0;
589 uint64_t instr_count_
= 0;
591 static const char* xreg_names
[];
592 static const char* wreg_names
[];
593 static const char* sreg_names
[];
594 static const char* dreg_names
[];
595 static const char* vreg_names
[];
597 static const Instruction
* kEndOfSimAddress
;
600 bool coloured_trace_
;
602 // Indicates whether the disassembly trace is active.
607 #endif // VIXL_A64_SIMULATOR_A64_H_