OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_ARM64_SIMULATOR_ARM64_H_ | 5 #ifndef V8_ARM64_SIMULATOR_ARM64_H_ |
6 #define V8_ARM64_SIMULATOR_ARM64_H_ | 6 #define V8_ARM64_SIMULATOR_ARM64_H_ |
7 | 7 |
8 #include <stdarg.h> | 8 #include <stdarg.h> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 | 68 |
69 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { | 69 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { |
70 return try_catch_address; | 70 return try_catch_address; |
71 } | 71 } |
72 | 72 |
73 static void UnregisterCTryCatch() { } | 73 static void UnregisterCTryCatch() { } |
74 }; | 74 }; |
75 | 75 |
76 #else // !defined(USE_SIMULATOR) | 76 #else // !defined(USE_SIMULATOR) |
77 | 77 |
78 | |
79 template<typename T> | |
80 struct make_unsigned { | |
81 typedef T type; | |
82 }; | |
83 | |
84 | |
78 enum ReverseByteMode { | 85 enum ReverseByteMode { |
79 Reverse16 = 0, | 86 Reverse16 = 0, |
80 Reverse32 = 1, | 87 Reverse32 = 1, |
81 Reverse64 = 2 | 88 Reverse64 = 2 |
82 }; | 89 }; |
83 | 90 |
84 | 91 |
85 // The proper way to initialize a simulated system register (such as NZCV) is as | 92 // The proper way to initialize a simulated system register (such as NZCV) is as |
86 // follows: | 93 // follows: |
87 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV); | 94 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 // describes the bits which are not modifiable. | 136 // describes the bits which are not modifiable. |
130 SimSystemRegister(uint32_t value, uint32_t write_ignore_mask) | 137 SimSystemRegister(uint32_t value, uint32_t write_ignore_mask) |
131 : value_(value), write_ignore_mask_(write_ignore_mask) { } | 138 : value_(value), write_ignore_mask_(write_ignore_mask) { } |
132 | 139 |
133 uint32_t value_; | 140 uint32_t value_; |
134 uint32_t write_ignore_mask_; | 141 uint32_t write_ignore_mask_; |
135 }; | 142 }; |
136 | 143 |
137 | 144 |
138 // Represent a register (r0-r31, v0-v31). | 145 // Represent a register (r0-r31, v0-v31). |
139 template<int kSizeInBytes> | |
140 class SimRegisterBase { | 146 class SimRegisterBase { |
141 public: | 147 public: |
142 template<typename T> | 148 void Set(int64_t new_value, unsigned size) { |
143 void Set(T new_value, unsigned size = sizeof(T)) { | 149 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); |
144 ASSERT(size <= kSizeInBytes); | |
145 ASSERT(size <= sizeof(new_value)); | |
146 // All AArch64 registers are zero-extending; Writing a W register clears the | 150 // All AArch64 registers are zero-extending; Writing a W register clears the |
147 // top bits of the corresponding X register. | 151 // top bits of the corresponding X register. |
148 memset(value_, 0, kSizeInBytes); | 152 value_ = new_value; |
Sven Panne
2014/05/16 11:15:47
A ternary is a bit more readable here:
value_ =
jbramley
2014/05/16 14:05:50
You probably need to set the value just once, to a
| |
149 memcpy(value_, &new_value, size); | 153 STATIC_ASSERT(kWRegSizeInBits == kSRegSizeInBits); |
154 if (size == kWRegSizeInBits) { | |
155 value_ &= kWRegMask; | |
156 } | |
jbramley
2014/05/16 14:05:50
else {
ASSERT(size == (sizeof(value_) * kByteSiz
| |
157 } | |
158 | |
159 template<typename T> | |
160 void Set(T new_value) { | |
Sven Panne
2014/05/16 11:15:47
This method and the corresponding templatized Get
jbramley
2014/05/16 14:05:50
Indeed; I'd like to see what you're aiming for. I
Fritz
2014/05/16 18:11:46
My direction is to only use the templatized Get/Se
| |
161 value_ = 0; | |
162 memcpy(&value_, &new_value, sizeof(T)); | |
150 } | 163 } |
151 | 164 |
152 // Copy 'size' bytes of the register to the result, and zero-extend to fill | 165 // Copy 'size' bytes of the register to the result, and zero-extend to fill |
153 // the result. | 166 // the result. |
167 int64_t Get(unsigned size) const { | |
168 ASSERT(size/8 <= kXRegSize); | |
169 int64_t result = value_; | |
Sven Panne
2014/05/16 11:15:47
I think a ternary is more readable here, too:
| |
170 if (size == kSRegSizeInBits) { | |
jbramley
2014/05/16 14:05:50
Use of SRegSize is surprising here; use WRegSize i
| |
171 result &= kSRegMask; | |
172 } | |
173 return result; | |
174 } | |
175 | |
154 template<typename T> | 176 template<typename T> |
155 T Get(unsigned size = sizeof(T)) const { | 177 T Get() const { |
156 ASSERT(size <= kSizeInBytes); | |
157 T result; | 178 T result; |
158 memset(&result, 0, sizeof(result)); | 179 memcpy(&result, &value_, sizeof(T)); |
159 memcpy(&result, value_, size); | |
160 return result; | 180 return result; |
161 } | 181 } |
162 | 182 |
163 protected: | 183 protected: |
164 uint8_t value_[kSizeInBytes]; | 184 int64_t value_; |
jbramley
2014/05/16 14:05:50
Have you thought about how NEON Q registers might
Fritz
2014/05/16 18:11:46
I don't have a fully formed solution yet. I do re
| |
165 }; | 185 }; |
166 typedef SimRegisterBase<kXRegSize> SimRegister; // r0-r31 | 186 |
167 typedef SimRegisterBase<kDRegSize> SimFPRegister; // v0-v31 | 187 STATIC_ASSERT(kXRegSize == kDRegSize); |
jbramley
2014/05/16 14:05:50
It'd be better to put this next to the declaration
| |
188 typedef SimRegisterBase SimRegister; // r0-r31 | |
189 typedef SimRegisterBase SimFPRegister; // v0-v31 | |
168 | 190 |
169 | 191 |
170 class Simulator : public DecoderVisitor { | 192 class Simulator : public DecoderVisitor { |
171 public: | 193 public: |
172 explicit Simulator(Decoder<DispatchingDecoderVisitor>* decoder, | 194 explicit Simulator(Decoder<DispatchingDecoderVisitor>* decoder, |
173 Isolate* isolate = NULL, | 195 Isolate* isolate = NULL, |
174 FILE* stream = stderr); | 196 FILE* stream = stderr); |
175 Simulator(); | 197 Simulator(); |
176 ~Simulator(); | 198 ~Simulator(); |
177 | 199 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 LogProcessorState(); | 346 LogProcessorState(); |
325 increment_pc(); | 347 increment_pc(); |
326 CheckBreakpoints(); | 348 CheckBreakpoints(); |
327 } | 349 } |
328 | 350 |
329 // Declare all Visitor functions. | 351 // Declare all Visitor functions. |
330 #define DECLARE(A) void Visit##A(Instruction* instr); | 352 #define DECLARE(A) void Visit##A(Instruction* instr); |
331 VISITOR_LIST(DECLARE) | 353 VISITOR_LIST(DECLARE) |
332 #undef DECLARE | 354 #undef DECLARE |
333 | 355 |
356 bool Reg31ZeroMode(unsigned code, Reg31Mode r31mode) const { | |
jbramley
2014/05/16 14:05:50
`IsZeroRegister(...)` would be a better name.
Fritz
2014/05/16 18:11:46
Done.
| |
357 return ((code == 31) && (r31mode == Reg31IsZeroRegister)); | |
358 } | |
359 | |
334 // Register accessors. | 360 // Register accessors. |
335 | |
336 // Return 'size' bits of the value of an integer register, as the specified | 361 // Return 'size' bits of the value of an integer register, as the specified |
337 // type. The value is zero-extended to fill the result. | 362 // type. The value is zero-extended to fill the result. |
338 // | 363 // |
339 // The only supported values of 'size' are kXRegSizeInBits and | 364 // The only supported values of 'size' are kXRegSizeInBits and |
340 // kWRegSizeInBits. | 365 // kWRegSizeInBits. |
341 template<typename T> | 366 int64_t reg(unsigned size, unsigned code, |
342 T reg(unsigned size, unsigned code, | |
343 Reg31Mode r31mode = Reg31IsZeroRegister) const { | 367 Reg31Mode r31mode = Reg31IsZeroRegister) const { |
344 unsigned size_in_bytes = size / 8; | |
345 ASSERT(size_in_bytes <= sizeof(T)); | |
346 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); | 368 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); |
347 ASSERT(code < kNumberOfRegisters); | 369 ASSERT(code < kNumberOfRegisters); |
348 | 370 |
349 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | 371 if (Reg31ZeroMode(code, r31mode)) { |
350 T result; | 372 return 0; |
351 memset(&result, 0, sizeof(result)); | |
352 return result; | |
353 } | 373 } |
354 return registers_[code].Get<T>(size_in_bytes); | 374 return registers_[code].Get(size); |
355 } | 375 } |
356 | 376 |
357 // Like reg(), but infer the access size from the template type. | 377 // Like reg(), but infer the access size from the template type. |
358 template<typename T> | 378 template<typename T> |
359 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | 379 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { |
360 return reg<T>(sizeof(T) * 8, code, r31mode); | 380 ASSERT(code < kNumberOfRegisters); |
381 if (Reg31ZeroMode(code, r31mode)) { | |
382 return 0; | |
383 } | |
384 return registers_[code].Get<T>(); | |
361 } | 385 } |
362 | 386 |
363 // Common specialized accessors for the reg() template. | 387 // Common specialized accessors for the reg() template. |
364 int32_t wreg(unsigned code, | 388 int32_t wreg(unsigned code, |
365 Reg31Mode r31mode = Reg31IsZeroRegister) const { | 389 Reg31Mode r31mode = Reg31IsZeroRegister) const { |
366 return reg<int32_t>(code, r31mode); | 390 return reg<int32_t>(code, r31mode); |
367 } | 391 } |
368 | 392 |
369 int64_t xreg(unsigned code, | 393 int64_t xreg(unsigned code, |
370 Reg31Mode r31mode = Reg31IsZeroRegister) const { | 394 Reg31Mode r31mode = Reg31IsZeroRegister) const { |
371 return reg<int64_t>(code, r31mode); | 395 return reg<int64_t>(code, r31mode); |
372 } | 396 } |
373 | 397 |
374 int64_t reg(unsigned size, unsigned code, | |
375 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
376 return reg<int64_t>(size, code, r31mode); | |
377 } | |
378 | |
379 // Write 'size' bits of 'value' into an integer register. The value is | 398 // Write 'size' bits of 'value' into an integer register. The value is |
380 // zero-extended. This behaviour matches AArch64 register writes. | 399 // zero-extended. This behaviour matches AArch64 register writes. |
381 // | 400 // |
382 // The only supported values of 'size' are kXRegSizeInBits and | 401 // The only supported values of 'size' are kXRegSizeInBits and |
383 // kWRegSizeInBits. | 402 // kWRegSizeInBits. |
384 template<typename T> | 403 template<typename T> |
385 void set_reg(unsigned size, unsigned code, T value, | 404 void set_reg(unsigned size, unsigned code, T value, |
386 Reg31Mode r31mode = Reg31IsZeroRegister) { | 405 Reg31Mode r31mode = Reg31IsZeroRegister) { |
387 unsigned size_in_bytes = size / 8; | |
388 ASSERT(size_in_bytes <= sizeof(T)); | |
389 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); | 406 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); |
390 ASSERT(code < kNumberOfRegisters); | 407 ASSERT(code < kNumberOfRegisters); |
391 | 408 |
392 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | 409 if (!Reg31ZeroMode(code, r31mode)) |
393 return; | 410 registers_[code].Set(value, size); |
394 } | |
395 return registers_[code].Set(value, size_in_bytes); | |
396 } | 411 } |
397 | 412 |
398 // Like set_reg(), but infer the access size from the template type. | 413 // Like set_reg(), but infer the access size from the template type. |
399 template<typename T> | 414 template<typename T> |
400 void set_reg(unsigned code, T value, | 415 void set_reg(unsigned code, T value, |
401 Reg31Mode r31mode = Reg31IsZeroRegister) { | 416 Reg31Mode r31mode = Reg31IsZeroRegister) { |
402 set_reg(sizeof(value) * 8, code, value, r31mode); | 417 ASSERT(code < kNumberOfRegisters); |
418 if (!Reg31ZeroMode(code, r31mode)) | |
419 registers_[code].Set(value); | |
403 } | 420 } |
404 | 421 |
405 // Common specialized accessors for the set_reg() template. | 422 // Common specialized accessors for the set_reg() template. |
406 void set_wreg(unsigned code, int32_t value, | 423 void set_wreg(unsigned code, int32_t value, |
407 Reg31Mode r31mode = Reg31IsZeroRegister) { | 424 Reg31Mode r31mode = Reg31IsZeroRegister) { |
408 set_reg(kWRegSizeInBits, code, value, r31mode); | 425 set_reg(code, value, r31mode); |
409 } | 426 } |
410 | 427 |
411 void set_xreg(unsigned code, int64_t value, | 428 void set_xreg(unsigned code, int64_t value, |
412 Reg31Mode r31mode = Reg31IsZeroRegister) { | 429 Reg31Mode r31mode = Reg31IsZeroRegister) { |
413 set_reg(kXRegSizeInBits, code, value, r31mode); | 430 set_reg(code, value, r31mode); |
414 } | 431 } |
415 | 432 |
416 // Commonly-used special cases. | 433 // Commonly-used special cases. |
417 template<typename T> | 434 template<typename T> |
418 void set_lr(T value) { | 435 void set_lr(T value) { |
419 ASSERT(sizeof(T) == kPointerSize); | 436 ASSERT(sizeof(T) == kPointerSize); |
420 set_reg(kLinkRegCode, value); | 437 set_reg(kLinkRegCode, value); |
421 } | 438 } |
422 | 439 |
423 template<typename T> | 440 template<typename T> |
424 void set_sp(T value) { | 441 void set_sp(T value) { |
425 ASSERT(sizeof(T) == kPointerSize); | 442 ASSERT(sizeof(T) == kPointerSize); |
426 set_reg(31, value, Reg31IsStackPointer); | 443 set_reg(31, value, Reg31IsStackPointer); |
427 } | 444 } |
428 | 445 |
429 int64_t sp() { return xreg(31, Reg31IsStackPointer); } | 446 int64_t sp() { return xreg(31, Reg31IsStackPointer); } |
430 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } | 447 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } |
431 int64_t fp() { | 448 int64_t fp() { |
432 return xreg(kFramePointerRegCode, Reg31IsStackPointer); | 449 return xreg(kFramePointerRegCode, Reg31IsStackPointer); |
433 } | 450 } |
434 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } | 451 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } |
435 | 452 |
436 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } | 453 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } |
437 | 454 |
438 // Return 'size' bits of the value of a floating-point register, as the | |
439 // specified type. The value is zero-extended to fill the result. | |
440 // | |
441 // The only supported values of 'size' are kDRegSizeInBits and | |
442 // kSRegSizeInBits. | |
443 template<typename T> | |
444 T fpreg(unsigned size, unsigned code) const { | |
445 unsigned size_in_bytes = size / 8; | |
446 ASSERT(size_in_bytes <= sizeof(T)); | |
447 ASSERT((size == kDRegSizeInBits) || (size == kSRegSizeInBits)); | |
448 ASSERT(code < kNumberOfFPRegisters); | |
449 return fpregisters_[code].Get<T>(size_in_bytes); | |
450 } | |
451 | |
452 // Like fpreg(), but infer the access size from the template type. | |
453 template<typename T> | 455 template<typename T> |
454 T fpreg(unsigned code) const { | 456 T fpreg(unsigned code) const { |
455 return fpreg<T>(sizeof(T) * 8, code); | 457 ASSERT(code < kNumberOfRegisters); |
458 return fpregisters_[code].Get<T>(); | |
456 } | 459 } |
457 | 460 |
458 // Common specialized accessors for the fpreg() template. | 461 // Common specialized accessors for the fpreg() template. |
459 float sreg(unsigned code) const { | 462 float sreg(unsigned code) const { |
460 return fpreg<float>(code); | 463 return fpreg<float>(code); |
461 } | 464 } |
462 | 465 |
463 uint32_t sreg_bits(unsigned code) const { | 466 uint32_t sreg_bits(unsigned code) const { |
464 return fpreg<uint32_t>(code); | 467 return fpreg<uint32_t>(code); |
465 } | 468 } |
(...skipping 15 matching lines...) Expand all Loading... | |
481 return 0.0; | 484 return 0.0; |
482 } | 485 } |
483 } | 486 } |
484 | 487 |
485 // Write 'value' into a floating-point register. The value is zero-extended. | 488 // Write 'value' into a floating-point register. The value is zero-extended. |
486 // This behaviour matches AArch64 register writes. | 489 // This behaviour matches AArch64 register writes. |
487 template<typename T> | 490 template<typename T> |
488 void set_fpreg(unsigned code, T value) { | 491 void set_fpreg(unsigned code, T value) { |
489 ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); | 492 ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); |
490 ASSERT(code < kNumberOfFPRegisters); | 493 ASSERT(code < kNumberOfFPRegisters); |
491 fpregisters_[code].Set(value, sizeof(value)); | 494 fpregisters_[code].Set(value); |
492 } | 495 } |
493 | 496 |
494 // Common specialized accessors for the set_fpreg() template. | 497 // Common specialized accessors for the set_fpreg() template. |
495 void set_sreg(unsigned code, float value) { | 498 void set_sreg(unsigned code, float value) { |
496 set_fpreg(code, value); | 499 set_fpreg(code, value); |
497 } | 500 } |
498 | 501 |
499 void set_sreg_bits(unsigned code, uint32_t value) { | 502 void set_sreg_bits(unsigned code, uint32_t value) { |
500 set_fpreg(code, value); | 503 set_fpreg(code, value); |
501 } | 504 } |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
655 float MemoryReadFP32(uint8_t* address); | 658 float MemoryReadFP32(uint8_t* address); |
656 uint64_t MemoryRead64(uint8_t* address); | 659 uint64_t MemoryRead64(uint8_t* address); |
657 double MemoryReadFP64(uint8_t* address); | 660 double MemoryReadFP64(uint8_t* address); |
658 | 661 |
659 void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes); | 662 void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes); |
660 void MemoryWrite32(uint8_t* address, uint32_t value); | 663 void MemoryWrite32(uint8_t* address, uint32_t value); |
661 void MemoryWriteFP32(uint8_t* address, float value); | 664 void MemoryWriteFP32(uint8_t* address, float value); |
662 void MemoryWrite64(uint8_t* address, uint64_t value); | 665 void MemoryWrite64(uint8_t* address, uint64_t value); |
663 void MemoryWriteFP64(uint8_t* address, double value); | 666 void MemoryWriteFP64(uint8_t* address, double value); |
664 | 667 |
665 int64_t ShiftOperand(unsigned reg_size, | 668 |
666 int64_t value, | 669 template <typename T> |
667 Shift shift_type, | 670 T ShiftOperand(T value, |
668 unsigned amount); | 671 Shift shift_type, |
672 unsigned amount); | |
673 | |
674 template <typename T> | |
675 void DataProcessing2Source(Instruction* instr); | |
676 | |
669 int64_t Rotate(unsigned reg_width, | 677 int64_t Rotate(unsigned reg_width, |
670 int64_t value, | 678 int64_t value, |
671 Shift shift_type, | 679 Shift shift_type, |
672 unsigned amount); | 680 unsigned amount); |
673 int64_t ExtendValue(unsigned reg_width, | 681 int64_t ExtendValue(unsigned reg_width, |
674 int64_t value, | 682 int64_t value, |
675 Extend extend_type, | 683 Extend extend_type, |
676 unsigned left_shift = 0); | 684 unsigned left_shift = 0); |
677 | 685 |
678 uint64_t ReverseBits(uint64_t value, unsigned num_bits); | 686 uint64_t ReverseBits(uint64_t value, unsigned num_bits); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
880 static void UnregisterCTryCatch() { | 888 static void UnregisterCTryCatch() { |
881 Simulator::current(Isolate::Current())->PopAddress(); | 889 Simulator::current(Isolate::Current())->PopAddress(); |
882 } | 890 } |
883 }; | 891 }; |
884 | 892 |
885 #endif // !defined(USE_SIMULATOR) | 893 #endif // !defined(USE_SIMULATOR) |
886 | 894 |
887 } } // namespace v8::internal | 895 } } // namespace v8::internal |
888 | 896 |
889 #endif // V8_ARM64_SIMULATOR_ARM64_H_ | 897 #endif // V8_ARM64_SIMULATOR_ARM64_H_ |
OLD | NEW |