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