1 // Copyright 2015, VIXL authors
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 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
28
29 #include <cmath>
30 #include <cstring>
31 #include <limits>
32
33 #include "simulator-aarch64.h"
34
35 namespace vixl {
36 namespace aarch64 {
37
38 using vixl::internal::SimFloat16;
39
40 const Instruction* Simulator::kEndOfSimAddress = NULL;
41
SetBits(int msb,int lsb,uint32_t bits)42 void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
43 int width = msb - lsb + 1;
44 VIXL_ASSERT(IsUintN(width, bits) || IsIntN(width, bits));
45
46 bits <<= lsb;
47 uint32_t mask = ((1 << width) - 1) << lsb;
48 VIXL_ASSERT((mask & write_ignore_mask_) == 0);
49
50 value_ = (value_ & ~mask) | (bits & mask);
51 }
52
53
DefaultValueFor(SystemRegister id)54 SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
55 switch (id) {
56 case NZCV:
57 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
58 case FPCR:
59 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
60 default:
61 VIXL_UNREACHABLE();
62 return SimSystemRegister();
63 }
64 }
65
66
Simulator(Decoder * decoder,FILE * stream)67 Simulator::Simulator(Decoder* decoder, FILE* stream)
68 : cpu_features_auditor_(decoder, CPUFeatures::All()) {
69 // Ensure that shift operations act as the simulator expects.
70 VIXL_ASSERT((static_cast<int32_t>(-1) >> 1) == -1);
71 VIXL_ASSERT((static_cast<uint32_t>(-1) >> 1) == 0x7fffffff);
72
73 instruction_stats_ = false;
74
75 // Set up the decoder.
76 decoder_ = decoder;
77 decoder_->AppendVisitor(this);
78
79 stream_ = stream;
80
81 print_disasm_ = new PrintDisassembler(stream_);
82 // The Simulator and Disassembler share the same available list, held by the
83 // auditor. The Disassembler only annotates instructions with features that
84 // are _not_ available, so registering the auditor should have no effect
85 // unless the simulator is about to abort (due to missing features). In
86 // practice, this means that with trace enabled, the simulator will crash just
87 // after the disassembler prints the instruction, with the missing features
88 // enumerated.
89 print_disasm_->RegisterCPUFeaturesAuditor(&cpu_features_auditor_);
90
91 SetColouredTrace(false);
92 trace_parameters_ = LOG_NONE;
93
94 ResetState();
95
96 // Allocate and set up the simulator stack.
97 stack_ = new byte[stack_size_];
98 stack_limit_ = stack_ + stack_protection_size_;
99 // Configure the starting stack pointer.
100 // - Find the top of the stack.
101 byte* tos = stack_ + stack_size_;
102 // - There's a protection region at both ends of the stack.
103 tos -= stack_protection_size_;
104 // - The stack pointer must be 16-byte aligned.
105 tos = AlignDown(tos, 16);
106 WriteSp(tos);
107
108 instrumentation_ = NULL;
109
110 // Print a warning about exclusive-access instructions, but only the first
111 // time they are encountered. This warning can be silenced using
112 // SilenceExclusiveAccessWarning().
113 print_exclusive_access_warning_ = true;
114 }
115
116
ResetState()117 void Simulator::ResetState() {
118 // Reset the system registers.
119 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
120 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
121
122 // Reset registers to 0.
123 pc_ = NULL;
124 pc_modified_ = false;
125 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
126 WriteXRegister(i, 0xbadbeef);
127 }
128 // Set FP registers to a value that is a NaN in both 32-bit and 64-bit FP.
129 uint64_t nan_bits[] = {
130 UINT64_C(0x7ff00cab7f8ba9e1), UINT64_C(0x7ff0dead7f8beef1),
131 };
132 VIXL_ASSERT(IsSignallingNaN(RawbitsToDouble(nan_bits[0] & kDRegMask)));
133 VIXL_ASSERT(IsSignallingNaN(RawbitsToFloat(nan_bits[0] & kSRegMask)));
134
135 qreg_t q_bits;
136 VIXL_ASSERT(sizeof(q_bits) == sizeof(nan_bits));
137 memcpy(&q_bits, nan_bits, sizeof(nan_bits));
138
139 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
140 WriteQRegister(i, q_bits);
141 }
142 // Returning to address 0 exits the Simulator.
143 WriteLr(kEndOfSimAddress);
144 }
145
146
~Simulator()147 Simulator::~Simulator() {
148 delete[] stack_;
149 // The decoder may outlive the simulator.
150 decoder_->RemoveVisitor(print_disasm_);
151 delete print_disasm_;
152
153 decoder_->RemoveVisitor(instrumentation_);
154 delete instrumentation_;
155 }
156
157
Run()158 void Simulator::Run() {
159 // Flush any written registers before executing anything, so that
160 // manually-set registers are logged _before_ the first instruction.
161 LogAllWrittenRegisters();
162
163 while (pc_ != kEndOfSimAddress) {
164 ExecuteInstruction();
165 }
166 }
167
168
RunFrom(const Instruction * first)169 void Simulator::RunFrom(const Instruction* first) {
170 WritePc(first, NoBranchLog);
171 Run();
172 }
173
174
175 const char* Simulator::xreg_names[] = {"x0", "x1", "x2", "x3", "x4", "x5",
176 "x6", "x7", "x8", "x9", "x10", "x11",
177 "x12", "x13", "x14", "x15", "x16", "x17",
178 "x18", "x19", "x20", "x21", "x22", "x23",
179 "x24", "x25", "x26", "x27", "x28", "x29",
180 "lr", "xzr", "sp"};
181
182 const char* Simulator::wreg_names[] = {"w0", "w1", "w2", "w3", "w4", "w5",
183 "w6", "w7", "w8", "w9", "w10", "w11",
184 "w12", "w13", "w14", "w15", "w16", "w17",
185 "w18", "w19", "w20", "w21", "w22", "w23",
186 "w24", "w25", "w26", "w27", "w28", "w29",
187 "w30", "wzr", "wsp"};
188
189 const char* Simulator::hreg_names[] = {"h0", "h1", "h2", "h3", "h4", "h5",
190 "h6", "h7", "h8", "h9", "h10", "h11",
191 "h12", "h13", "h14", "h15", "h16", "h17",
192 "h18", "h19", "h20", "h21", "h22", "h23",
193 "h24", "h25", "h26", "h27", "h28", "h29",
194 "h30", "h31"};
195
196 const char* Simulator::sreg_names[] = {"s0", "s1", "s2", "s3", "s4", "s5",
197 "s6", "s7", "s8", "s9", "s10", "s11",
198 "s12", "s13", "s14", "s15", "s16", "s17",
199 "s18", "s19", "s20", "s21", "s22", "s23",
200 "s24", "s25", "s26", "s27", "s28", "s29",
201 "s30", "s31"};
202
203 const char* Simulator::dreg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5",
204 "d6", "d7", "d8", "d9", "d10", "d11",
205 "d12", "d13", "d14", "d15", "d16", "d17",
206 "d18", "d19", "d20", "d21", "d22", "d23",
207 "d24", "d25", "d26", "d27", "d28", "d29",
208 "d30", "d31"};
209
210 const char* Simulator::vreg_names[] = {"v0", "v1", "v2", "v3", "v4", "v5",
211 "v6", "v7", "v8", "v9", "v10", "v11",
212 "v12", "v13", "v14", "v15", "v16", "v17",
213 "v18", "v19", "v20", "v21", "v22", "v23",
214 "v24", "v25", "v26", "v27", "v28", "v29",
215 "v30", "v31"};
216
217
WRegNameForCode(unsigned code,Reg31Mode mode)218 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
219 VIXL_ASSERT(code < kNumberOfRegisters);
220 // If the code represents the stack pointer, index the name after zr.
221 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
222 code = kZeroRegCode + 1;
223 }
224 return wreg_names[code];
225 }
226
227
XRegNameForCode(unsigned code,Reg31Mode mode)228 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
229 VIXL_ASSERT(code < kNumberOfRegisters);
230 // If the code represents the stack pointer, index the name after zr.
231 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
232 code = kZeroRegCode + 1;
233 }
234 return xreg_names[code];
235 }
236
237
HRegNameForCode(unsigned code)238 const char* Simulator::HRegNameForCode(unsigned code) {
239 VIXL_ASSERT(code < kNumberOfFPRegisters);
240 return hreg_names[code];
241 }
242
243
SRegNameForCode(unsigned code)244 const char* Simulator::SRegNameForCode(unsigned code) {
245 VIXL_ASSERT(code < kNumberOfFPRegisters);
246 return sreg_names[code];
247 }
248
249
DRegNameForCode(unsigned code)250 const char* Simulator::DRegNameForCode(unsigned code) {
251 VIXL_ASSERT(code < kNumberOfFPRegisters);
252 return dreg_names[code];
253 }
254
255
VRegNameForCode(unsigned code)256 const char* Simulator::VRegNameForCode(unsigned code) {
257 VIXL_ASSERT(code < kNumberOfVRegisters);
258 return vreg_names[code];
259 }
260
261
262 #define COLOUR(colour_code) "\033[0;" colour_code "m"
263 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
264 #define COLOUR_HIGHLIGHT "\033[43m"
265 #define NORMAL ""
266 #define GREY "30"
267 #define RED "31"
268 #define GREEN "32"
269 #define YELLOW "33"
270 #define BLUE "34"
271 #define MAGENTA "35"
272 #define CYAN "36"
273 #define WHITE "37"
SetColouredTrace(bool value)274 void Simulator::SetColouredTrace(bool value) {
275 coloured_trace_ = value;
276
277 clr_normal = value ? COLOUR(NORMAL) : "";
278 clr_flag_name = value ? COLOUR_BOLD(WHITE) : "";
279 clr_flag_value = value ? COLOUR(NORMAL) : "";
280 clr_reg_name = value ? COLOUR_BOLD(CYAN) : "";
281 clr_reg_value = value ? COLOUR(CYAN) : "";
282 clr_vreg_name = value ? COLOUR_BOLD(MAGENTA) : "";
283 clr_vreg_value = value ? COLOUR(MAGENTA) : "";
284 clr_memory_address = value ? COLOUR_BOLD(BLUE) : "";
285 clr_warning = value ? COLOUR_BOLD(YELLOW) : "";
286 clr_warning_message = value ? COLOUR(YELLOW) : "";
287 clr_printf = value ? COLOUR(GREEN) : "";
288 clr_branch_marker = value ? COLOUR(GREY) COLOUR_HIGHLIGHT : "";
289
290 if (value) {
291 print_disasm_->SetCPUFeaturesPrefix("// Needs: " COLOUR_BOLD(RED));
292 print_disasm_->SetCPUFeaturesSuffix(COLOUR(NORMAL));
293 } else {
294 print_disasm_->SetCPUFeaturesPrefix("// Needs: ");
295 print_disasm_->SetCPUFeaturesSuffix("");
296 }
297 }
298
299
SetTraceParameters(int parameters)300 void Simulator::SetTraceParameters(int parameters) {
301 bool disasm_before = trace_parameters_ & LOG_DISASM;
302 trace_parameters_ = parameters;
303 bool disasm_after = trace_parameters_ & LOG_DISASM;
304
305 if (disasm_before != disasm_after) {
306 if (disasm_after) {
307 decoder_->InsertVisitorBefore(print_disasm_, this);
308 } else {
309 decoder_->RemoveVisitor(print_disasm_);
310 }
311 }
312 }
313
314
SetInstructionStats(bool value)315 void Simulator::SetInstructionStats(bool value) {
316 if (value != instruction_stats_) {
317 if (value) {
318 if (instrumentation_ == NULL) {
319 // Set the sample period to 10, as the VIXL examples and tests are
320 // short.
321 instrumentation_ = new Instrument("vixl_stats.csv", 10);
322 }
323 decoder_->AppendVisitor(instrumentation_);
324 } else if (instrumentation_ != NULL) {
325 decoder_->RemoveVisitor(instrumentation_);
326 }
327 instruction_stats_ = value;
328 }
329 }
330
331 // Helpers ---------------------------------------------------------------------
AddWithCarry(unsigned reg_size,bool set_flags,uint64_t left,uint64_t right,int carry_in)332 uint64_t Simulator::AddWithCarry(unsigned reg_size,
333 bool set_flags,
334 uint64_t left,
335 uint64_t right,
336 int carry_in) {
337 VIXL_ASSERT((carry_in == 0) || (carry_in == 1));
338 VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));
339
340 uint64_t max_uint = (reg_size == kWRegSize) ? kWMaxUInt : kXMaxUInt;
341 uint64_t reg_mask = (reg_size == kWRegSize) ? kWRegMask : kXRegMask;
342 uint64_t sign_mask = (reg_size == kWRegSize) ? kWSignMask : kXSignMask;
343
344 left &= reg_mask;
345 right &= reg_mask;
346 uint64_t result = (left + right + carry_in) & reg_mask;
347
348 if (set_flags) {
349 ReadNzcv().SetN(CalcNFlag(result, reg_size));
350 ReadNzcv().SetZ(CalcZFlag(result));
351
352 // Compute the C flag by comparing the result to the max unsigned integer.
353 uint64_t max_uint_2op = max_uint - carry_in;
354 bool C = (left > max_uint_2op) || ((max_uint_2op - left) < right);
355 ReadNzcv().SetC(C ? 1 : 0);
356
357 // Overflow iff the sign bit is the same for the two inputs and different
358 // for the result.
359 uint64_t left_sign = left & sign_mask;
360 uint64_t right_sign = right & sign_mask;
361 uint64_t result_sign = result & sign_mask;
362 bool V = (left_sign == right_sign) && (left_sign != result_sign);
363 ReadNzcv().SetV(V ? 1 : 0);
364
365 LogSystemRegister(NZCV);
366 }
367 return result;
368 }
369
370
ShiftOperand(unsigned reg_size,int64_t value,Shift shift_type,unsigned amount) const371 int64_t Simulator::ShiftOperand(unsigned reg_size,
372 int64_t value,
373 Shift shift_type,
374 unsigned amount) const {
375 VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
376 if (amount == 0) {
377 return value;
378 }
379 uint64_t uvalue = static_cast<uint64_t>(value);
380 uint64_t mask = kWRegMask;
381 bool is_negative = (uvalue & kWSignMask) != 0;
382 if (reg_size == kXRegSize) {
383 mask = kXRegMask;
384 is_negative = (uvalue & kXSignMask) != 0;
385 }
386
387 switch (shift_type) {
388 case LSL:
389 uvalue <<= amount;
390 break;
391 case LSR:
392 uvalue >>= amount;
393 break;
394 case ASR:
395 uvalue >>= amount;
396 if (is_negative) {
397 // Simulate sign-extension to 64 bits.
398 uvalue |= ~UINT64_C(0) << (reg_size - amount);
399 }
400 break;
401 case ROR: {
402 uvalue = RotateRight(uvalue, amount, reg_size);
403 break;
404 }
405 default:
406 VIXL_UNIMPLEMENTED();
407 return 0;
408 }
409 uvalue &= mask;
410
411 int64_t result;
412 memcpy(&result, &uvalue, sizeof(result));
413 return result;
414 }
415
416
ExtendValue(unsigned reg_size,int64_t value,Extend extend_type,unsigned left_shift) const417 int64_t Simulator::ExtendValue(unsigned reg_size,
418 int64_t value,
419 Extend extend_type,
420 unsigned left_shift) const {
421 switch (extend_type) {
422 case UXTB:
423 value &= kByteMask;
424 break;
425 case UXTH:
426 value &= kHalfWordMask;
427 break;
428 case UXTW:
429 value &= kWordMask;
430 break;
431 case SXTB:
432 value &= kByteMask;
433 if ((value & 0x80) != 0) {
434 value |= ~UINT64_C(0) << 8;
435 }
436 break;
437 case SXTH:
438 value &= kHalfWordMask;
439 if ((value & 0x8000) != 0) {
440 value |= ~UINT64_C(0) << 16;
441 }
442 break;
443 case SXTW:
444 value &= kWordMask;
445 if ((value & 0x80000000) != 0) {
446 value |= ~UINT64_C(0) << 32;
447 }
448 break;
449 case UXTX:
450 case SXTX:
451 break;
452 default:
453 VIXL_UNREACHABLE();
454 }
455 return ShiftOperand(reg_size, value, LSL, left_shift);
456 }
457
458
FPCompare(double val0,double val1,FPTrapFlags trap)459 void Simulator::FPCompare(double val0, double val1, FPTrapFlags trap) {
460 AssertSupportedFPCR();
461
462 // TODO: This assumes that the C++ implementation handles comparisons in the
463 // way that we expect (as per AssertSupportedFPCR()).
464 bool process_exception = false;
465 if ((IsNaN(val0) != 0) || (IsNaN(val1) != 0)) {
466 ReadNzcv().SetRawValue(FPUnorderedFlag);
467 if (IsSignallingNaN(val0) || IsSignallingNaN(val1) ||
468 (trap == EnableTrap)) {
469 process_exception = true;
470 }
471 } else if (val0 < val1) {
472 ReadNzcv().SetRawValue(FPLessThanFlag);
473 } else if (val0 > val1) {
474 ReadNzcv().SetRawValue(FPGreaterThanFlag);
475 } else if (val0 == val1) {
476 ReadNzcv().SetRawValue(FPEqualFlag);
477 } else {
478 VIXL_UNREACHABLE();
479 }
480 LogSystemRegister(NZCV);
481 if (process_exception) FPProcessException();
482 }
483
484
ComputeMemOperandAddress(const MemOperand & mem_op) const485 uint64_t Simulator::ComputeMemOperandAddress(const MemOperand& mem_op) const {
486 VIXL_ASSERT(mem_op.IsValid());
487 int64_t base = ReadRegister<int64_t>(mem_op.GetBaseRegister());
488 if (mem_op.IsImmediateOffset()) {
489 return base + mem_op.GetOffset();
490 } else {
491 VIXL_ASSERT(mem_op.GetRegisterOffset().IsValid());
492 int64_t offset = ReadRegister<int64_t>(mem_op.GetRegisterOffset());
493 unsigned shift_amount = mem_op.GetShiftAmount();
494 if (mem_op.GetShift() != NO_SHIFT) {
495 offset = ShiftOperand(kXRegSize, offset, mem_op.GetShift(), shift_amount);
496 }
497 if (mem_op.GetExtend() != NO_EXTEND) {
498 offset = ExtendValue(kXRegSize, offset, mem_op.GetExtend(), shift_amount);
499 }
500 return static_cast<uint64_t>(base + offset);
501 }
502 }
503
504
GetPrintRegisterFormatForSize(unsigned reg_size,unsigned lane_size)505 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
506 unsigned reg_size, unsigned lane_size) {
507 VIXL_ASSERT(reg_size >= lane_size);
508
509 uint32_t format = 0;
510 if (reg_size != lane_size) {
511 switch (reg_size) {
512 default:
513 VIXL_UNREACHABLE();
514 break;
515 case kQRegSizeInBytes:
516 format = kPrintRegAsQVector;
517 break;
518 case kDRegSizeInBytes:
519 format = kPrintRegAsDVector;
520 break;
521 }
522 }
523
524 switch (lane_size) {
525 default:
526 VIXL_UNREACHABLE();
527 break;
528 case kQRegSizeInBytes:
529 format |= kPrintReg1Q;
530 break;
531 case kDRegSizeInBytes:
532 format |= kPrintReg1D;
533 break;
534 case kSRegSizeInBytes:
535 format |= kPrintReg1S;
536 break;
537 case kHRegSizeInBytes:
538 format |= kPrintReg1H;
539 break;
540 case kBRegSizeInBytes:
541 format |= kPrintReg1B;
542 break;
543 }
544 // These sizes would be duplicate case labels.
545 VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes);
546 VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes);
547 VIXL_STATIC_ASSERT(kPrintXReg == kPrintReg1D);
548 VIXL_STATIC_ASSERT(kPrintWReg == kPrintReg1S);
549
550 return static_cast<PrintRegisterFormat>(format);
551 }
552
553
GetPrintRegisterFormat(VectorFormat vform)554 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
555 VectorFormat vform) {
556 switch (vform) {
557 default:
558 VIXL_UNREACHABLE();
559 return kPrintReg16B;
560 case kFormat16B:
561 return kPrintReg16B;
562 case kFormat8B:
563 return kPrintReg8B;
564 case kFormat8H:
565 return kPrintReg8H;
566 case kFormat4H:
567 return kPrintReg4H;
568 case kFormat4S:
569 return kPrintReg4S;
570 case kFormat2S:
571 return kPrintReg2S;
572 case kFormat2D:
573 return kPrintReg2D;
574 case kFormat1D:
575 return kPrintReg1D;
576
577 case kFormatB:
578 return kPrintReg1B;
579 case kFormatH:
580 return kPrintReg1H;
581 case kFormatS:
582 return kPrintReg1S;
583 case kFormatD:
584 return kPrintReg1D;
585 }
586 }
587
588
GetPrintRegisterFormatFP(VectorFormat vform)589 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatFP(
590 VectorFormat vform) {
591 switch (vform) {
592 default:
593 VIXL_UNREACHABLE();
594 return kPrintReg16B;
595 case kFormat8H:
596 return kPrintReg8HFP;
597 case kFormat4H:
598 return kPrintReg4HFP;
599 case kFormat4S:
600 return kPrintReg4SFP;
601 case kFormat2S:
602 return kPrintReg2SFP;
603 case kFormat2D:
604 return kPrintReg2DFP;
605 case kFormat1D:
606 return kPrintReg1DFP;
607 case kFormatH:
608 return kPrintReg1HFP;
609 case kFormatS:
610 return kPrintReg1SFP;
611 case kFormatD:
612 return kPrintReg1DFP;
613 }
614 }
615
616
PrintWrittenRegisters()617 void Simulator::PrintWrittenRegisters() {
618 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
619 if (registers_[i].WrittenSinceLastLog()) PrintRegister(i);
620 }
621 }
622
623
PrintWrittenVRegisters()624 void Simulator::PrintWrittenVRegisters() {
625 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
626 // At this point there is no type information, so print as a raw 1Q.
627 if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q);
628 }
629 }
630
631
PrintSystemRegisters()632 void Simulator::PrintSystemRegisters() {
633 PrintSystemRegister(NZCV);
634 PrintSystemRegister(FPCR);
635 }
636
637
PrintRegisters()638 void Simulator::PrintRegisters() {
639 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
640 PrintRegister(i);
641 }
642 }
643
644
PrintVRegisters()645 void Simulator::PrintVRegisters() {
646 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
647 // At this point there is no type information, so print as a raw 1Q.
648 PrintVRegister(i, kPrintReg1Q);
649 }
650 }
651
652
653 // Print a register's name and raw value.
654 //
655 // Only the least-significant `size_in_bytes` bytes of the register are printed,
656 // but the value is aligned as if the whole register had been printed.
657 //
658 // For typical register updates, size_in_bytes should be set to kXRegSizeInBytes
659 // -- the default -- so that the whole register is printed. Other values of
660 // size_in_bytes are intended for use when the register hasn't actually been
661 // updated (such as in PrintWrite).
662 //
663 // No newline is printed. This allows the caller to print more details (such as
664 // a memory access annotation).
PrintRegisterRawHelper(unsigned code,Reg31Mode r31mode,int size_in_bytes)665 void Simulator::PrintRegisterRawHelper(unsigned code,
666 Reg31Mode r31mode,
667 int size_in_bytes) {
668 // The template for all supported sizes.
669 // "# x{code}: 0xffeeddccbbaa9988"
670 // "# w{code}: 0xbbaa9988"
671 // "# w{code}<15:0>: 0x9988"
672 // "# w{code}<7:0>: 0x88"
673 unsigned padding_chars = (kXRegSizeInBytes - size_in_bytes) * 2;
674
675 const char* name = "";
676 const char* suffix = "";
677 switch (size_in_bytes) {
678 case kXRegSizeInBytes:
679 name = XRegNameForCode(code, r31mode);
680 break;
681 case kWRegSizeInBytes:
682 name = WRegNameForCode(code, r31mode);
683 break;
684 case 2:
685 name = WRegNameForCode(code, r31mode);
686 suffix = "<15:0>";
687 padding_chars -= strlen(suffix);
688 break;
689 case 1:
690 name = WRegNameForCode(code, r31mode);
691 suffix = "<7:0>";
692 padding_chars -= strlen(suffix);
693 break;
694 default:
695 VIXL_UNREACHABLE();
696 }
697 fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix);
698
699 // Print leading padding spaces.
700 VIXL_ASSERT(padding_chars < (kXRegSizeInBytes * 2));
701 for (unsigned i = 0; i < padding_chars; i++) {
702 putc(' ', stream_);
703 }
704
705 // Print the specified bits in hexadecimal format.
706 uint64_t bits = ReadRegister<uint64_t>(code, r31mode);
707 bits &= kXRegMask >> ((kXRegSizeInBytes - size_in_bytes) * 8);
708 VIXL_STATIC_ASSERT(sizeof(bits) == kXRegSizeInBytes);
709
710 int chars = size_in_bytes * 2;
711 fprintf(stream_,
712 "%s0x%0*" PRIx64 "%s",
713 clr_reg_value,
714 chars,
715 bits,
716 clr_normal);
717 }
718
719
PrintRegister(unsigned code,Reg31Mode r31mode)720 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
721 registers_[code].NotifyRegisterLogged();
722
723 // Don't print writes into xzr.
724 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
725 return;
726 }
727
728 // The template for all x and w registers:
729 // "# x{code}: 0x{value}"
730 // "# w{code}: 0x{value}"
731
732 PrintRegisterRawHelper(code, r31mode);
733 fprintf(stream_, "\n");
734 }
735
736
737 // Print a register's name and raw value.
738 //
739 // The `bytes` and `lsb` arguments can be used to limit the bytes that are
740 // printed. These arguments are intended for use in cases where register hasn't
741 // actually been updated (such as in PrintVWrite).
742 //
743 // No newline is printed. This allows the caller to print more details (such as
744 // a floating-point interpretation or a memory access annotation).
PrintVRegisterRawHelper(unsigned code,int bytes,int lsb)745 void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) {
746 // The template for vector types:
747 // "# v{code}: 0xffeeddccbbaa99887766554433221100".
748 // An example with bytes=4 and lsb=8:
749 // "# v{code}: 0xbbaa9988 ".
750 fprintf(stream_,
751 "# %s%5s: %s",
752 clr_vreg_name,
753 VRegNameForCode(code),
754 clr_vreg_value);
755
756 int msb = lsb + bytes - 1;
757 int byte = kQRegSizeInBytes - 1;
758
759 // Print leading padding spaces. (Two spaces per byte.)
760 while (byte > msb) {
761 fprintf(stream_, " ");
762 byte--;
763 }
764
765 // Print the specified part of the value, byte by byte.
766 qreg_t rawbits = ReadQRegister(code);
767 fprintf(stream_, "0x");
768 while (byte >= lsb) {
769 fprintf(stream_, "%02x", rawbits.val[byte]);
770 byte--;
771 }
772
773 // Print trailing padding spaces.
774 while (byte >= 0) {
775 fprintf(stream_, " ");
776 byte--;
777 }
778 fprintf(stream_, "%s", clr_normal);
779 }
780
781
782 // Print each of the specified lanes of a register as a float or double value.
783 //
784 // The `lane_count` and `lslane` arguments can be used to limit the lanes that
785 // are printed. These arguments are intended for use in cases where register
786 // hasn't actually been updated (such as in PrintVWrite).
787 //
788 // No newline is printed. This allows the caller to print more details (such as
789 // a memory access annotation).
PrintVRegisterFPHelper(unsigned code,unsigned lane_size_in_bytes,int lane_count,int rightmost_lane)790 void Simulator::PrintVRegisterFPHelper(unsigned code,
791 unsigned lane_size_in_bytes,
792 int lane_count,
793 int rightmost_lane) {
794 VIXL_ASSERT((lane_size_in_bytes == kHRegSizeInBytes) ||
795 (lane_size_in_bytes == kSRegSizeInBytes) ||
796 (lane_size_in_bytes == kDRegSizeInBytes));
797
798 unsigned msb = ((lane_count + rightmost_lane) * lane_size_in_bytes);
799 VIXL_ASSERT(msb <= kQRegSizeInBytes);
800
801 // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register
802 // name is used:
803 // " (h{code}: {value})"
804 // " (s{code}: {value})"
805 // " (d{code}: {value})"
806 // For vector types, "..." is used to represent one or more omitted lanes.
807 // " (..., {value}, {value}, ...)"
808 if (lane_size_in_bytes == kHRegSizeInBytes) {
809 // TODO: Trace tests will fail until we regenerate them.
810 return;
811 }
812 if ((lane_count == 1) && (rightmost_lane == 0)) {
813 const char* name;
814 switch (lane_size_in_bytes) {
815 case kHRegSizeInBytes:
816 name = HRegNameForCode(code);
817 break;
818 case kSRegSizeInBytes:
819 name = SRegNameForCode(code);
820 break;
821 case kDRegSizeInBytes:
822 name = DRegNameForCode(code);
823 break;
824 default:
825 name = NULL;
826 VIXL_UNREACHABLE();
827 }
828 fprintf(stream_, " (%s%s: ", clr_vreg_name, name);
829 } else {
830 if (msb < (kQRegSizeInBytes - 1)) {
831 fprintf(stream_, " (..., ");
832 } else {
833 fprintf(stream_, " (");
834 }
835 }
836
837 // Print the list of values.
838 const char* separator = "";
839 int leftmost_lane = rightmost_lane + lane_count - 1;
840 for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) {
841 double value;
842 switch (lane_size_in_bytes) {
843 case kHRegSizeInBytes:
844 value = ReadVRegister(code).GetLane<uint16_t>(lane);
845 break;
846 case kSRegSizeInBytes:
847 value = ReadVRegister(code).GetLane<float>(lane);
848 break;
849 case kDRegSizeInBytes:
850 value = ReadVRegister(code).GetLane<double>(lane);
851 break;
852 default:
853 value = 0.0;
854 VIXL_UNREACHABLE();
855 }
856 if (IsNaN(value)) {
857 // The output for NaNs is implementation defined. Always print `nan`, so
858 // that traces are coherent across different implementations.
859 fprintf(stream_, "%s%snan%s", separator, clr_vreg_value, clr_normal);
860 } else {
861 fprintf(stream_,
862 "%s%s%#g%s",
863 separator,
864 clr_vreg_value,
865 value,
866 clr_normal);
867 }
868 separator = ", ";
869 }
870
871 if (rightmost_lane > 0) {
872 fprintf(stream_, ", ...");
873 }
874 fprintf(stream_, ")");
875 }
876
877
PrintVRegister(unsigned code,PrintRegisterFormat format)878 void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) {
879 vregisters_[code].NotifyRegisterLogged();
880
881 int lane_size_log2 = format & kPrintRegLaneSizeMask;
882
883 int reg_size_log2;
884 if (format & kPrintRegAsQVector) {
885 reg_size_log2 = kQRegSizeInBytesLog2;
886 } else if (format & kPrintRegAsDVector) {
887 reg_size_log2 = kDRegSizeInBytesLog2;
888 } else {
889 // Scalar types.
890 reg_size_log2 = lane_size_log2;
891 }
892
893 int lane_count = 1 << (reg_size_log2 - lane_size_log2);
894 int lane_size = 1 << lane_size_log2;
895
896 // The template for vector types:
897 // "# v{code}: 0x{rawbits} (..., {value}, ...)".
898 // The template for scalar types:
899 // "# v{code}: 0x{rawbits} ({reg}:{value})".
900 // The values in parentheses after the bit representations are floating-point
901 // interpretations. They are displayed only if the kPrintVRegAsFP bit is set.
902
903 PrintVRegisterRawHelper(code);
904 if (format & kPrintRegAsFP) {
905 PrintVRegisterFPHelper(code, lane_size, lane_count);
906 }
907
908 fprintf(stream_, "\n");
909 }
910
911
PrintSystemRegister(SystemRegister id)912 void Simulator::PrintSystemRegister(SystemRegister id) {
913 switch (id) {
914 case NZCV:
915 fprintf(stream_,
916 "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
917 clr_flag_name,
918 clr_flag_value,
919 ReadNzcv().GetN(),
920 ReadNzcv().GetZ(),
921 ReadNzcv().GetC(),
922 ReadNzcv().GetV(),
923 clr_normal);
924 break;
925 case FPCR: {
926 static const char* rmode[] = {"0b00 (Round to Nearest)",
927 "0b01 (Round towards Plus Infinity)",
928 "0b10 (Round towards Minus Infinity)",
929 "0b11 (Round towards Zero)"};
930 VIXL_ASSERT(ReadFpcr().GetRMode() < ArrayLength(rmode));
931 fprintf(stream_,
932 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
933 clr_flag_name,
934 clr_flag_value,
935 ReadFpcr().GetAHP(),
936 ReadFpcr().GetDN(),
937 ReadFpcr().GetFZ(),
938 rmode[ReadFpcr().GetRMode()],
939 clr_normal);
940 break;
941 }
942 default:
943 VIXL_UNREACHABLE();
944 }
945 }
946
947
PrintRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)948 void Simulator::PrintRead(uintptr_t address,
949 unsigned reg_code,
950 PrintRegisterFormat format) {
951 registers_[reg_code].NotifyRegisterLogged();
952
953 USE(format);
954
955 // The template is "# {reg}: 0x{value} <- {address}".
956 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister);
957 fprintf(stream_,
958 " <- %s0x%016" PRIxPTR "%s\n",
959 clr_memory_address,
960 address,
961 clr_normal);
962 }
963
964
PrintVRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)965 void Simulator::PrintVRead(uintptr_t address,
966 unsigned reg_code,
967 PrintRegisterFormat format,
968 unsigned lane) {
969 vregisters_[reg_code].NotifyRegisterLogged();
970
971 // The template is "# v{code}: 0x{rawbits} <- address".
972 PrintVRegisterRawHelper(reg_code);
973 if (format & kPrintRegAsFP) {
974 PrintVRegisterFPHelper(reg_code,
975 GetPrintRegLaneSizeInBytes(format),
976 GetPrintRegLaneCount(format),
977 lane);
978 }
979 fprintf(stream_,
980 " <- %s0x%016" PRIxPTR "%s\n",
981 clr_memory_address,
982 address,
983 clr_normal);
984 }
985
986
PrintWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)987 void Simulator::PrintWrite(uintptr_t address,
988 unsigned reg_code,
989 PrintRegisterFormat format) {
990 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
991
992 // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy
993 // and readable, the value is aligned with the values in the register trace.
994 PrintRegisterRawHelper(reg_code,
995 Reg31IsZeroRegister,
996 GetPrintRegSizeInBytes(format));
997 fprintf(stream_,
998 " -> %s0x%016" PRIxPTR "%s\n",
999 clr_memory_address,
1000 address,
1001 clr_normal);
1002 }
1003
1004
PrintVWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)1005 void Simulator::PrintVWrite(uintptr_t address,
1006 unsigned reg_code,
1007 PrintRegisterFormat format,
1008 unsigned lane) {
1009 // The templates:
1010 // "# v{code}: 0x{rawbits} -> {address}"
1011 // "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}".
1012 // "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}"
1013 // Because this trace doesn't represent a change to the source register's
1014 // value, only the relevant part of the value is printed. To keep the trace
1015 // tidy and readable, the raw value is aligned with the other values in the
1016 // register trace.
1017 int lane_count = GetPrintRegLaneCount(format);
1018 int lane_size = GetPrintRegLaneSizeInBytes(format);
1019 int reg_size = GetPrintRegSizeInBytes(format);
1020 PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane);
1021 if (format & kPrintRegAsFP) {
1022 PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane);
1023 }
1024 fprintf(stream_,
1025 " -> %s0x%016" PRIxPTR "%s\n",
1026 clr_memory_address,
1027 address,
1028 clr_normal);
1029 }
1030
1031
PrintTakenBranch(const Instruction * target)1032 void Simulator::PrintTakenBranch(const Instruction* target) {
1033 fprintf(stream_,
1034 "# %sBranch%s to 0x%016" PRIx64 ".\n",
1035 clr_branch_marker,
1036 clr_normal,
1037 reinterpret_cast<uint64_t>(target));
1038 }
1039
1040
1041 // Visitors---------------------------------------------------------------------
1042
VisitUnimplemented(const Instruction * instr)1043 void Simulator::VisitUnimplemented(const Instruction* instr) {
1044 printf("Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
1045 reinterpret_cast<const void*>(instr),
1046 instr->GetInstructionBits());
1047 VIXL_UNIMPLEMENTED();
1048 }
1049
1050
VisitUnallocated(const Instruction * instr)1051 void Simulator::VisitUnallocated(const Instruction* instr) {
1052 printf("Unallocated instruction at %p: 0x%08" PRIx32 "\n",
1053 reinterpret_cast<const void*>(instr),
1054 instr->GetInstructionBits());
1055 VIXL_UNIMPLEMENTED();
1056 }
1057
1058
VisitPCRelAddressing(const Instruction * instr)1059 void Simulator::VisitPCRelAddressing(const Instruction* instr) {
1060 VIXL_ASSERT((instr->Mask(PCRelAddressingMask) == ADR) ||
1061 (instr->Mask(PCRelAddressingMask) == ADRP));
1062
1063 WriteRegister(instr->GetRd(), instr->GetImmPCOffsetTarget());
1064 }
1065
1066
VisitUnconditionalBranch(const Instruction * instr)1067 void Simulator::VisitUnconditionalBranch(const Instruction* instr) {
1068 switch (instr->Mask(UnconditionalBranchMask)) {
1069 case BL:
1070 WriteLr(instr->GetNextInstruction());
1071 VIXL_FALLTHROUGH();
1072 case B:
1073 WritePc(instr->GetImmPCOffsetTarget());
1074 break;
1075 default:
1076 VIXL_UNREACHABLE();
1077 }
1078 }
1079
1080
VisitConditionalBranch(const Instruction * instr)1081 void Simulator::VisitConditionalBranch(const Instruction* instr) {
1082 VIXL_ASSERT(instr->Mask(ConditionalBranchMask) == B_cond);
1083 if (ConditionPassed(instr->GetConditionBranch())) {
1084 WritePc(instr->GetImmPCOffsetTarget());
1085 }
1086 }
1087
1088
VisitUnconditionalBranchToRegister(const Instruction * instr)1089 void Simulator::VisitUnconditionalBranchToRegister(const Instruction* instr) {
1090 bool authenticate = false;
1091 bool link = false;
1092 uint64_t addr = 0;
1093 uint64_t context = 0;
1094 Instruction* target;
1095
1096 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1097 case BLR:
1098 link = true;
1099 VIXL_FALLTHROUGH();
1100 case BR:
1101 case RET:
1102 addr = ReadXRegister(instr->GetRn());
1103 break;
1104
1105 case BLRAAZ:
1106 case BLRABZ:
1107 link = true;
1108 VIXL_FALLTHROUGH();
1109 case BRAAZ:
1110 case BRABZ:
1111 authenticate = true;
1112 addr = ReadXRegister(instr->GetRn());
1113 break;
1114
1115 case BLRAA:
1116 case BLRAB:
1117 link = true;
1118 VIXL_FALLTHROUGH();
1119 case BRAA:
1120 case BRAB:
1121 authenticate = true;
1122 addr = ReadXRegister(instr->GetRn());
1123 context = ReadXRegister(instr->GetRd());
1124 break;
1125
1126 case RETAA:
1127 case RETAB:
1128 authenticate = true;
1129 addr = ReadXRegister(kLinkRegCode);
1130 context = ReadXRegister(31, Reg31IsStackPointer);
1131 break;
1132 default:
1133 VIXL_UNREACHABLE();
1134 }
1135
1136 if (link) {
1137 WriteLr(instr->GetNextInstruction());
1138 }
1139
1140 if (authenticate) {
1141 PACKey key = (instr->ExtractBit(10) == 0) ? kPACKeyIA : kPACKeyIB;
1142 addr = AuthPAC(addr, context, key, kInstructionPointer);
1143
1144 int error_lsb = GetTopPACBit(addr, kInstructionPointer) - 2;
1145 if (((addr >> error_lsb) & 0x3) != 0x0) {
1146 VIXL_ABORT_WITH_MSG("Failed to authenticate pointer.");
1147 }
1148 }
1149
1150 target = Instruction::Cast(addr);
1151 WritePc(target);
1152 }
1153
1154
VisitTestBranch(const Instruction * instr)1155 void Simulator::VisitTestBranch(const Instruction* instr) {
1156 unsigned bit_pos =
1157 (instr->GetImmTestBranchBit5() << 5) | instr->GetImmTestBranchBit40();
1158 bool bit_zero = ((ReadXRegister(instr->GetRt()) >> bit_pos) & 1) == 0;
1159 bool take_branch = false;
1160 switch (instr->Mask(TestBranchMask)) {
1161 case TBZ:
1162 take_branch = bit_zero;
1163 break;
1164 case TBNZ:
1165 take_branch = !bit_zero;
1166 break;
1167 default:
1168 VIXL_UNIMPLEMENTED();
1169 }
1170 if (take_branch) {
1171 WritePc(instr->GetImmPCOffsetTarget());
1172 }
1173 }
1174
1175
VisitCompareBranch(const Instruction * instr)1176 void Simulator::VisitCompareBranch(const Instruction* instr) {
1177 unsigned rt = instr->GetRt();
1178 bool take_branch = false;
1179 switch (instr->Mask(CompareBranchMask)) {
1180 case CBZ_w:
1181 take_branch = (ReadWRegister(rt) == 0);
1182 break;
1183 case CBZ_x:
1184 take_branch = (ReadXRegister(rt) == 0);
1185 break;
1186 case CBNZ_w:
1187 take_branch = (ReadWRegister(rt) != 0);
1188 break;
1189 case CBNZ_x:
1190 take_branch = (ReadXRegister(rt) != 0);
1191 break;
1192 default:
1193 VIXL_UNIMPLEMENTED();
1194 }
1195 if (take_branch) {
1196 WritePc(instr->GetImmPCOffsetTarget());
1197 }
1198 }
1199
1200
AddSubHelper(const Instruction * instr,int64_t op2)1201 void Simulator::AddSubHelper(const Instruction* instr, int64_t op2) {
1202 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1203 bool set_flags = instr->GetFlagsUpdate();
1204 int64_t new_val = 0;
1205 Instr operation = instr->Mask(AddSubOpMask);
1206
1207 switch (operation) {
1208 case ADD:
1209 case ADDS: {
1210 new_val = AddWithCarry(reg_size,
1211 set_flags,
1212 ReadRegister(reg_size,
1213 instr->GetRn(),
1214 instr->GetRnMode()),
1215 op2);
1216 break;
1217 }
1218 case SUB:
1219 case SUBS: {
1220 new_val = AddWithCarry(reg_size,
1221 set_flags,
1222 ReadRegister(reg_size,
1223 instr->GetRn(),
1224 instr->GetRnMode()),
1225 ~op2,
1226 1);
1227 break;
1228 }
1229 default:
1230 VIXL_UNREACHABLE();
1231 }
1232
1233 WriteRegister(reg_size,
1234 instr->GetRd(),
1235 new_val,
1236 LogRegWrites,
1237 instr->GetRdMode());
1238 }
1239
1240
VisitAddSubShifted(const Instruction * instr)1241 void Simulator::VisitAddSubShifted(const Instruction* instr) {
1242 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1243 int64_t op2 = ShiftOperand(reg_size,
1244 ReadRegister(reg_size, instr->GetRm()),
1245 static_cast<Shift>(instr->GetShiftDP()),
1246 instr->GetImmDPShift());
1247 AddSubHelper(instr, op2);
1248 }
1249
1250
VisitAddSubImmediate(const Instruction * instr)1251 void Simulator::VisitAddSubImmediate(const Instruction* instr) {
1252 int64_t op2 = instr->GetImmAddSub()
1253 << ((instr->GetShiftAddSub() == 1) ? 12 : 0);
1254 AddSubHelper(instr, op2);
1255 }
1256
1257
VisitAddSubExtended(const Instruction * instr)1258 void Simulator::VisitAddSubExtended(const Instruction* instr) {
1259 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1260 int64_t op2 = ExtendValue(reg_size,
1261 ReadRegister(reg_size, instr->GetRm()),
1262 static_cast<Extend>(instr->GetExtendMode()),
1263 instr->GetImmExtendShift());
1264 AddSubHelper(instr, op2);
1265 }
1266
1267
VisitAddSubWithCarry(const Instruction * instr)1268 void Simulator::VisitAddSubWithCarry(const Instruction* instr) {
1269 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1270 int64_t op2 = ReadRegister(reg_size, instr->GetRm());
1271 int64_t new_val;
1272
1273 if ((instr->Mask(AddSubOpMask) == SUB) ||
1274 (instr->Mask(AddSubOpMask) == SUBS)) {
1275 op2 = ~op2;
1276 }
1277
1278 new_val = AddWithCarry(reg_size,
1279 instr->GetFlagsUpdate(),
1280 ReadRegister(reg_size, instr->GetRn()),
1281 op2,
1282 ReadC());
1283
1284 WriteRegister(reg_size, instr->GetRd(), new_val);
1285 }
1286
1287
VisitLogicalShifted(const Instruction * instr)1288 void Simulator::VisitLogicalShifted(const Instruction* instr) {
1289 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1290 Shift shift_type = static_cast<Shift>(instr->GetShiftDP());
1291 unsigned shift_amount = instr->GetImmDPShift();
1292 int64_t op2 = ShiftOperand(reg_size,
1293 ReadRegister(reg_size, instr->GetRm()),
1294 shift_type,
1295 shift_amount);
1296 if (instr->Mask(NOT) == NOT) {
1297 op2 = ~op2;
1298 }
1299 LogicalHelper(instr, op2);
1300 }
1301
1302
VisitLogicalImmediate(const Instruction * instr)1303 void Simulator::VisitLogicalImmediate(const Instruction* instr) {
1304 LogicalHelper(instr, instr->GetImmLogical());
1305 }
1306
1307
LogicalHelper(const Instruction * instr,int64_t op2)1308 void Simulator::LogicalHelper(const Instruction* instr, int64_t op2) {
1309 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1310 int64_t op1 = ReadRegister(reg_size, instr->GetRn());
1311 int64_t result = 0;
1312 bool update_flags = false;
1313
1314 // Switch on the logical operation, stripping out the NOT bit, as it has a
1315 // different meaning for logical immediate instructions.
1316 switch (instr->Mask(LogicalOpMask & ~NOT)) {
1317 case ANDS:
1318 update_flags = true;
1319 VIXL_FALLTHROUGH();
1320 case AND:
1321 result = op1 & op2;
1322 break;
1323 case ORR:
1324 result = op1 | op2;
1325 break;
1326 case EOR:
1327 result = op1 ^ op2;
1328 break;
1329 default:
1330 VIXL_UNIMPLEMENTED();
1331 }
1332
1333 if (update_flags) {
1334 ReadNzcv().SetN(CalcNFlag(result, reg_size));
1335 ReadNzcv().SetZ(CalcZFlag(result));
1336 ReadNzcv().SetC(0);
1337 ReadNzcv().SetV(0);
1338 LogSystemRegister(NZCV);
1339 }
1340
1341 WriteRegister(reg_size,
1342 instr->GetRd(),
1343 result,
1344 LogRegWrites,
1345 instr->GetRdMode());
1346 }
1347
1348
VisitConditionalCompareRegister(const Instruction * instr)1349 void Simulator::VisitConditionalCompareRegister(const Instruction* instr) {
1350 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1351 ConditionalCompareHelper(instr, ReadRegister(reg_size, instr->GetRm()));
1352 }
1353
1354
VisitConditionalCompareImmediate(const Instruction * instr)1355 void Simulator::VisitConditionalCompareImmediate(const Instruction* instr) {
1356 ConditionalCompareHelper(instr, instr->GetImmCondCmp());
1357 }
1358
1359
ConditionalCompareHelper(const Instruction * instr,int64_t op2)1360 void Simulator::ConditionalCompareHelper(const Instruction* instr,
1361 int64_t op2) {
1362 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
1363 int64_t op1 = ReadRegister(reg_size, instr->GetRn());
1364
1365 if (ConditionPassed(instr->GetCondition())) {
1366 // If the condition passes, set the status flags to the result of comparing
1367 // the operands.
1368 if (instr->Mask(ConditionalCompareMask) == CCMP) {
1369 AddWithCarry(reg_size, true, op1, ~op2, 1);
1370 } else {
1371 VIXL_ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
1372 AddWithCarry(reg_size, true, op1, op2, 0);
1373 }
1374 } else {
1375 // If the condition fails, set the status flags to the nzcv immediate.
1376 ReadNzcv().SetFlags(instr->GetNzcv());
1377 LogSystemRegister(NZCV);
1378 }
1379 }
1380
1381
VisitLoadStoreUnsignedOffset(const Instruction * instr)1382 void Simulator::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
1383 int offset = instr->GetImmLSUnsigned() << instr->GetSizeLS();
1384 LoadStoreHelper(instr, offset, Offset);
1385 }
1386
1387
VisitLoadStoreUnscaledOffset(const Instruction * instr)1388 void Simulator::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
1389 LoadStoreHelper(instr, instr->GetImmLS(), Offset);
1390 }
1391
1392
VisitLoadStorePreIndex(const Instruction * instr)1393 void Simulator::VisitLoadStorePreIndex(const Instruction* instr) {
1394 LoadStoreHelper(instr, instr->GetImmLS(), PreIndex);
1395 }
1396
1397
VisitLoadStorePostIndex(const Instruction * instr)1398 void Simulator::VisitLoadStorePostIndex(const Instruction* instr) {
1399 LoadStoreHelper(instr, instr->GetImmLS(), PostIndex);
1400 }
1401
1402
VisitLoadStoreRegisterOffset(const Instruction * instr)1403 void Simulator::VisitLoadStoreRegisterOffset(const Instruction* instr) {
1404 Extend ext = static_cast<Extend>(instr->GetExtendMode());
1405 VIXL_ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
1406 unsigned shift_amount = instr->GetImmShiftLS() * instr->GetSizeLS();
1407
1408 int64_t offset =
1409 ExtendValue(kXRegSize, ReadXRegister(instr->GetRm()), ext, shift_amount);
1410 LoadStoreHelper(instr, offset, Offset);
1411 }
1412
1413
LoadStoreHelper(const Instruction * instr,int64_t offset,AddrMode addrmode)1414 void Simulator::LoadStoreHelper(const Instruction* instr,
1415 int64_t offset,
1416 AddrMode addrmode) {
1417 unsigned srcdst = instr->GetRt();
1418 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addrmode);
1419
1420 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
1421 switch (op) {
1422 case LDRB_w:
1423 WriteWRegister(srcdst, Memory::Read<uint8_t>(address), NoRegLog);
1424 break;
1425 case LDRH_w:
1426 WriteWRegister(srcdst, Memory::Read<uint16_t>(address), NoRegLog);
1427 break;
1428 case LDR_w:
1429 WriteWRegister(srcdst, Memory::Read<uint32_t>(address), NoRegLog);
1430 break;
1431 case LDR_x:
1432 WriteXRegister(srcdst, Memory::Read<uint64_t>(address), NoRegLog);
1433 break;
1434 case LDRSB_w:
1435 WriteWRegister(srcdst, Memory::Read<int8_t>(address), NoRegLog);
1436 break;
1437 case LDRSH_w:
1438 WriteWRegister(srcdst, Memory::Read<int16_t>(address), NoRegLog);
1439 break;
1440 case LDRSB_x:
1441 WriteXRegister(srcdst, Memory::Read<int8_t>(address), NoRegLog);
1442 break;
1443 case LDRSH_x:
1444 WriteXRegister(srcdst, Memory::Read<int16_t>(address), NoRegLog);
1445 break;
1446 case LDRSW_x:
1447 WriteXRegister(srcdst, Memory::Read<int32_t>(address), NoRegLog);
1448 break;
1449 case LDR_b:
1450 WriteBRegister(srcdst, Memory::Read<uint8_t>(address), NoRegLog);
1451 break;
1452 case LDR_h:
1453 WriteHRegister(srcdst, Memory::Read<uint16_t>(address), NoRegLog);
1454 break;
1455 case LDR_s:
1456 WriteSRegister(srcdst, Memory::Read<float>(address), NoRegLog);
1457 break;
1458 case LDR_d:
1459 WriteDRegister(srcdst, Memory::Read<double>(address), NoRegLog);
1460 break;
1461 case LDR_q:
1462 WriteQRegister(srcdst, Memory::Read<qreg_t>(address), NoRegLog);
1463 break;
1464
1465 case STRB_w:
1466 Memory::Write<uint8_t>(address, ReadWRegister(srcdst));
1467 break;
1468 case STRH_w:
1469 Memory::Write<uint16_t>(address, ReadWRegister(srcdst));
1470 break;
1471 case STR_w:
1472 Memory::Write<uint32_t>(address, ReadWRegister(srcdst));
1473 break;
1474 case STR_x:
1475 Memory::Write<uint64_t>(address, ReadXRegister(srcdst));
1476 break;
1477 case STR_b:
1478 Memory::Write<uint8_t>(address, ReadBRegister(srcdst));
1479 break;
1480 case STR_h:
1481 Memory::Write<uint16_t>(address, ReadHRegisterBits(srcdst));
1482 break;
1483 case STR_s:
1484 Memory::Write<float>(address, ReadSRegister(srcdst));
1485 break;
1486 case STR_d:
1487 Memory::Write<double>(address, ReadDRegister(srcdst));
1488 break;
1489 case STR_q:
1490 Memory::Write<qreg_t>(address, ReadQRegister(srcdst));
1491 break;
1492
1493 // Ignore prfm hint instructions.
1494 case PRFM:
1495 break;
1496
1497 default:
1498 VIXL_UNIMPLEMENTED();
1499 }
1500
1501 unsigned access_size = 1 << instr->GetSizeLS();
1502 if (instr->IsLoad()) {
1503 if ((op == LDR_s) || (op == LDR_d)) {
1504 LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1505 } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) {
1506 LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1507 } else {
1508 LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1509 }
1510 } else if (instr->IsStore()) {
1511 if ((op == STR_s) || (op == STR_d)) {
1512 LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1513 } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) {
1514 LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1515 } else {
1516 LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1517 }
1518 } else {
1519 VIXL_ASSERT(op == PRFM);
1520 }
1521
1522 local_monitor_.MaybeClear();
1523 }
1524
1525
VisitLoadStorePairOffset(const Instruction * instr)1526 void Simulator::VisitLoadStorePairOffset(const Instruction* instr) {
1527 LoadStorePairHelper(instr, Offset);
1528 }
1529
1530
VisitLoadStorePairPreIndex(const Instruction * instr)1531 void Simulator::VisitLoadStorePairPreIndex(const Instruction* instr) {
1532 LoadStorePairHelper(instr, PreIndex);
1533 }
1534
1535
VisitLoadStorePairPostIndex(const Instruction * instr)1536 void Simulator::VisitLoadStorePairPostIndex(const Instruction* instr) {
1537 LoadStorePairHelper(instr, PostIndex);
1538 }
1539
1540
VisitLoadStorePairNonTemporal(const Instruction * instr)1541 void Simulator::VisitLoadStorePairNonTemporal(const Instruction* instr) {
1542 LoadStorePairHelper(instr, Offset);
1543 }
1544
1545
LoadStorePairHelper(const Instruction * instr,AddrMode addrmode)1546 void Simulator::LoadStorePairHelper(const Instruction* instr,
1547 AddrMode addrmode) {
1548 unsigned rt = instr->GetRt();
1549 unsigned rt2 = instr->GetRt2();
1550 int element_size = 1 << instr->GetSizeLSPair();
1551 int64_t offset = instr->GetImmLSPair() * element_size;
1552 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addrmode);
1553 uintptr_t address2 = address + element_size;
1554
1555 LoadStorePairOp op =
1556 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
1557
1558 // 'rt' and 'rt2' can only be aliased for stores.
1559 VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2));
1560
1561 switch (op) {
1562 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
1563 // will print a more detailed log.
1564 case LDP_w: {
1565 WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
1566 WriteWRegister(rt2, Memory::Read<uint32_t>(address2), NoRegLog);
1567 break;
1568 }
1569 case LDP_s: {
1570 WriteSRegister(rt, Memory::Read<float>(address), NoRegLog);
1571 WriteSRegister(rt2, Memory::Read<float>(address2), NoRegLog);
1572 break;
1573 }
1574 case LDP_x: {
1575 WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
1576 WriteXRegister(rt2, Memory::Read<uint64_t>(address2), NoRegLog);
1577 break;
1578 }
1579 case LDP_d: {
1580 WriteDRegister(rt, Memory::Read<double>(address), NoRegLog);
1581 WriteDRegister(rt2, Memory::Read<double>(address2), NoRegLog);
1582 break;
1583 }
1584 case LDP_q: {
1585 WriteQRegister(rt, Memory::Read<qreg_t>(address), NoRegLog);
1586 WriteQRegister(rt2, Memory::Read<qreg_t>(address2), NoRegLog);
1587 break;
1588 }
1589 case LDPSW_x: {
1590 WriteXRegister(rt, Memory::Read<int32_t>(address), NoRegLog);
1591 WriteXRegister(rt2, Memory::Read<int32_t>(address2), NoRegLog);
1592 break;
1593 }
1594 case STP_w: {
1595 Memory::Write<uint32_t>(address, ReadWRegister(rt));
1596 Memory::Write<uint32_t>(address2, ReadWRegister(rt2));
1597 break;
1598 }
1599 case STP_s: {
1600 Memory::Write<float>(address, ReadSRegister(rt));
1601 Memory::Write<float>(address2, ReadSRegister(rt2));
1602 break;
1603 }
1604 case STP_x: {
1605 Memory::Write<uint64_t>(address, ReadXRegister(rt));
1606 Memory::Write<uint64_t>(address2, ReadXRegister(rt2));
1607 break;
1608 }
1609 case STP_d: {
1610 Memory::Write<double>(address, ReadDRegister(rt));
1611 Memory::Write<double>(address2, ReadDRegister(rt2));
1612 break;
1613 }
1614 case STP_q: {
1615 Memory::Write<qreg_t>(address, ReadQRegister(rt));
1616 Memory::Write<qreg_t>(address2, ReadQRegister(rt2));
1617 break;
1618 }
1619 default:
1620 VIXL_UNREACHABLE();
1621 }
1622
1623 // Print a detailed trace (including the memory address) instead of the basic
1624 // register:value trace generated by set_*reg().
1625 if (instr->IsLoad()) {
1626 if ((op == LDP_s) || (op == LDP_d)) {
1627 LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1628 LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1629 } else if (op == LDP_q) {
1630 LogVRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1631 LogVRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1632 } else {
1633 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1634 LogRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1635 }
1636 } else {
1637 if ((op == STP_s) || (op == STP_d)) {
1638 LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1639 LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1640 } else if (op == STP_q) {
1641 LogVWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1642 LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1643 } else {
1644 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1645 LogWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1646 }
1647 }
1648
1649 local_monitor_.MaybeClear();
1650 }
1651
1652
PrintExclusiveAccessWarning()1653 void Simulator::PrintExclusiveAccessWarning() {
1654 if (print_exclusive_access_warning_) {
1655 fprintf(stderr,
1656 "%sWARNING:%s VIXL simulator support for "
1657 "load-/store-/clear-exclusive "
1658 "instructions is limited. Refer to the README for details.%s\n",
1659 clr_warning,
1660 clr_warning_message,
1661 clr_normal);
1662 print_exclusive_access_warning_ = false;
1663 }
1664 }
1665
1666 template <typename T>
CompareAndSwapHelper(const Instruction * instr)1667 void Simulator::CompareAndSwapHelper(const Instruction* instr) {
1668 unsigned rs = instr->GetRs();
1669 unsigned rt = instr->GetRt();
1670 unsigned rn = instr->GetRn();
1671
1672 unsigned element_size = sizeof(T);
1673 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
1674
1675 bool is_acquire = instr->ExtractBit(22) == 1;
1676 bool is_release = instr->ExtractBit(15) == 1;
1677
1678 T comparevalue = ReadRegister<T>(rs);
1679 T newvalue = ReadRegister<T>(rt);
1680
1681 // The architecture permits that the data read clears any exclusive monitors
1682 // associated with that location, even if the compare subsequently fails.
1683 local_monitor_.Clear();
1684
1685 T data = Memory::Read<T>(address);
1686 if (is_acquire) {
1687 // Approximate load-acquire by issuing a full barrier after the load.
1688 __sync_synchronize();
1689 }
1690
1691 if (data == comparevalue) {
1692 if (is_release) {
1693 // Approximate store-release by issuing a full barrier before the store.
1694 __sync_synchronize();
1695 }
1696 Memory::Write<T>(address, newvalue);
1697 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1698 }
1699 WriteRegister<T>(rs, data);
1700 LogRead(address, rs, GetPrintRegisterFormatForSize(element_size));
1701 }
1702
1703 template <typename T>
CompareAndSwapPairHelper(const Instruction * instr)1704 void Simulator::CompareAndSwapPairHelper(const Instruction* instr) {
1705 VIXL_ASSERT((sizeof(T) == 4) || (sizeof(T) == 8));
1706 unsigned rs = instr->GetRs();
1707 unsigned rt = instr->GetRt();
1708 unsigned rn = instr->GetRn();
1709
1710 VIXL_ASSERT((rs % 2 == 0) && (rs % 2 == 0));
1711
1712 unsigned element_size = sizeof(T);
1713 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
1714 uint64_t address2 = address + element_size;
1715
1716 bool is_acquire = instr->ExtractBit(22) == 1;
1717 bool is_release = instr->ExtractBit(15) == 1;
1718
1719 T comparevalue_high = ReadRegister<T>(rs + 1);
1720 T comparevalue_low = ReadRegister<T>(rs);
1721 T newvalue_high = ReadRegister<T>(rt + 1);
1722 T newvalue_low = ReadRegister<T>(rt);
1723
1724 // The architecture permits that the data read clears any exclusive monitors
1725 // associated with that location, even if the compare subsequently fails.
1726 local_monitor_.Clear();
1727
1728 T data_high = Memory::Read<T>(address);
1729 T data_low = Memory::Read<T>(address2);
1730
1731 if (is_acquire) {
1732 // Approximate load-acquire by issuing a full barrier after the load.
1733 __sync_synchronize();
1734 }
1735
1736 bool same =
1737 (data_high == comparevalue_high) && (data_low == comparevalue_low);
1738 if (same) {
1739 if (is_release) {
1740 // Approximate store-release by issuing a full barrier before the store.
1741 __sync_synchronize();
1742 }
1743
1744 Memory::Write<T>(address, newvalue_high);
1745 Memory::Write<T>(address2, newvalue_low);
1746 }
1747
1748 WriteRegister<T>(rs + 1, data_high);
1749 WriteRegister<T>(rs, data_low);
1750
1751 LogRead(address, rs + 1, GetPrintRegisterFormatForSize(element_size));
1752 LogRead(address2, rs, GetPrintRegisterFormatForSize(element_size));
1753
1754 if (same) {
1755 LogWrite(address, rt + 1, GetPrintRegisterFormatForSize(element_size));
1756 LogWrite(address2, rt, GetPrintRegisterFormatForSize(element_size));
1757 }
1758 }
1759
1760
VisitLoadStoreExclusive(const Instruction * instr)1761 void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
1762 PrintExclusiveAccessWarning();
1763
1764 unsigned rs = instr->GetRs();
1765 unsigned rt = instr->GetRt();
1766 unsigned rt2 = instr->GetRt2();
1767 unsigned rn = instr->GetRn();
1768
1769 LoadStoreExclusive op =
1770 static_cast<LoadStoreExclusive>(instr->Mask(LoadStoreExclusiveMask));
1771
1772 bool is_exclusive = !instr->GetLdStXNotExclusive();
1773 bool is_acquire_release = !is_exclusive || instr->GetLdStXAcquireRelease();
1774 bool is_load = instr->GetLdStXLoad();
1775 bool is_pair = instr->GetLdStXPair();
1776
1777 unsigned element_size = 1 << instr->GetLdStXSizeLog2();
1778 unsigned access_size = is_pair ? element_size * 2 : element_size;
1779 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
1780
1781 // Verify that the address is available to the host.
1782 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1783
1784 // Check the alignment of `address`.
1785 if (AlignDown(address, access_size) != address) {
1786 VIXL_ALIGNMENT_EXCEPTION();
1787 }
1788
1789 // The sp must be aligned to 16 bytes when it is accessed.
1790 if ((rn == 31) && (AlignDown(address, 16) != address)) {
1791 VIXL_ALIGNMENT_EXCEPTION();
1792 }
1793
1794
1795 switch (op) {
1796 case CAS_w:
1797 case CASA_w:
1798 case CASL_w:
1799 case CASAL_w:
1800 CompareAndSwapHelper<uint32_t>(instr);
1801 break;
1802 case CAS_x:
1803 case CASA_x:
1804 case CASL_x:
1805 case CASAL_x:
1806 CompareAndSwapHelper<uint64_t>(instr);
1807 break;
1808 case CASB:
1809 case CASAB:
1810 case CASLB:
1811 case CASALB:
1812 CompareAndSwapHelper<uint8_t>(instr);
1813 break;
1814 case CASH:
1815 case CASAH:
1816 case CASLH:
1817 case CASALH:
1818 CompareAndSwapHelper<uint16_t>(instr);
1819 break;
1820 case CASP_w:
1821 case CASPA_w:
1822 case CASPL_w:
1823 case CASPAL_w:
1824 CompareAndSwapPairHelper<uint32_t>(instr);
1825 break;
1826 case CASP_x:
1827 case CASPA_x:
1828 case CASPL_x:
1829 case CASPAL_x:
1830 CompareAndSwapPairHelper<uint64_t>(instr);
1831 break;
1832 default:
1833 if (is_load) {
1834 if (is_exclusive) {
1835 local_monitor_.MarkExclusive(address, access_size);
1836 } else {
1837 // Any non-exclusive load can clear the local monitor as a side
1838 // effect. We don't need to do this, but it is useful to stress the
1839 // simulated code.
1840 local_monitor_.Clear();
1841 }
1842
1843 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS).
1844 // We will print a more detailed log.
1845 switch (op) {
1846 case LDXRB_w:
1847 case LDAXRB_w:
1848 case LDARB_w:
1849 case LDLARB:
1850 WriteWRegister(rt, Memory::Read<uint8_t>(address), NoRegLog);
1851 break;
1852 case LDXRH_w:
1853 case LDAXRH_w:
1854 case LDARH_w:
1855 case LDLARH:
1856 WriteWRegister(rt, Memory::Read<uint16_t>(address), NoRegLog);
1857 break;
1858 case LDXR_w:
1859 case LDAXR_w:
1860 case LDAR_w:
1861 case LDLAR_w:
1862 WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
1863 break;
1864 case LDXR_x:
1865 case LDAXR_x:
1866 case LDAR_x:
1867 case LDLAR_x:
1868 WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
1869 break;
1870 case LDXP_w:
1871 case LDAXP_w:
1872 WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
1873 WriteWRegister(rt2,
1874 Memory::Read<uint32_t>(address + element_size),
1875 NoRegLog);
1876 break;
1877 case LDXP_x:
1878 case LDAXP_x:
1879 WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
1880 WriteXRegister(rt2,
1881 Memory::Read<uint64_t>(address + element_size),
1882 NoRegLog);
1883 break;
1884 default:
1885 VIXL_UNREACHABLE();
1886 }
1887
1888 if (is_acquire_release) {
1889 // Approximate load-acquire by issuing a full barrier after the load.
1890 __sync_synchronize();
1891 }
1892
1893 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1894 if (is_pair) {
1895 LogRead(address + element_size,
1896 rt2,
1897 GetPrintRegisterFormatForSize(element_size));
1898 }
1899 } else {
1900 if (is_acquire_release) {
1901 // Approximate store-release by issuing a full barrier before the
1902 // store.
1903 __sync_synchronize();
1904 }
1905
1906 bool do_store = true;
1907 if (is_exclusive) {
1908 do_store = local_monitor_.IsExclusive(address, access_size) &&
1909 global_monitor_.IsExclusive(address, access_size);
1910 WriteWRegister(rs, do_store ? 0 : 1);
1911
1912 // - All exclusive stores explicitly clear the local monitor.
1913 local_monitor_.Clear();
1914 } else {
1915 // - Any other store can clear the local monitor as a side effect.
1916 local_monitor_.MaybeClear();
1917 }
1918
1919 if (do_store) {
1920 switch (op) {
1921 case STXRB_w:
1922 case STLXRB_w:
1923 case STLRB_w:
1924 case STLLRB:
1925 Memory::Write<uint8_t>(address, ReadWRegister(rt));
1926 break;
1927 case STXRH_w:
1928 case STLXRH_w:
1929 case STLRH_w:
1930 case STLLRH:
1931 Memory::Write<uint16_t>(address, ReadWRegister(rt));
1932 break;
1933 case STXR_w:
1934 case STLXR_w:
1935 case STLR_w:
1936 case STLLR_w:
1937 Memory::Write<uint32_t>(address, ReadWRegister(rt));
1938 break;
1939 case STXR_x:
1940 case STLXR_x:
1941 case STLR_x:
1942 case STLLR_x:
1943 Memory::Write<uint64_t>(address, ReadXRegister(rt));
1944 break;
1945 case STXP_w:
1946 case STLXP_w:
1947 Memory::Write<uint32_t>(address, ReadWRegister(rt));
1948 Memory::Write<uint32_t>(address + element_size,
1949 ReadWRegister(rt2));
1950 break;
1951 case STXP_x:
1952 case STLXP_x:
1953 Memory::Write<uint64_t>(address, ReadXRegister(rt));
1954 Memory::Write<uint64_t>(address + element_size,
1955 ReadXRegister(rt2));
1956 break;
1957 default:
1958 VIXL_UNREACHABLE();
1959 }
1960
1961 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1962 if (is_pair) {
1963 LogWrite(address + element_size,
1964 rt2,
1965 GetPrintRegisterFormatForSize(element_size));
1966 }
1967 }
1968 }
1969 }
1970 }
1971
1972 template <typename T>
AtomicMemorySimpleHelper(const Instruction * instr)1973 void Simulator::AtomicMemorySimpleHelper(const Instruction* instr) {
1974 unsigned rs = instr->GetRs();
1975 unsigned rt = instr->GetRt();
1976 unsigned rn = instr->GetRn();
1977
1978 bool is_acquire = (instr->ExtractBit(23) == 1) && (rt != kZeroRegCode);
1979 bool is_release = instr->ExtractBit(22) == 1;
1980
1981 unsigned element_size = sizeof(T);
1982 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
1983
1984 // Verify that the address is available to the host.
1985 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1986
1987 T value = ReadRegister<T>(rs);
1988
1989 T data = Memory::Read<T>(address);
1990
1991 if (is_acquire) {
1992 // Approximate load-acquire by issuing a full barrier after the load.
1993 __sync_synchronize();
1994 }
1995
1996 T result = 0;
1997 switch (instr->Mask(AtomicMemorySimpleOpMask)) {
1998 case LDADDOp:
1999 result = data + value;
2000 break;
2001 case LDCLROp:
2002 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
2003 result = data & ~value;
2004 break;
2005 case LDEOROp:
2006 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
2007 result = data ^ value;
2008 break;
2009 case LDSETOp:
2010 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
2011 result = data | value;
2012 break;
2013
2014 // Signed/Unsigned difference is done via the templated type T.
2015 case LDSMAXOp:
2016 case LDUMAXOp:
2017 result = (data > value) ? data : value;
2018 break;
2019 case LDSMINOp:
2020 case LDUMINOp:
2021 result = (data > value) ? value : data;
2022 break;
2023 }
2024
2025 if (is_release) {
2026 // Approximate store-release by issuing a full barrier before the store.
2027 __sync_synchronize();
2028 }
2029
2030 Memory::Write<T>(address, result);
2031 WriteRegister<T>(rt, data, NoRegLog);
2032
2033 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
2034 LogWrite(address, rs, GetPrintRegisterFormatForSize(element_size));
2035 }
2036
2037 template <typename T>
AtomicMemorySwapHelper(const Instruction * instr)2038 void Simulator::AtomicMemorySwapHelper(const Instruction* instr) {
2039 unsigned rs = instr->GetRs();
2040 unsigned rt = instr->GetRt();
2041 unsigned rn = instr->GetRn();
2042
2043 bool is_acquire = (instr->ExtractBit(23) == 1) && (rt != kZeroRegCode);
2044 bool is_release = instr->ExtractBit(22) == 1;
2045
2046 unsigned element_size = sizeof(T);
2047 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
2048
2049 // Verify that the address is available to the host.
2050 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
2051
2052 T data = Memory::Read<T>(address);
2053 if (is_acquire) {
2054 // Approximate load-acquire by issuing a full barrier after the load.
2055 __sync_synchronize();
2056 }
2057
2058 if (is_release) {
2059 // Approximate store-release by issuing a full barrier before the store.
2060 __sync_synchronize();
2061 }
2062 Memory::Write<T>(address, ReadRegister<T>(rs));
2063
2064 WriteRegister<T>(rt, data);
2065
2066 LogRead(address, rt, GetPrintRegisterFormat(element_size));
2067 LogWrite(address, rs, GetPrintRegisterFormat(element_size));
2068 }
2069
2070 template <typename T>
LoadAcquireRCpcHelper(const Instruction * instr)2071 void Simulator::LoadAcquireRCpcHelper(const Instruction* instr) {
2072 unsigned rt = instr->GetRt();
2073 unsigned rn = instr->GetRn();
2074
2075 unsigned element_size = sizeof(T);
2076 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
2077
2078 // Verify that the address is available to the host.
2079 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
2080 WriteRegister<T>(rt, Memory::Read<T>(address));
2081
2082 // Approximate load-acquire by issuing a full barrier after the load.
2083 __sync_synchronize();
2084
2085 LogRead(address, rt, GetPrintRegisterFormat(element_size));
2086 }
2087
2088 #define ATOMIC_MEMORY_SIMPLE_UINT_LIST(V) \
2089 V(LDADD) \
2090 V(LDCLR) \
2091 V(LDEOR) \
2092 V(LDSET) \
2093 V(LDUMAX) \
2094 V(LDUMIN)
2095
2096 #define ATOMIC_MEMORY_SIMPLE_INT_LIST(V) \
2097 V(LDSMAX) \
2098 V(LDSMIN)
2099
VisitAtomicMemory(const Instruction * instr)2100 void Simulator::VisitAtomicMemory(const Instruction* instr) {
2101 switch (instr->Mask(AtomicMemoryMask)) {
2102 // clang-format off
2103 #define SIM_FUNC_B(A) \
2104 case A##B: \
2105 case A##AB: \
2106 case A##LB: \
2107 case A##ALB:
2108 #define SIM_FUNC_H(A) \
2109 case A##H: \
2110 case A##AH: \
2111 case A##LH: \
2112 case A##ALH:
2113 #define SIM_FUNC_w(A) \
2114 case A##_w: \
2115 case A##A_w: \
2116 case A##L_w: \
2117 case A##AL_w:
2118 #define SIM_FUNC_x(A) \
2119 case A##_x: \
2120 case A##A_x: \
2121 case A##L_x: \
2122 case A##AL_x:
2123
2124 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_B)
2125 AtomicMemorySimpleHelper<uint8_t>(instr);
2126 break;
2127 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_B)
2128 AtomicMemorySimpleHelper<int8_t>(instr);
2129 break;
2130 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_H)
2131 AtomicMemorySimpleHelper<uint16_t>(instr);
2132 break;
2133 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_H)
2134 AtomicMemorySimpleHelper<int16_t>(instr);
2135 break;
2136 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_w)
2137 AtomicMemorySimpleHelper<uint32_t>(instr);
2138 break;
2139 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_w)
2140 AtomicMemorySimpleHelper<int32_t>(instr);
2141 break;
2142 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_x)
2143 AtomicMemorySimpleHelper<uint64_t>(instr);
2144 break;
2145 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_x)
2146 AtomicMemorySimpleHelper<int64_t>(instr);
2147 break;
2148 // clang-format on
2149
2150 case SWPB:
2151 case SWPAB:
2152 case SWPLB:
2153 case SWPALB:
2154 AtomicMemorySwapHelper<uint8_t>(instr);
2155 break;
2156 case SWPH:
2157 case SWPAH:
2158 case SWPLH:
2159 case SWPALH:
2160 AtomicMemorySwapHelper<uint16_t>(instr);
2161 break;
2162 case SWP_w:
2163 case SWPA_w:
2164 case SWPL_w:
2165 case SWPAL_w:
2166 AtomicMemorySwapHelper<uint32_t>(instr);
2167 break;
2168 case SWP_x:
2169 case SWPA_x:
2170 case SWPL_x:
2171 case SWPAL_x:
2172 AtomicMemorySwapHelper<uint64_t>(instr);
2173 break;
2174 case LDAPRB:
2175 LoadAcquireRCpcHelper<uint8_t>(instr);
2176 break;
2177 case LDAPRH:
2178 LoadAcquireRCpcHelper<uint16_t>(instr);
2179 break;
2180 case LDAPR_w:
2181 LoadAcquireRCpcHelper<uint32_t>(instr);
2182 break;
2183 case LDAPR_x:
2184 LoadAcquireRCpcHelper<uint64_t>(instr);
2185 break;
2186 }
2187 }
2188
2189
VisitLoadLiteral(const Instruction * instr)2190 void Simulator::VisitLoadLiteral(const Instruction* instr) {
2191 unsigned rt = instr->GetRt();
2192 uint64_t address = instr->GetLiteralAddress<uint64_t>();
2193
2194 // Verify that the calculated address is available to the host.
2195 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
2196
2197 switch (instr->Mask(LoadLiteralMask)) {
2198 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
2199 // print a more detailed log.
2200 case LDR_w_lit:
2201 WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
2202 LogRead(address, rt, kPrintWReg);
2203 break;
2204 case LDR_x_lit:
2205 WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
2206 LogRead(address, rt, kPrintXReg);
2207 break;
2208 case LDR_s_lit:
2209 WriteSRegister(rt, Memory::Read<float>(address), NoRegLog);
2210 LogVRead(address, rt, kPrintSReg);
2211 break;
2212 case LDR_d_lit:
2213 WriteDRegister(rt, Memory::Read<double>(address), NoRegLog);
2214 LogVRead(address, rt, kPrintDReg);
2215 break;
2216 case LDR_q_lit:
2217 WriteQRegister(rt, Memory::Read<qreg_t>(address), NoRegLog);
2218 LogVRead(address, rt, kPrintReg1Q);
2219 break;
2220 case LDRSW_x_lit:
2221 WriteXRegister(rt, Memory::Read<int32_t>(address), NoRegLog);
2222 LogRead(address, rt, kPrintWReg);
2223 break;
2224
2225 // Ignore prfm hint instructions.
2226 case PRFM_lit:
2227 break;
2228
2229 default:
2230 VIXL_UNREACHABLE();
2231 }
2232
2233 local_monitor_.MaybeClear();
2234 }
2235
2236
AddressModeHelper(unsigned addr_reg,int64_t offset,AddrMode addrmode)2237 uintptr_t Simulator::AddressModeHelper(unsigned addr_reg,
2238 int64_t offset,
2239 AddrMode addrmode) {
2240 uint64_t address = ReadXRegister(addr_reg, Reg31IsStackPointer);
2241
2242 if ((addr_reg == 31) && ((address % 16) != 0)) {
2243 // When the base register is SP the stack pointer is required to be
2244 // quadword aligned prior to the address calculation and write-backs.
2245 // Misalignment will cause a stack alignment fault.
2246 VIXL_ALIGNMENT_EXCEPTION();
2247 }
2248
2249 if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
2250 VIXL_ASSERT(offset != 0);
2251 // Only preindex should log the register update here. For Postindex, the
2252 // update will be printed automatically by LogWrittenRegisters _after_ the
2253 // memory access itself is logged.
2254 RegLogMode log_mode = (addrmode == PreIndex) ? LogRegWrites : NoRegLog;
2255 WriteXRegister(addr_reg, address + offset, log_mode, Reg31IsStackPointer);
2256 }
2257
2258 if ((addrmode == Offset) || (addrmode == PreIndex)) {
2259 address += offset;
2260 }
2261
2262 // Verify that the calculated address is available to the host.
2263 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
2264
2265 return static_cast<uintptr_t>(address);
2266 }
2267
2268
VisitMoveWideImmediate(const Instruction * instr)2269 void Simulator::VisitMoveWideImmediate(const Instruction* instr) {
2270 MoveWideImmediateOp mov_op =
2271 static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
2272 int64_t new_xn_val = 0;
2273
2274 bool is_64_bits = instr->GetSixtyFourBits() == 1;
2275 // Shift is limited for W operations.
2276 VIXL_ASSERT(is_64_bits || (instr->GetShiftMoveWide() < 2));
2277
2278 // Get the shifted immediate.
2279 int64_t shift = instr->GetShiftMoveWide() * 16;
2280 int64_t shifted_imm16 = static_cast<int64_t>(instr->GetImmMoveWide())
2281 << shift;
2282
2283 // Compute the new value.
2284 switch (mov_op) {
2285 case MOVN_w:
2286 case MOVN_x: {
2287 new_xn_val = ~shifted_imm16;
2288 if (!is_64_bits) new_xn_val &= kWRegMask;
2289 break;
2290 }
2291 case MOVK_w:
2292 case MOVK_x: {
2293 unsigned reg_code = instr->GetRd();
2294 int64_t prev_xn_val =
2295 is_64_bits ? ReadXRegister(reg_code) : ReadWRegister(reg_code);
2296 new_xn_val = (prev_xn_val & ~(INT64_C(0xffff) << shift)) | shifted_imm16;
2297 break;
2298 }
2299 case MOVZ_w:
2300 case MOVZ_x: {
2301 new_xn_val = shifted_imm16;
2302 break;
2303 }
2304 default:
2305 VIXL_UNREACHABLE();
2306 }
2307
2308 // Update the destination register.
2309 WriteXRegister(instr->GetRd(), new_xn_val);
2310 }
2311
2312
VisitConditionalSelect(const Instruction * instr)2313 void Simulator::VisitConditionalSelect(const Instruction* instr) {
2314 uint64_t new_val = ReadXRegister(instr->GetRn());
2315
2316 if (ConditionFailed(static_cast<Condition>(instr->GetCondition()))) {
2317 new_val = ReadXRegister(instr->GetRm());
2318 switch (instr->Mask(ConditionalSelectMask)) {
2319 case CSEL_w:
2320 case CSEL_x:
2321 break;
2322 case CSINC_w:
2323 case CSINC_x:
2324 new_val++;
2325 break;
2326 case CSINV_w:
2327 case CSINV_x:
2328 new_val = ~new_val;
2329 break;
2330 case CSNEG_w:
2331 case CSNEG_x:
2332 new_val = -new_val;
2333 break;
2334 default:
2335 VIXL_UNIMPLEMENTED();
2336 }
2337 }
2338 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
2339 WriteRegister(reg_size, instr->GetRd(), new_val);
2340 }
2341
2342
2343 // clang-format off
2344 #define PAUTH_MODES(V) \
2345 V(IA, ReadXRegister(src), kPACKeyIA, kInstructionPointer) \
2346 V(IB, ReadXRegister(src), kPACKeyIB, kInstructionPointer) \
2347 V(IZA, 0x00000000, kPACKeyIA, kInstructionPointer) \
2348 V(IZB, 0x00000000, kPACKeyIB, kInstructionPointer) \
2349 V(DA, ReadXRegister(src), kPACKeyDA, kDataPointer) \
2350 V(DB, ReadXRegister(src), kPACKeyDB, kDataPointer) \
2351 V(DZA, 0x00000000, kPACKeyDA, kDataPointer) \
2352 V(DZB, 0x00000000, kPACKeyDB, kDataPointer)
2353 // clang-format on
2354
VisitDataProcessing1Source(const Instruction * instr)2355 void Simulator::VisitDataProcessing1Source(const Instruction* instr) {
2356 unsigned dst = instr->GetRd();
2357 unsigned src = instr->GetRn();
2358
2359 switch (instr->Mask(DataProcessing1SourceMask)) {
2360 #define DEFINE_PAUTH_FUNCS(SUFFIX, MOD, KEY, D) \
2361 case PAC##SUFFIX: { \
2362 uint64_t ptr = ReadXRegister(dst); \
2363 WriteXRegister(dst, AddPAC(ptr, MOD, KEY, D)); \
2364 break; \
2365 } \
2366 case AUT##SUFFIX: { \
2367 uint64_t ptr = ReadXRegister(dst); \
2368 WriteXRegister(dst, AuthPAC(ptr, MOD, KEY, D)); \
2369 break; \
2370 }
2371
2372 PAUTH_MODES(DEFINE_PAUTH_FUNCS)
2373 #undef DEFINE_PAUTH_FUNCS
2374
2375 case XPACI:
2376 WriteXRegister(dst, StripPAC(ReadXRegister(dst), kInstructionPointer));
2377 break;
2378 case XPACD:
2379 WriteXRegister(dst, StripPAC(ReadXRegister(dst), kDataPointer));
2380 break;
2381 case RBIT_w:
2382 WriteWRegister(dst, ReverseBits(ReadWRegister(src)));
2383 break;
2384 case RBIT_x:
2385 WriteXRegister(dst, ReverseBits(ReadXRegister(src)));
2386 break;
2387 case REV16_w:
2388 WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 1));
2389 break;
2390 case REV16_x:
2391 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 1));
2392 break;
2393 case REV_w:
2394 WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 2));
2395 break;
2396 case REV32_x:
2397 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 2));
2398 break;
2399 case REV_x:
2400 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 3));
2401 break;
2402 case CLZ_w:
2403 WriteWRegister(dst, CountLeadingZeros(ReadWRegister(src)));
2404 break;
2405 case CLZ_x:
2406 WriteXRegister(dst, CountLeadingZeros(ReadXRegister(src)));
2407 break;
2408 case CLS_w:
2409 WriteWRegister(dst, CountLeadingSignBits(ReadWRegister(src)));
2410 break;
2411 case CLS_x:
2412 WriteXRegister(dst, CountLeadingSignBits(ReadXRegister(src)));
2413 break;
2414 default:
2415 VIXL_UNIMPLEMENTED();
2416 }
2417 }
2418
2419
Poly32Mod2(unsigned n,uint64_t data,uint32_t poly)2420 uint32_t Simulator::Poly32Mod2(unsigned n, uint64_t data, uint32_t poly) {
2421 VIXL_ASSERT((n > 32) && (n <= 64));
2422 for (unsigned i = (n - 1); i >= 32; i--) {
2423 if (((data >> i) & 1) != 0) {
2424 uint64_t polysh32 = (uint64_t)poly << (i - 32);
2425 uint64_t mask = (UINT64_C(1) << i) - 1;
2426 data = ((data & mask) ^ polysh32);
2427 }
2428 }
2429 return data & 0xffffffff;
2430 }
2431
2432
2433 template <typename T>
Crc32Checksum(uint32_t acc,T val,uint32_t poly)2434 uint32_t Simulator::Crc32Checksum(uint32_t acc, T val, uint32_t poly) {
2435 unsigned size = sizeof(val) * 8; // Number of bits in type T.
2436 VIXL_ASSERT((size == 8) || (size == 16) || (size == 32));
2437 uint64_t tempacc = static_cast<uint64_t>(ReverseBits(acc)) << size;
2438 uint64_t tempval = static_cast<uint64_t>(ReverseBits(val)) << 32;
2439 return ReverseBits(Poly32Mod2(32 + size, tempacc ^ tempval, poly));
2440 }
2441
2442
Crc32Checksum(uint32_t acc,uint64_t val,uint32_t poly)2443 uint32_t Simulator::Crc32Checksum(uint32_t acc, uint64_t val, uint32_t poly) {
2444 // Poly32Mod2 cannot handle inputs with more than 32 bits, so compute
2445 // the CRC of each 32-bit word sequentially.
2446 acc = Crc32Checksum(acc, (uint32_t)(val & 0xffffffff), poly);
2447 return Crc32Checksum(acc, (uint32_t)(val >> 32), poly);
2448 }
2449
2450
VisitDataProcessing2Source(const Instruction * instr)2451 void Simulator::VisitDataProcessing2Source(const Instruction* instr) {
2452 Shift shift_op = NO_SHIFT;
2453 int64_t result = 0;
2454 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
2455
2456 switch (instr->Mask(DataProcessing2SourceMask)) {
2457 case SDIV_w: {
2458 int32_t rn = ReadWRegister(instr->GetRn());
2459 int32_t rm = ReadWRegister(instr->GetRm());
2460 if ((rn == kWMinInt) && (rm == -1)) {
2461 result = kWMinInt;
2462 } else if (rm == 0) {
2463 // Division by zero can be trapped, but not on A-class processors.
2464 result = 0;
2465 } else {
2466 result = rn / rm;
2467 }
2468 break;
2469 }
2470 case SDIV_x: {
2471 int64_t rn = ReadXRegister(instr->GetRn());
2472 int64_t rm = ReadXRegister(instr->GetRm());
2473 if ((rn == kXMinInt) && (rm == -1)) {
2474 result = kXMinInt;
2475 } else if (rm == 0) {
2476 // Division by zero can be trapped, but not on A-class processors.
2477 result = 0;
2478 } else {
2479 result = rn / rm;
2480 }
2481 break;
2482 }
2483 case UDIV_w: {
2484 uint32_t rn = static_cast<uint32_t>(ReadWRegister(instr->GetRn()));
2485 uint32_t rm = static_cast<uint32_t>(ReadWRegister(instr->GetRm()));
2486 if (rm == 0) {
2487 // Division by zero can be trapped, but not on A-class processors.
2488 result = 0;
2489 } else {
2490 result = rn / rm;
2491 }
2492 break;
2493 }
2494 case UDIV_x: {
2495 uint64_t rn = static_cast<uint64_t>(ReadXRegister(instr->GetRn()));
2496 uint64_t rm = static_cast<uint64_t>(ReadXRegister(instr->GetRm()));
2497 if (rm == 0) {
2498 // Division by zero can be trapped, but not on A-class processors.
2499 result = 0;
2500 } else {
2501 result = rn / rm;
2502 }
2503 break;
2504 }
2505 case LSLV_w:
2506 case LSLV_x:
2507 shift_op = LSL;
2508 break;
2509 case LSRV_w:
2510 case LSRV_x:
2511 shift_op = LSR;
2512 break;
2513 case ASRV_w:
2514 case ASRV_x:
2515 shift_op = ASR;
2516 break;
2517 case RORV_w:
2518 case RORV_x:
2519 shift_op = ROR;
2520 break;
2521 case PACGA: {
2522 uint64_t dst = static_cast<uint64_t>(ReadXRegister(instr->GetRn()));
2523 uint64_t src = static_cast<uint64_t>(
2524 ReadXRegister(instr->GetRm(), Reg31IsStackPointer));
2525 uint64_t code = ComputePAC(dst, src, kPACKeyGA);
2526 result = code & 0xffffffff00000000;
2527 break;
2528 }
2529 case CRC32B: {
2530 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2531 uint8_t val = ReadRegister<uint8_t>(instr->GetRm());
2532 result = Crc32Checksum(acc, val, CRC32_POLY);
2533 break;
2534 }
2535 case CRC32H: {
2536 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2537 uint16_t val = ReadRegister<uint16_t>(instr->GetRm());
2538 result = Crc32Checksum(acc, val, CRC32_POLY);
2539 break;
2540 }
2541 case CRC32W: {
2542 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2543 uint32_t val = ReadRegister<uint32_t>(instr->GetRm());
2544 result = Crc32Checksum(acc, val, CRC32_POLY);
2545 break;
2546 }
2547 case CRC32X: {
2548 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2549 uint64_t val = ReadRegister<uint64_t>(instr->GetRm());
2550 result = Crc32Checksum(acc, val, CRC32_POLY);
2551 reg_size = kWRegSize;
2552 break;
2553 }
2554 case CRC32CB: {
2555 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2556 uint8_t val = ReadRegister<uint8_t>(instr->GetRm());
2557 result = Crc32Checksum(acc, val, CRC32C_POLY);
2558 break;
2559 }
2560 case CRC32CH: {
2561 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2562 uint16_t val = ReadRegister<uint16_t>(instr->GetRm());
2563 result = Crc32Checksum(acc, val, CRC32C_POLY);
2564 break;
2565 }
2566 case CRC32CW: {
2567 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2568 uint32_t val = ReadRegister<uint32_t>(instr->GetRm());
2569 result = Crc32Checksum(acc, val, CRC32C_POLY);
2570 break;
2571 }
2572 case CRC32CX: {
2573 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
2574 uint64_t val = ReadRegister<uint64_t>(instr->GetRm());
2575 result = Crc32Checksum(acc, val, CRC32C_POLY);
2576 reg_size = kWRegSize;
2577 break;
2578 }
2579 default:
2580 VIXL_UNIMPLEMENTED();
2581 }
2582
2583 if (shift_op != NO_SHIFT) {
2584 // Shift distance encoded in the least-significant five/six bits of the
2585 // register.
2586 int mask = (instr->GetSixtyFourBits() == 1) ? 0x3f : 0x1f;
2587 unsigned shift = ReadWRegister(instr->GetRm()) & mask;
2588 result = ShiftOperand(reg_size,
2589 ReadRegister(reg_size, instr->GetRn()),
2590 shift_op,
2591 shift);
2592 }
2593 WriteRegister(reg_size, instr->GetRd(), result);
2594 }
2595
2596
2597 // The algorithm used is adapted from the one described in section 8.2 of
2598 // Hacker's Delight, by Henry S. Warren, Jr.
2599 template <typename T>
MultiplyHigh(T u,T v)2600 static int64_t MultiplyHigh(T u, T v) {
2601 uint64_t u0, v0, w0, u1, v1, w1, w2, t;
2602 uint64_t sign_mask = UINT64_C(0x8000000000000000);
2603 uint64_t sign_ext = 0;
2604 if (std::numeric_limits<T>::is_signed) {
2605 sign_ext = UINT64_C(0xffffffff00000000);
2606 }
2607
2608 VIXL_ASSERT(sizeof(u) == sizeof(uint64_t));
2609 VIXL_ASSERT(sizeof(u) == sizeof(u0));
2610
2611 u0 = u & 0xffffffff;
2612 u1 = u >> 32 | (((u & sign_mask) != 0) ? sign_ext : 0);
2613 v0 = v & 0xffffffff;
2614 v1 = v >> 32 | (((v & sign_mask) != 0) ? sign_ext : 0);
2615
2616 w0 = u0 * v0;
2617 t = u1 * v0 + (w0 >> 32);
2618
2619 w1 = t & 0xffffffff;
2620 w2 = t >> 32 | (((t & sign_mask) != 0) ? sign_ext : 0);
2621 w1 = u0 * v1 + w1;
2622 w1 = w1 >> 32 | (((w1 & sign_mask) != 0) ? sign_ext : 0);
2623
2624 uint64_t value = u1 * v1 + w2 + w1;
2625 int64_t result;
2626 memcpy(&result, &value, sizeof(result));
2627 return result;
2628 }
2629
2630
VisitDataProcessing3Source(const Instruction * instr)2631 void Simulator::VisitDataProcessing3Source(const Instruction* instr) {
2632 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
2633
2634 uint64_t result = 0;
2635 // Extract and sign- or zero-extend 32-bit arguments for widening operations.
2636 uint64_t rn_u32 = ReadRegister<uint32_t>(instr->GetRn());
2637 uint64_t rm_u32 = ReadRegister<uint32_t>(instr->GetRm());
2638 int64_t rn_s32 = ReadRegister<int32_t>(instr->GetRn());
2639 int64_t rm_s32 = ReadRegister<int32_t>(instr->GetRm());
2640 uint64_t rn_u64 = ReadXRegister(instr->GetRn());
2641 uint64_t rm_u64 = ReadXRegister(instr->GetRm());
2642 switch (instr->Mask(DataProcessing3SourceMask)) {
2643 case MADD_w:
2644 case MADD_x:
2645 result = ReadXRegister(instr->GetRa()) + (rn_u64 * rm_u64);
2646 break;
2647 case MSUB_w:
2648 case MSUB_x:
2649 result = ReadXRegister(instr->GetRa()) - (rn_u64 * rm_u64);
2650 break;
2651 case SMADDL_x:
2652 result = ReadXRegister(instr->GetRa()) +
2653 static_cast<uint64_t>(rn_s32 * rm_s32);
2654 break;
2655 case SMSUBL_x:
2656 result = ReadXRegister(instr->GetRa()) -
2657 static_cast<uint64_t>(rn_s32 * rm_s32);
2658 break;
2659 case UMADDL_x:
2660 result = ReadXRegister(instr->GetRa()) + (rn_u32 * rm_u32);
2661 break;
2662 case UMSUBL_x:
2663 result = ReadXRegister(instr->GetRa()) - (rn_u32 * rm_u32);
2664 break;
2665 case UMULH_x:
2666 result = MultiplyHigh(ReadRegister<uint64_t>(instr->GetRn()),
2667 ReadRegister<uint64_t>(instr->GetRm()));
2668 break;
2669 case SMULH_x:
2670 result = MultiplyHigh(ReadXRegister(instr->GetRn()),
2671 ReadXRegister(instr->GetRm()));
2672 break;
2673 default:
2674 VIXL_UNIMPLEMENTED();
2675 }
2676 WriteRegister(reg_size, instr->GetRd(), result);
2677 }
2678
2679
VisitBitfield(const Instruction * instr)2680 void Simulator::VisitBitfield(const Instruction* instr) {
2681 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
2682 int64_t reg_mask = instr->GetSixtyFourBits() ? kXRegMask : kWRegMask;
2683 int R = instr->GetImmR();
2684 int S = instr->GetImmS();
2685 int diff = S - R;
2686 uint64_t mask;
2687 if (diff >= 0) {
2688 mask = ~UINT64_C(0) >> (64 - (diff + 1));
2689 mask = (static_cast<unsigned>(diff) < (reg_size - 1)) ? mask : reg_mask;
2690 } else {
2691 mask = ~UINT64_C(0) >> (64 - (S + 1));
2692 mask = RotateRight(mask, R, reg_size);
2693 diff += reg_size;
2694 }
2695
2696 // inzero indicates if the extracted bitfield is inserted into the
2697 // destination register value or in zero.
2698 // If extend is true, extend the sign of the extracted bitfield.
2699 bool inzero = false;
2700 bool extend = false;
2701 switch (instr->Mask(BitfieldMask)) {
2702 case BFM_x:
2703 case BFM_w:
2704 break;
2705 case SBFM_x:
2706 case SBFM_w:
2707 inzero = true;
2708 extend = true;
2709 break;
2710 case UBFM_x:
2711 case UBFM_w:
2712 inzero = true;
2713 break;
2714 default:
2715 VIXL_UNIMPLEMENTED();
2716 }
2717
2718 uint64_t dst = inzero ? 0 : ReadRegister(reg_size, instr->GetRd());
2719 uint64_t src = ReadRegister(reg_size, instr->GetRn());
2720 // Rotate source bitfield into place.
2721 uint64_t result = RotateRight(src, R, reg_size);
2722 // Determine the sign extension.
2723 uint64_t topbits = (diff == 63) ? 0 : (~UINT64_C(0) << (diff + 1));
2724 uint64_t signbits = extend && ((src >> S) & 1) ? topbits : 0;
2725
2726 // Merge sign extension, dest/zero and bitfield.
2727 result = signbits | (result & mask) | (dst & ~mask);
2728
2729 WriteRegister(reg_size, instr->GetRd(), result);
2730 }
2731
2732
VisitExtract(const Instruction * instr)2733 void Simulator::VisitExtract(const Instruction* instr) {
2734 unsigned lsb = instr->GetImmS();
2735 unsigned reg_size = (instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;
2736 uint64_t low_res =
2737 static_cast<uint64_t>(ReadRegister(reg_size, instr->GetRm())) >> lsb;
2738 uint64_t high_res =
2739 (lsb == 0) ? 0 : ReadRegister<uint64_t>(reg_size, instr->GetRn())
2740 << (reg_size - lsb);
2741 WriteRegister(reg_size, instr->GetRd(), low_res | high_res);
2742 }
2743
2744
VisitFPImmediate(const Instruction * instr)2745 void Simulator::VisitFPImmediate(const Instruction* instr) {
2746 AssertSupportedFPCR();
2747 unsigned dest = instr->GetRd();
2748 switch (instr->Mask(FPImmediateMask)) {
2749 case FMOV_h_imm:
2750 WriteHRegister(dest, Float16ToRawbits(instr->GetImmFP16()));
2751 break;
2752 case FMOV_s_imm:
2753 WriteSRegister(dest, instr->GetImmFP32());
2754 break;
2755 case FMOV_d_imm:
2756 WriteDRegister(dest, instr->GetImmFP64());
2757 break;
2758 default:
2759 VIXL_UNREACHABLE();
2760 }
2761 }
2762
2763
VisitFPIntegerConvert(const Instruction * instr)2764 void Simulator::VisitFPIntegerConvert(const Instruction* instr) {
2765 AssertSupportedFPCR();
2766
2767 unsigned dst = instr->GetRd();
2768 unsigned src = instr->GetRn();
2769
2770 FPRounding round = ReadRMode();
2771
2772 switch (instr->Mask(FPIntegerConvertMask)) {
2773 case FCVTAS_wh:
2774 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPTieAway));
2775 break;
2776 case FCVTAS_xh:
2777 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPTieAway));
2778 break;
2779 case FCVTAS_ws:
2780 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPTieAway));
2781 break;
2782 case FCVTAS_xs:
2783 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPTieAway));
2784 break;
2785 case FCVTAS_wd:
2786 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPTieAway));
2787 break;
2788 case FCVTAS_xd:
2789 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPTieAway));
2790 break;
2791 case FCVTAU_wh:
2792 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPTieAway));
2793 break;
2794 case FCVTAU_xh:
2795 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPTieAway));
2796 break;
2797 case FCVTAU_ws:
2798 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPTieAway));
2799 break;
2800 case FCVTAU_xs:
2801 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPTieAway));
2802 break;
2803 case FCVTAU_wd:
2804 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPTieAway));
2805 break;
2806 case FCVTAU_xd:
2807 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPTieAway));
2808 break;
2809 case FCVTMS_wh:
2810 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPNegativeInfinity));
2811 break;
2812 case FCVTMS_xh:
2813 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPNegativeInfinity));
2814 break;
2815 case FCVTMS_ws:
2816 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPNegativeInfinity));
2817 break;
2818 case FCVTMS_xs:
2819 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPNegativeInfinity));
2820 break;
2821 case FCVTMS_wd:
2822 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPNegativeInfinity));
2823 break;
2824 case FCVTMS_xd:
2825 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPNegativeInfinity));
2826 break;
2827 case FCVTMU_wh:
2828 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPNegativeInfinity));
2829 break;
2830 case FCVTMU_xh:
2831 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPNegativeInfinity));
2832 break;
2833 case FCVTMU_ws:
2834 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPNegativeInfinity));
2835 break;
2836 case FCVTMU_xs:
2837 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPNegativeInfinity));
2838 break;
2839 case FCVTMU_wd:
2840 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPNegativeInfinity));
2841 break;
2842 case FCVTMU_xd:
2843 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPNegativeInfinity));
2844 break;
2845 case FCVTPS_wh:
2846 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPPositiveInfinity));
2847 break;
2848 case FCVTPS_xh:
2849 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPPositiveInfinity));
2850 break;
2851 case FCVTPS_ws:
2852 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPPositiveInfinity));
2853 break;
2854 case FCVTPS_xs:
2855 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPPositiveInfinity));
2856 break;
2857 case FCVTPS_wd:
2858 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPPositiveInfinity));
2859 break;
2860 case FCVTPS_xd:
2861 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPPositiveInfinity));
2862 break;
2863 case FCVTPU_wh:
2864 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPPositiveInfinity));
2865 break;
2866 case FCVTPU_xh:
2867 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPPositiveInfinity));
2868 break;
2869 case FCVTPU_ws:
2870 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPPositiveInfinity));
2871 break;
2872 case FCVTPU_xs:
2873 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPPositiveInfinity));
2874 break;
2875 case FCVTPU_wd:
2876 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPPositiveInfinity));
2877 break;
2878 case FCVTPU_xd:
2879 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPPositiveInfinity));
2880 break;
2881 case FCVTNS_wh:
2882 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPTieEven));
2883 break;
2884 case FCVTNS_xh:
2885 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPTieEven));
2886 break;
2887 case FCVTNS_ws:
2888 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPTieEven));
2889 break;
2890 case FCVTNS_xs:
2891 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPTieEven));
2892 break;
2893 case FCVTNS_wd:
2894 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPTieEven));
2895 break;
2896 case FCVTNS_xd:
2897 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPTieEven));
2898 break;
2899 case FCVTNU_wh:
2900 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPTieEven));
2901 break;
2902 case FCVTNU_xh:
2903 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPTieEven));
2904 break;
2905 case FCVTNU_ws:
2906 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPTieEven));
2907 break;
2908 case FCVTNU_xs:
2909 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPTieEven));
2910 break;
2911 case FCVTNU_wd:
2912 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPTieEven));
2913 break;
2914 case FCVTNU_xd:
2915 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPTieEven));
2916 break;
2917 case FCVTZS_wh:
2918 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPZero));
2919 break;
2920 case FCVTZS_xh:
2921 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPZero));
2922 break;
2923 case FCVTZS_ws:
2924 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPZero));
2925 break;
2926 case FCVTZS_xs:
2927 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPZero));
2928 break;
2929 case FCVTZS_wd:
2930 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPZero));
2931 break;
2932 case FCVTZS_xd:
2933 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPZero));
2934 break;
2935 case FCVTZU_wh:
2936 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPZero));
2937 break;
2938 case FCVTZU_xh:
2939 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPZero));
2940 break;
2941 case FCVTZU_ws:
2942 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPZero));
2943 break;
2944 case FCVTZU_xs:
2945 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPZero));
2946 break;
2947 case FCVTZU_wd:
2948 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPZero));
2949 break;
2950 case FCVTZU_xd:
2951 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPZero));
2952 break;
2953 case FJCVTZS:
2954 WriteWRegister(dst, FPToFixedJS(ReadDRegister(src)));
2955 break;
2956 case FMOV_hw:
2957 WriteHRegister(dst, ReadWRegister(src) & kHRegMask);
2958 break;
2959 case FMOV_wh:
2960 WriteWRegister(dst, ReadHRegisterBits(src));
2961 break;
2962 case FMOV_xh:
2963 WriteXRegister(dst, ReadHRegisterBits(src));
2964 break;
2965 case FMOV_hx:
2966 WriteHRegister(dst, ReadXRegister(src) & kHRegMask);
2967 break;
2968 case FMOV_ws:
2969 WriteWRegister(dst, ReadSRegisterBits(src));
2970 break;
2971 case FMOV_xd:
2972 WriteXRegister(dst, ReadDRegisterBits(src));
2973 break;
2974 case FMOV_sw:
2975 WriteSRegisterBits(dst, ReadWRegister(src));
2976 break;
2977 case FMOV_dx:
2978 WriteDRegisterBits(dst, ReadXRegister(src));
2979 break;
2980 case FMOV_d1_x:
2981 LogicVRegister(ReadVRegister(dst))
2982 .SetUint(kFormatD, 1, ReadXRegister(src));
2983 break;
2984 case FMOV_x_d1:
2985 WriteXRegister(dst, LogicVRegister(ReadVRegister(src)).Uint(kFormatD, 1));
2986 break;
2987
2988 // A 32-bit input can be handled in the same way as a 64-bit input, since
2989 // the sign- or zero-extension will not affect the conversion.
2990 case SCVTF_dx:
2991 WriteDRegister(dst, FixedToDouble(ReadXRegister(src), 0, round));
2992 break;
2993 case SCVTF_dw:
2994 WriteDRegister(dst, FixedToDouble(ReadWRegister(src), 0, round));
2995 break;
2996 case UCVTF_dx:
2997 WriteDRegister(dst, UFixedToDouble(ReadXRegister(src), 0, round));
2998 break;
2999 case UCVTF_dw: {
3000 WriteDRegister(dst,
3001 UFixedToDouble(ReadRegister<uint32_t>(src), 0, round));
3002 break;
3003 }
3004 case SCVTF_sx:
3005 WriteSRegister(dst, FixedToFloat(ReadXRegister(src), 0, round));
3006 break;
3007 case SCVTF_sw:
3008 WriteSRegister(dst, FixedToFloat(ReadWRegister(src), 0, round));
3009 break;
3010 case UCVTF_sx:
3011 WriteSRegister(dst, UFixedToFloat(ReadXRegister(src), 0, round));
3012 break;
3013 case UCVTF_sw: {
3014 WriteSRegister(dst, UFixedToFloat(ReadRegister<uint32_t>(src), 0, round));
3015 break;
3016 }
3017 case SCVTF_hx:
3018 WriteHRegister(dst, FixedToFloat16(ReadXRegister(src), 0, round));
3019 break;
3020 case SCVTF_hw:
3021 WriteHRegister(dst, FixedToFloat16(ReadWRegister(src), 0, round));
3022 break;
3023 case UCVTF_hx:
3024 WriteHRegister(dst, UFixedToFloat16(ReadXRegister(src), 0, round));
3025 break;
3026 case UCVTF_hw: {
3027 WriteHRegister(dst,
3028 UFixedToFloat16(ReadRegister<uint32_t>(src), 0, round));
3029 break;
3030 }
3031
3032 default:
3033 VIXL_UNREACHABLE();
3034 }
3035 }
3036
3037
VisitFPFixedPointConvert(const Instruction * instr)3038 void Simulator::VisitFPFixedPointConvert(const Instruction* instr) {
3039 AssertSupportedFPCR();
3040
3041 unsigned dst = instr->GetRd();
3042 unsigned src = instr->GetRn();
3043 int fbits = 64 - instr->GetFPScale();
3044
3045 FPRounding round = ReadRMode();
3046
3047 switch (instr->Mask(FPFixedPointConvertMask)) {
3048 // A 32-bit input can be handled in the same way as a 64-bit input, since
3049 // the sign- or zero-extension will not affect the conversion.
3050 case SCVTF_dx_fixed:
3051 WriteDRegister(dst, FixedToDouble(ReadXRegister(src), fbits, round));
3052 break;
3053 case SCVTF_dw_fixed:
3054 WriteDRegister(dst, FixedToDouble(ReadWRegister(src), fbits, round));
3055 break;
3056 case UCVTF_dx_fixed:
3057 WriteDRegister(dst, UFixedToDouble(ReadXRegister(src), fbits, round));
3058 break;
3059 case UCVTF_dw_fixed: {
3060 WriteDRegister(dst,
3061 UFixedToDouble(ReadRegister<uint32_t>(src), fbits, round));
3062 break;
3063 }
3064 case SCVTF_sx_fixed:
3065 WriteSRegister(dst, FixedToFloat(ReadXRegister(src), fbits, round));
3066 break;
3067 case SCVTF_sw_fixed:
3068 WriteSRegister(dst, FixedToFloat(ReadWRegister(src), fbits, round));
3069 break;
3070 case UCVTF_sx_fixed:
3071 WriteSRegister(dst, UFixedToFloat(ReadXRegister(src), fbits, round));
3072 break;
3073 case UCVTF_sw_fixed: {
3074 WriteSRegister(dst,
3075 UFixedToFloat(ReadRegister<uint32_t>(src), fbits, round));
3076 break;
3077 }
3078 case SCVTF_hx_fixed:
3079 WriteHRegister(dst, FixedToFloat16(ReadXRegister(src), fbits, round));
3080 break;
3081 case SCVTF_hw_fixed:
3082 WriteHRegister(dst, FixedToFloat16(ReadWRegister(src), fbits, round));
3083 break;
3084 case UCVTF_hx_fixed:
3085 WriteHRegister(dst, UFixedToFloat16(ReadXRegister(src), fbits, round));
3086 break;
3087 case UCVTF_hw_fixed: {
3088 WriteHRegister(dst,
3089 UFixedToFloat16(ReadRegister<uint32_t>(src),
3090 fbits,
3091 round));
3092 break;
3093 }
3094 case FCVTZS_xd_fixed:
3095 WriteXRegister(dst,
3096 FPToInt64(ReadDRegister(src) * std::pow(2.0, fbits),
3097 FPZero));
3098 break;
3099 case FCVTZS_wd_fixed:
3100 WriteWRegister(dst,
3101 FPToInt32(ReadDRegister(src) * std::pow(2.0, fbits),
3102 FPZero));
3103 break;
3104 case FCVTZU_xd_fixed:
3105 WriteXRegister(dst,
3106 FPToUInt64(ReadDRegister(src) * std::pow(2.0, fbits),
3107 FPZero));
3108 break;
3109 case FCVTZU_wd_fixed:
3110 WriteWRegister(dst,
3111 FPToUInt32(ReadDRegister(src) * std::pow(2.0, fbits),
3112 FPZero));
3113 break;
3114 case FCVTZS_xs_fixed:
3115 WriteXRegister(dst,
3116 FPToInt64(ReadSRegister(src) * std::pow(2.0f, fbits),
3117 FPZero));
3118 break;
3119 case FCVTZS_ws_fixed:
3120 WriteWRegister(dst,
3121 FPToInt32(ReadSRegister(src) * std::pow(2.0f, fbits),
3122 FPZero));
3123 break;
3124 case FCVTZU_xs_fixed:
3125 WriteXRegister(dst,
3126 FPToUInt64(ReadSRegister(src) * std::pow(2.0f, fbits),
3127 FPZero));
3128 break;
3129 case FCVTZU_ws_fixed:
3130 WriteWRegister(dst,
3131 FPToUInt32(ReadSRegister(src) * std::pow(2.0f, fbits),
3132 FPZero));
3133 break;
3134 case FCVTZS_xh_fixed: {
3135 double output =
3136 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
3137 WriteXRegister(dst, FPToInt64(output, FPZero));
3138 break;
3139 }
3140 case FCVTZS_wh_fixed: {
3141 double output =
3142 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
3143 WriteWRegister(dst, FPToInt32(output, FPZero));
3144 break;
3145 }
3146 case FCVTZU_xh_fixed: {
3147 double output =
3148 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
3149 WriteXRegister(dst, FPToUInt64(output, FPZero));
3150 break;
3151 }
3152 case FCVTZU_wh_fixed: {
3153 double output =
3154 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
3155 WriteWRegister(dst, FPToUInt32(output, FPZero));
3156 break;
3157 }
3158 default:
3159 VIXL_UNREACHABLE();
3160 }
3161 }
3162
3163
VisitFPCompare(const Instruction * instr)3164 void Simulator::VisitFPCompare(const Instruction* instr) {
3165 AssertSupportedFPCR();
3166
3167 FPTrapFlags trap = DisableTrap;
3168 switch (instr->Mask(FPCompareMask)) {
3169 case FCMPE_h:
3170 trap = EnableTrap;
3171 VIXL_FALLTHROUGH();
3172 case FCMP_h:
3173 FPCompare(ReadHRegister(instr->GetRn()),
3174 ReadHRegister(instr->GetRm()),
3175 trap);
3176 break;
3177 case FCMPE_s:
3178 trap = EnableTrap;
3179 VIXL_FALLTHROUGH();
3180 case FCMP_s:
3181 FPCompare(ReadSRegister(instr->GetRn()),
3182 ReadSRegister(instr->GetRm()),
3183 trap);
3184 break;
3185 case FCMPE_d:
3186 trap = EnableTrap;
3187 VIXL_FALLTHROUGH();
3188 case FCMP_d:
3189 FPCompare(ReadDRegister(instr->GetRn()),
3190 ReadDRegister(instr->GetRm()),
3191 trap);
3192 break;
3193 case FCMPE_h_zero:
3194 trap = EnableTrap;
3195 VIXL_FALLTHROUGH();
3196 case FCMP_h_zero:
3197 FPCompare(ReadHRegister(instr->GetRn()), SimFloat16(0.0), trap);
3198 break;
3199 case FCMPE_s_zero:
3200 trap = EnableTrap;
3201 VIXL_FALLTHROUGH();
3202 case FCMP_s_zero:
3203 FPCompare(ReadSRegister(instr->GetRn()), 0.0f, trap);
3204 break;
3205 case FCMPE_d_zero:
3206 trap = EnableTrap;
3207 VIXL_FALLTHROUGH();
3208 case FCMP_d_zero:
3209 FPCompare(ReadDRegister(instr->GetRn()), 0.0, trap);
3210 break;
3211 default:
3212 VIXL_UNIMPLEMENTED();
3213 }
3214 }
3215
3216
VisitFPConditionalCompare(const Instruction * instr)3217 void Simulator::VisitFPConditionalCompare(const Instruction* instr) {
3218 AssertSupportedFPCR();
3219
3220 FPTrapFlags trap = DisableTrap;
3221 switch (instr->Mask(FPConditionalCompareMask)) {
3222 case FCCMPE_h:
3223 trap = EnableTrap;
3224 VIXL_FALLTHROUGH();
3225 case FCCMP_h:
3226 if (ConditionPassed(instr->GetCondition())) {
3227 FPCompare(ReadHRegister(instr->GetRn()),
3228 ReadHRegister(instr->GetRm()),
3229 trap);
3230 } else {
3231 ReadNzcv().SetFlags(instr->GetNzcv());
3232 LogSystemRegister(NZCV);
3233 }
3234 break;
3235 case FCCMPE_s:
3236 trap = EnableTrap;
3237 VIXL_FALLTHROUGH();
3238 case FCCMP_s:
3239 if (ConditionPassed(instr->GetCondition())) {
3240 FPCompare(ReadSRegister(instr->GetRn()),
3241 ReadSRegister(instr->GetRm()),
3242 trap);
3243 } else {
3244 ReadNzcv().SetFlags(instr->GetNzcv());
3245 LogSystemRegister(NZCV);
3246 }
3247 break;
3248 case FCCMPE_d:
3249 trap = EnableTrap;
3250 VIXL_FALLTHROUGH();
3251 case FCCMP_d:
3252 if (ConditionPassed(instr->GetCondition())) {
3253 FPCompare(ReadDRegister(instr->GetRn()),
3254 ReadDRegister(instr->GetRm()),
3255 trap);
3256 } else {
3257 ReadNzcv().SetFlags(instr->GetNzcv());
3258 LogSystemRegister(NZCV);
3259 }
3260 break;
3261 default:
3262 VIXL_UNIMPLEMENTED();
3263 }
3264 }
3265
3266
VisitFPConditionalSelect(const Instruction * instr)3267 void Simulator::VisitFPConditionalSelect(const Instruction* instr) {
3268 AssertSupportedFPCR();
3269
3270 Instr selected;
3271 if (ConditionPassed(instr->GetCondition())) {
3272 selected = instr->GetRn();
3273 } else {
3274 selected = instr->GetRm();
3275 }
3276
3277 switch (instr->Mask(FPConditionalSelectMask)) {
3278 case FCSEL_h:
3279 WriteHRegister(instr->GetRd(), ReadHRegister(selected));
3280 break;
3281 case FCSEL_s:
3282 WriteSRegister(instr->GetRd(), ReadSRegister(selected));
3283 break;
3284 case FCSEL_d:
3285 WriteDRegister(instr->GetRd(), ReadDRegister(selected));
3286 break;
3287 default:
3288 VIXL_UNIMPLEMENTED();
3289 }
3290 }
3291
3292
VisitFPDataProcessing1Source(const Instruction * instr)3293 void Simulator::VisitFPDataProcessing1Source(const Instruction* instr) {
3294 AssertSupportedFPCR();
3295
3296 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
3297 VectorFormat vform;
3298 switch (instr->Mask(FPTypeMask)) {
3299 default:
3300 VIXL_UNREACHABLE_OR_FALLTHROUGH();
3301 case FP64:
3302 vform = kFormatD;
3303 break;
3304 case FP32:
3305 vform = kFormatS;
3306 break;
3307 case FP16:
3308 vform = kFormatH;
3309 break;
3310 }
3311
3312 SimVRegister& rd = ReadVRegister(instr->GetRd());
3313 SimVRegister& rn = ReadVRegister(instr->GetRn());
3314 bool inexact_exception = false;
3315
3316 unsigned fd = instr->GetRd();
3317 unsigned fn = instr->GetRn();
3318
3319 switch (instr->Mask(FPDataProcessing1SourceMask)) {
3320 case FMOV_h:
3321 WriteHRegister(fd, ReadHRegister(fn));
3322 return;
3323 case FMOV_s:
3324 WriteSRegister(fd, ReadSRegister(fn));
3325 return;
3326 case FMOV_d:
3327 WriteDRegister(fd, ReadDRegister(fn));
3328 return;
3329 case FABS_h:
3330 case FABS_s:
3331 case FABS_d:
3332 fabs_(vform, ReadVRegister(fd), ReadVRegister(fn));
3333 // Explicitly log the register update whilst we have type information.
3334 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3335 return;
3336 case FNEG_h:
3337 case FNEG_s:
3338 case FNEG_d:
3339 fneg(vform, ReadVRegister(fd), ReadVRegister(fn));
3340 // Explicitly log the register update whilst we have type information.
3341 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3342 return;
3343 case FCVT_ds:
3344 WriteDRegister(fd, FPToDouble(ReadSRegister(fn), ReadDN()));
3345 return;
3346 case FCVT_sd:
3347 WriteSRegister(fd, FPToFloat(ReadDRegister(fn), FPTieEven, ReadDN()));
3348 return;
3349 case FCVT_hs:
3350 WriteHRegister(fd,
3351 Float16ToRawbits(
3352 FPToFloat16(ReadSRegister(fn), FPTieEven, ReadDN())));
3353 return;
3354 case FCVT_sh:
3355 WriteSRegister(fd, FPToFloat(ReadHRegister(fn), ReadDN()));
3356 return;
3357 case FCVT_dh:
3358 WriteDRegister(fd, FPToDouble(ReadHRegister(fn), ReadDN()));
3359 return;
3360 case FCVT_hd:
3361 WriteHRegister(fd,
3362 Float16ToRawbits(
3363 FPToFloat16(ReadDRegister(fn), FPTieEven, ReadDN())));
3364 return;
3365 case FSQRT_h:
3366 case FSQRT_s:
3367 case FSQRT_d:
3368 fsqrt(vform, rd, rn);
3369 // Explicitly log the register update whilst we have type information.
3370 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3371 return;
3372 case FRINTI_h:
3373 case FRINTI_s:
3374 case FRINTI_d:
3375 break; // Use FPCR rounding mode.
3376 case FRINTX_h:
3377 case FRINTX_s:
3378 case FRINTX_d:
3379 inexact_exception = true;
3380 break;
3381 case FRINTA_h:
3382 case FRINTA_s:
3383 case FRINTA_d:
3384 fpcr_rounding = FPTieAway;
3385 break;
3386 case FRINTM_h:
3387 case FRINTM_s:
3388 case FRINTM_d:
3389 fpcr_rounding = FPNegativeInfinity;
3390 break;
3391 case FRINTN_h:
3392 case FRINTN_s:
3393 case FRINTN_d:
3394 fpcr_rounding = FPTieEven;
3395 break;
3396 case FRINTP_h:
3397 case FRINTP_s:
3398 case FRINTP_d:
3399 fpcr_rounding = FPPositiveInfinity;
3400 break;
3401 case FRINTZ_h:
3402 case FRINTZ_s:
3403 case FRINTZ_d:
3404 fpcr_rounding = FPZero;
3405 break;
3406 default:
3407 VIXL_UNIMPLEMENTED();
3408 }
3409
3410 // Only FRINT* instructions fall through the switch above.
3411 frint(vform, rd, rn, fpcr_rounding, inexact_exception);
3412 // Explicitly log the register update whilst we have type information.
3413 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3414 }
3415
3416
VisitFPDataProcessing2Source(const Instruction * instr)3417 void Simulator::VisitFPDataProcessing2Source(const Instruction* instr) {
3418 AssertSupportedFPCR();
3419
3420 VectorFormat vform;
3421 switch (instr->Mask(FPTypeMask)) {
3422 default:
3423 VIXL_UNREACHABLE_OR_FALLTHROUGH();
3424 case FP64:
3425 vform = kFormatD;
3426 break;
3427 case FP32:
3428 vform = kFormatS;
3429 break;
3430 case FP16:
3431 vform = kFormatH;
3432 break;
3433 }
3434 SimVRegister& rd = ReadVRegister(instr->GetRd());
3435 SimVRegister& rn = ReadVRegister(instr->GetRn());
3436 SimVRegister& rm = ReadVRegister(instr->GetRm());
3437
3438 switch (instr->Mask(FPDataProcessing2SourceMask)) {
3439 case FADD_h:
3440 case FADD_s:
3441 case FADD_d:
3442 fadd(vform, rd, rn, rm);
3443 break;
3444 case FSUB_h:
3445 case FSUB_s:
3446 case FSUB_d:
3447 fsub(vform, rd, rn, rm);
3448 break;
3449 case FMUL_h:
3450 case FMUL_s:
3451 case FMUL_d:
3452 fmul(vform, rd, rn, rm);
3453 break;
3454 case FNMUL_h:
3455 case FNMUL_s:
3456 case FNMUL_d:
3457 fnmul(vform, rd, rn, rm);
3458 break;
3459 case FDIV_h:
3460 case FDIV_s:
3461 case FDIV_d:
3462 fdiv(vform, rd, rn, rm);
3463 break;
3464 case FMAX_h:
3465 case FMAX_s:
3466 case FMAX_d:
3467 fmax(vform, rd, rn, rm);
3468 break;
3469 case FMIN_h:
3470 case FMIN_s:
3471 case FMIN_d:
3472 fmin(vform, rd, rn, rm);
3473 break;
3474 case FMAXNM_h:
3475 case FMAXNM_s:
3476 case FMAXNM_d:
3477 fmaxnm(vform, rd, rn, rm);
3478 break;
3479 case FMINNM_h:
3480 case FMINNM_s:
3481 case FMINNM_d:
3482 fminnm(vform, rd, rn, rm);
3483 break;
3484 default:
3485 VIXL_UNREACHABLE();
3486 }
3487 // Explicitly log the register update whilst we have type information.
3488 LogVRegister(instr->GetRd(), GetPrintRegisterFormatFP(vform));
3489 }
3490
3491
VisitFPDataProcessing3Source(const Instruction * instr)3492 void Simulator::VisitFPDataProcessing3Source(const Instruction* instr) {
3493 AssertSupportedFPCR();
3494
3495 unsigned fd = instr->GetRd();
3496 unsigned fn = instr->GetRn();
3497 unsigned fm = instr->GetRm();
3498 unsigned fa = instr->GetRa();
3499
3500 switch (instr->Mask(FPDataProcessing3SourceMask)) {
3501 // fd = fa +/- (fn * fm)
3502 case FMADD_h:
3503 WriteHRegister(fd,
3504 FPMulAdd(ReadHRegister(fa),
3505 ReadHRegister(fn),
3506 ReadHRegister(fm)));
3507 break;
3508 case FMSUB_h:
3509 WriteHRegister(fd,
3510 FPMulAdd(ReadHRegister(fa),
3511 -ReadHRegister(fn),
3512 ReadHRegister(fm)));
3513 break;
3514 case FMADD_s:
3515 WriteSRegister(fd,
3516 FPMulAdd(ReadSRegister(fa),
3517 ReadSRegister(fn),
3518 ReadSRegister(fm)));
3519 break;
3520 case FMSUB_s:
3521 WriteSRegister(fd,
3522 FPMulAdd(ReadSRegister(fa),
3523 -ReadSRegister(fn),
3524 ReadSRegister(fm)));
3525 break;
3526 case FMADD_d:
3527 WriteDRegister(fd,
3528 FPMulAdd(ReadDRegister(fa),
3529 ReadDRegister(fn),
3530 ReadDRegister(fm)));
3531 break;
3532 case FMSUB_d:
3533 WriteDRegister(fd,
3534 FPMulAdd(ReadDRegister(fa),
3535 -ReadDRegister(fn),
3536 ReadDRegister(fm)));
3537 break;
3538 // Negated variants of the above.
3539 case FNMADD_h:
3540 WriteHRegister(fd,
3541 FPMulAdd(-ReadHRegister(fa),
3542 -ReadHRegister(fn),
3543 ReadHRegister(fm)));
3544 break;
3545 case FNMSUB_h:
3546 WriteHRegister(fd,
3547 FPMulAdd(-ReadHRegister(fa),
3548 ReadHRegister(fn),
3549 ReadHRegister(fm)));
3550 break;
3551 case FNMADD_s:
3552 WriteSRegister(fd,
3553 FPMulAdd(-ReadSRegister(fa),
3554 -ReadSRegister(fn),
3555 ReadSRegister(fm)));
3556 break;
3557 case FNMSUB_s:
3558 WriteSRegister(fd,
3559 FPMulAdd(-ReadSRegister(fa),
3560 ReadSRegister(fn),
3561 ReadSRegister(fm)));
3562 break;
3563 case FNMADD_d:
3564 WriteDRegister(fd,
3565 FPMulAdd(-ReadDRegister(fa),
3566 -ReadDRegister(fn),
3567 ReadDRegister(fm)));
3568 break;
3569 case FNMSUB_d:
3570 WriteDRegister(fd,
3571 FPMulAdd(-ReadDRegister(fa),
3572 ReadDRegister(fn),
3573 ReadDRegister(fm)));
3574 break;
3575 default:
3576 VIXL_UNIMPLEMENTED();
3577 }
3578 }
3579
3580
FPProcessNaNs(const Instruction * instr)3581 bool Simulator::FPProcessNaNs(const Instruction* instr) {
3582 unsigned fd = instr->GetRd();
3583 unsigned fn = instr->GetRn();
3584 unsigned fm = instr->GetRm();
3585 bool done = false;
3586
3587 if (instr->Mask(FP64) == FP64) {
3588 double result = FPProcessNaNs(ReadDRegister(fn), ReadDRegister(fm));
3589 if (IsNaN(result)) {
3590 WriteDRegister(fd, result);
3591 done = true;
3592 }
3593 } else if (instr->Mask(FP32) == FP32) {
3594 float result = FPProcessNaNs(ReadSRegister(fn), ReadSRegister(fm));
3595 if (IsNaN(result)) {
3596 WriteSRegister(fd, result);
3597 done = true;
3598 }
3599 } else {
3600 VIXL_ASSERT(instr->Mask(FP16) == FP16);
3601 VIXL_UNIMPLEMENTED();
3602 }
3603
3604 return done;
3605 }
3606
3607
SysOp_W(int op,int64_t val)3608 void Simulator::SysOp_W(int op, int64_t val) {
3609 switch (op) {
3610 case IVAU:
3611 case CVAC:
3612 case CVAU:
3613 case CIVAC: {
3614 // Perform a dummy memory access to ensure that we have read access
3615 // to the specified address.
3616 volatile uint8_t y = Memory::Read<uint8_t>(val);
3617 USE(y);
3618 // TODO: Implement "case ZVA:".
3619 break;
3620 }
3621 default:
3622 VIXL_UNIMPLEMENTED();
3623 }
3624 }
3625
3626
3627 // clang-format off
3628 #define PAUTH_SYSTEM_MODES(V) \
3629 V(A1716, 17, ReadXRegister(16), kPACKeyIA) \
3630 V(B1716, 17, ReadXRegister(16), kPACKeyIB) \
3631 V(AZ, 30, 0x00000000, kPACKeyIA) \
3632 V(BZ, 30, 0x00000000, kPACKeyIB) \
3633 V(ASP, 30, ReadXRegister(31, Reg31IsStackPointer), kPACKeyIA) \
3634 V(BSP, 30, ReadXRegister(31, Reg31IsStackPointer), kPACKeyIB)
3635 // clang-format on
3636
3637
VisitSystem(const Instruction * instr)3638 void Simulator::VisitSystem(const Instruction* instr) {
3639 // Some system instructions hijack their Op and Cp fields to represent a
3640 // range of immediates instead of indicating a different instruction. This
3641 // makes the decoding tricky.
3642 if (instr->GetInstructionBits() == XPACLRI) {
3643 WriteXRegister(30, StripPAC(ReadXRegister(30), kInstructionPointer));
3644 } else if (instr->Mask(SystemPAuthFMask) == SystemPAuthFixed) {
3645 switch (instr->Mask(SystemPAuthMask)) {
3646 #define DEFINE_PAUTH_FUNCS(SUFFIX, DST, MOD, KEY) \
3647 case PACI##SUFFIX: \
3648 WriteXRegister(DST, \
3649 AddPAC(ReadXRegister(DST), MOD, KEY, kInstructionPointer)); \
3650 break; \
3651 case AUTI##SUFFIX: \
3652 WriteXRegister(DST, \
3653 AuthPAC(ReadXRegister(DST), \
3654 MOD, \
3655 KEY, \
3656 kInstructionPointer)); \
3657 break;
3658
3659 PAUTH_SYSTEM_MODES(DEFINE_PAUTH_FUNCS)
3660 #undef DEFINE_PAUTH_FUNCS
3661 }
3662 } else if (instr->Mask(SystemExclusiveMonitorFMask) ==
3663 SystemExclusiveMonitorFixed) {
3664 VIXL_ASSERT(instr->Mask(SystemExclusiveMonitorMask) == CLREX);
3665 switch (instr->Mask(SystemExclusiveMonitorMask)) {
3666 case CLREX: {
3667 PrintExclusiveAccessWarning();
3668 ClearLocalMonitor();
3669 break;
3670 }
3671 }
3672 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
3673 switch (instr->Mask(SystemSysRegMask)) {
3674 case MRS: {
3675 switch (instr->GetImmSystemRegister()) {
3676 case NZCV:
3677 WriteXRegister(instr->GetRt(), ReadNzcv().GetRawValue());
3678 break;
3679 case FPCR:
3680 WriteXRegister(instr->GetRt(), ReadFpcr().GetRawValue());
3681 break;
3682 default:
3683 VIXL_UNIMPLEMENTED();
3684 }
3685 break;
3686 }
3687 case MSR: {
3688 switch (instr->GetImmSystemRegister()) {
3689 case NZCV:
3690 ReadNzcv().SetRawValue(ReadWRegister(instr->GetRt()));
3691 LogSystemRegister(NZCV);
3692 break;
3693 case FPCR:
3694 ReadFpcr().SetRawValue(ReadWRegister(instr->GetRt()));
3695 LogSystemRegister(FPCR);
3696 break;
3697 default:
3698 VIXL_UNIMPLEMENTED();
3699 }
3700 break;
3701 }
3702 }
3703 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
3704 VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
3705 switch (instr->GetImmHint()) {
3706 case NOP:
3707 case ESB:
3708 case CSDB:
3709 break;
3710 default:
3711 VIXL_UNIMPLEMENTED();
3712 }
3713 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
3714 __sync_synchronize();
3715 } else if ((instr->Mask(SystemSysFMask) == SystemSysFixed)) {
3716 switch (instr->Mask(SystemSysMask)) {
3717 case SYS:
3718 SysOp_W(instr->GetSysOp(), ReadXRegister(instr->GetRt()));
3719 break;
3720 default:
3721 VIXL_UNIMPLEMENTED();
3722 }
3723 } else {
3724 VIXL_UNIMPLEMENTED();
3725 }
3726 }
3727
3728
VisitException(const Instruction * instr)3729 void Simulator::VisitException(const Instruction* instr) {
3730 switch (instr->Mask(ExceptionMask)) {
3731 case HLT:
3732 switch (instr->GetImmException()) {
3733 case kUnreachableOpcode:
3734 DoUnreachable(instr);
3735 return;
3736 case kTraceOpcode:
3737 DoTrace(instr);
3738 return;
3739 case kLogOpcode:
3740 DoLog(instr);
3741 return;
3742 case kPrintfOpcode:
3743 DoPrintf(instr);
3744 return;
3745 case kRuntimeCallOpcode:
3746 DoRuntimeCall(instr);
3747 return;
3748 case kSetCPUFeaturesOpcode:
3749 case kEnableCPUFeaturesOpcode:
3750 case kDisableCPUFeaturesOpcode:
3751 DoConfigureCPUFeatures(instr);
3752 return;
3753 case kSaveCPUFeaturesOpcode:
3754 DoSaveCPUFeatures(instr);
3755 return;
3756 case kRestoreCPUFeaturesOpcode:
3757 DoRestoreCPUFeatures(instr);
3758 return;
3759 default:
3760 HostBreakpoint();
3761 return;
3762 }
3763 case BRK:
3764 HostBreakpoint();
3765 return;
3766 default:
3767 VIXL_UNIMPLEMENTED();
3768 }
3769 }
3770
3771
VisitCrypto2RegSHA(const Instruction * instr)3772 void Simulator::VisitCrypto2RegSHA(const Instruction* instr) {
3773 VisitUnimplemented(instr);
3774 }
3775
3776
VisitCrypto3RegSHA(const Instruction * instr)3777 void Simulator::VisitCrypto3RegSHA(const Instruction* instr) {
3778 VisitUnimplemented(instr);
3779 }
3780
3781
VisitCryptoAES(const Instruction * instr)3782 void Simulator::VisitCryptoAES(const Instruction* instr) {
3783 VisitUnimplemented(instr);
3784 }
3785
3786
VisitNEON2RegMisc(const Instruction * instr)3787 void Simulator::VisitNEON2RegMisc(const Instruction* instr) {
3788 NEONFormatDecoder nfd(instr);
3789 VectorFormat vf = nfd.GetVectorFormat();
3790
3791 static const NEONFormatMap map_lp =
3792 {{23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
3793 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);
3794
3795 static const NEONFormatMap map_fcvtl = {{22}, {NF_4S, NF_2D}};
3796 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);
3797
3798 static const NEONFormatMap map_fcvtn = {{22, 30},
3799 {NF_4H, NF_8H, NF_2S, NF_4S}};
3800 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);
3801
3802 SimVRegister& rd = ReadVRegister(instr->GetRd());
3803 SimVRegister& rn = ReadVRegister(instr->GetRn());
3804
3805 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
3806 // These instructions all use a two bit size field, except NOT and RBIT,
3807 // which use the field to encode the operation.
3808 switch (instr->Mask(NEON2RegMiscMask)) {
3809 case NEON_REV64:
3810 rev64(vf, rd, rn);
3811 break;
3812 case NEON_REV32:
3813 rev32(vf, rd, rn);
3814 break;
3815 case NEON_REV16:
3816 rev16(vf, rd, rn);
3817 break;
3818 case NEON_SUQADD:
3819 suqadd(vf, rd, rn);
3820 break;
3821 case NEON_USQADD:
3822 usqadd(vf, rd, rn);
3823 break;
3824 case NEON_CLS:
3825 cls(vf, rd, rn);
3826 break;
3827 case NEON_CLZ:
3828 clz(vf, rd, rn);
3829 break;
3830 case NEON_CNT:
3831 cnt(vf, rd, rn);
3832 break;
3833 case NEON_SQABS:
3834 abs(vf, rd, rn).SignedSaturate(vf);
3835 break;
3836 case NEON_SQNEG:
3837 neg(vf, rd, rn).SignedSaturate(vf);
3838 break;
3839 case NEON_CMGT_zero:
3840 cmp(vf, rd, rn, 0, gt);
3841 break;
3842 case NEON_CMGE_zero:
3843 cmp(vf, rd, rn, 0, ge);
3844 break;
3845 case NEON_CMEQ_zero:
3846 cmp(vf, rd, rn, 0, eq);
3847 break;
3848 case NEON_CMLE_zero:
3849 cmp(vf, rd, rn, 0, le);
3850 break;
3851 case NEON_CMLT_zero:
3852 cmp(vf, rd, rn, 0, lt);
3853 break;
3854 case NEON_ABS:
3855 abs(vf, rd, rn);
3856 break;
3857 case NEON_NEG:
3858 neg(vf, rd, rn);
3859 break;
3860 case NEON_SADDLP:
3861 saddlp(vf_lp, rd, rn);
3862 break;
3863 case NEON_UADDLP:
3864 uaddlp(vf_lp, rd, rn);
3865 break;
3866 case NEON_SADALP:
3867 sadalp(vf_lp, rd, rn);
3868 break;
3869 case NEON_UADALP:
3870 uadalp(vf_lp, rd, rn);
3871 break;
3872 case NEON_RBIT_NOT:
3873 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
3874 switch (instr->GetFPType()) {
3875 case 0:
3876 not_(vf, rd, rn);
3877 break;
3878 case 1:
3879 rbit(vf, rd, rn);
3880 break;
3881 default:
3882 VIXL_UNIMPLEMENTED();
3883 }
3884 break;
3885 }
3886 } else {
3887 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
3888 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
3889 bool inexact_exception = false;
3890
3891 // These instructions all use a one bit size field, except XTN, SQXTUN,
3892 // SHLL, SQXTN and UQXTN, which use a two bit size field.
3893 switch (instr->Mask(NEON2RegMiscFPMask)) {
3894 case NEON_FABS:
3895 fabs_(fpf, rd, rn);
3896 return;
3897 case NEON_FNEG:
3898 fneg(fpf, rd, rn);
3899 return;
3900 case NEON_FSQRT:
3901 fsqrt(fpf, rd, rn);
3902 return;
3903 case NEON_FCVTL:
3904 if (instr->Mask(NEON_Q)) {
3905 fcvtl2(vf_fcvtl, rd, rn);
3906 } else {
3907 fcvtl(vf_fcvtl, rd, rn);
3908 }
3909 return;
3910 case NEON_FCVTN:
3911 if (instr->Mask(NEON_Q)) {
3912 fcvtn2(vf_fcvtn, rd, rn);
3913 } else {
3914 fcvtn(vf_fcvtn, rd, rn);
3915 }
3916 return;
3917 case NEON_FCVTXN:
3918 if (instr->Mask(NEON_Q)) {
3919 fcvtxn2(vf_fcvtn, rd, rn);
3920 } else {
3921 fcvtxn(vf_fcvtn, rd, rn);
3922 }
3923 return;
3924
3925 // The following instructions break from the switch statement, rather
3926 // than return.
3927 case NEON_FRINTI:
3928 break; // Use FPCR rounding mode.
3929 case NEON_FRINTX:
3930 inexact_exception = true;
3931 break;
3932 case NEON_FRINTA:
3933 fpcr_rounding = FPTieAway;
3934 break;
3935 case NEON_FRINTM:
3936 fpcr_rounding = FPNegativeInfinity;
3937 break;
3938 case NEON_FRINTN:
3939 fpcr_rounding = FPTieEven;
3940 break;
3941 case NEON_FRINTP:
3942 fpcr_rounding = FPPositiveInfinity;
3943 break;
3944 case NEON_FRINTZ:
3945 fpcr_rounding = FPZero;
3946 break;
3947
3948 case NEON_FCVTNS:
3949 fcvts(fpf, rd, rn, FPTieEven);
3950 return;
3951 case NEON_FCVTNU:
3952 fcvtu(fpf, rd, rn, FPTieEven);
3953 return;
3954 case NEON_FCVTPS:
3955 fcvts(fpf, rd, rn, FPPositiveInfinity);
3956 return;
3957 case NEON_FCVTPU:
3958 fcvtu(fpf, rd, rn, FPPositiveInfinity);
3959 return;
3960 case NEON_FCVTMS:
3961 fcvts(fpf, rd, rn, FPNegativeInfinity);
3962 return;
3963 case NEON_FCVTMU:
3964 fcvtu(fpf, rd, rn, FPNegativeInfinity);
3965 return;
3966 case NEON_FCVTZS:
3967 fcvts(fpf, rd, rn, FPZero);
3968 return;
3969 case NEON_FCVTZU:
3970 fcvtu(fpf, rd, rn, FPZero);
3971 return;
3972 case NEON_FCVTAS:
3973 fcvts(fpf, rd, rn, FPTieAway);
3974 return;
3975 case NEON_FCVTAU:
3976 fcvtu(fpf, rd, rn, FPTieAway);
3977 return;
3978 case NEON_SCVTF:
3979 scvtf(fpf, rd, rn, 0, fpcr_rounding);
3980 return;
3981 case NEON_UCVTF:
3982 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
3983 return;
3984 case NEON_URSQRTE:
3985 ursqrte(fpf, rd, rn);
3986 return;
3987 case NEON_URECPE:
3988 urecpe(fpf, rd, rn);
3989 return;
3990 case NEON_FRSQRTE:
3991 frsqrte(fpf, rd, rn);
3992 return;
3993 case NEON_FRECPE:
3994 frecpe(fpf, rd, rn, fpcr_rounding);
3995 return;
3996 case NEON_FCMGT_zero:
3997 fcmp_zero(fpf, rd, rn, gt);
3998 return;
3999 case NEON_FCMGE_zero:
4000 fcmp_zero(fpf, rd, rn, ge);
4001 return;
4002 case NEON_FCMEQ_zero:
4003 fcmp_zero(fpf, rd, rn, eq);
4004 return;
4005 case NEON_FCMLE_zero:
4006 fcmp_zero(fpf, rd, rn, le);
4007 return;
4008 case NEON_FCMLT_zero:
4009 fcmp_zero(fpf, rd, rn, lt);
4010 return;
4011 default:
4012 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
4013 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
4014 switch (instr->Mask(NEON2RegMiscMask)) {
4015 case NEON_XTN:
4016 xtn(vf, rd, rn);
4017 return;
4018 case NEON_SQXTN:
4019 sqxtn(vf, rd, rn);
4020 return;
4021 case NEON_UQXTN:
4022 uqxtn(vf, rd, rn);
4023 return;
4024 case NEON_SQXTUN:
4025 sqxtun(vf, rd, rn);
4026 return;
4027 case NEON_SHLL:
4028 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4029 if (instr->Mask(NEON_Q)) {
4030 shll2(vf, rd, rn);
4031 } else {
4032 shll(vf, rd, rn);
4033 }
4034 return;
4035 default:
4036 VIXL_UNIMPLEMENTED();
4037 }
4038 } else {
4039 VIXL_UNIMPLEMENTED();
4040 }
4041 }
4042
4043 // Only FRINT* instructions fall through the switch above.
4044 frint(fpf, rd, rn, fpcr_rounding, inexact_exception);
4045 }
4046 }
4047
4048
VisitNEON2RegMiscFP16(const Instruction * instr)4049 void Simulator::VisitNEON2RegMiscFP16(const Instruction* instr) {
4050 static const NEONFormatMap map_half = {{30}, {NF_4H, NF_8H}};
4051 NEONFormatDecoder nfd(instr);
4052 VectorFormat fpf = nfd.GetVectorFormat(&map_half);
4053
4054 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
4055
4056 SimVRegister& rd = ReadVRegister(instr->GetRd());
4057 SimVRegister& rn = ReadVRegister(instr->GetRn());
4058
4059 switch (instr->Mask(NEON2RegMiscFP16Mask)) {
4060 case NEON_SCVTF_H:
4061 scvtf(fpf, rd, rn, 0, fpcr_rounding);
4062 return;
4063 case NEON_UCVTF_H:
4064 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
4065 return;
4066 case NEON_FCVTNS_H:
4067 fcvts(fpf, rd, rn, FPTieEven);
4068 return;
4069 case NEON_FCVTNU_H:
4070 fcvtu(fpf, rd, rn, FPTieEven);
4071 return;
4072 case NEON_FCVTPS_H:
4073 fcvts(fpf, rd, rn, FPPositiveInfinity);
4074 return;
4075 case NEON_FCVTPU_H:
4076 fcvtu(fpf, rd, rn, FPPositiveInfinity);
4077 return;
4078 case NEON_FCVTMS_H:
4079 fcvts(fpf, rd, rn, FPNegativeInfinity);
4080 return;
4081 case NEON_FCVTMU_H:
4082 fcvtu(fpf, rd, rn, FPNegativeInfinity);
4083 return;
4084 case NEON_FCVTZS_H:
4085 fcvts(fpf, rd, rn, FPZero);
4086 return;
4087 case NEON_FCVTZU_H:
4088 fcvtu(fpf, rd, rn, FPZero);
4089 return;
4090 case NEON_FCVTAS_H:
4091 fcvts(fpf, rd, rn, FPTieAway);
4092 return;
4093 case NEON_FCVTAU_H:
4094 fcvtu(fpf, rd, rn, FPTieAway);
4095 return;
4096 case NEON_FRINTI_H:
4097 frint(fpf, rd, rn, fpcr_rounding, false);
4098 return;
4099 case NEON_FRINTX_H:
4100 frint(fpf, rd, rn, fpcr_rounding, true);
4101 return;
4102 case NEON_FRINTA_H:
4103 frint(fpf, rd, rn, FPTieAway, false);
4104 return;
4105 case NEON_FRINTM_H:
4106 frint(fpf, rd, rn, FPNegativeInfinity, false);
4107 return;
4108 case NEON_FRINTN_H:
4109 frint(fpf, rd, rn, FPTieEven, false);
4110 return;
4111 case NEON_FRINTP_H:
4112 frint(fpf, rd, rn, FPPositiveInfinity, false);
4113 return;
4114 case NEON_FRINTZ_H:
4115 frint(fpf, rd, rn, FPZero, false);
4116 return;
4117 case NEON_FABS_H:
4118 fabs_(fpf, rd, rn);
4119 return;
4120 case NEON_FNEG_H:
4121 fneg(fpf, rd, rn);
4122 return;
4123 case NEON_FSQRT_H:
4124 fsqrt(fpf, rd, rn);
4125 return;
4126 case NEON_FRSQRTE_H:
4127 frsqrte(fpf, rd, rn);
4128 return;
4129 case NEON_FRECPE_H:
4130 frecpe(fpf, rd, rn, fpcr_rounding);
4131 return;
4132 case NEON_FCMGT_H_zero:
4133 fcmp_zero(fpf, rd, rn, gt);
4134 return;
4135 case NEON_FCMGE_H_zero:
4136 fcmp_zero(fpf, rd, rn, ge);
4137 return;
4138 case NEON_FCMEQ_H_zero:
4139 fcmp_zero(fpf, rd, rn, eq);
4140 return;
4141 case NEON_FCMLE_H_zero:
4142 fcmp_zero(fpf, rd, rn, le);
4143 return;
4144 case NEON_FCMLT_H_zero:
4145 fcmp_zero(fpf, rd, rn, lt);
4146 return;
4147 default:
4148 VIXL_UNIMPLEMENTED();
4149 return;
4150 }
4151 }
4152
4153
VisitNEON3Same(const Instruction * instr)4154 void Simulator::VisitNEON3Same(const Instruction* instr) {
4155 NEONFormatDecoder nfd(instr);
4156 SimVRegister& rd = ReadVRegister(instr->GetRd());
4157 SimVRegister& rn = ReadVRegister(instr->GetRn());
4158 SimVRegister& rm = ReadVRegister(instr->GetRm());
4159
4160 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
4161 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
4162 switch (instr->Mask(NEON3SameLogicalMask)) {
4163 case NEON_AND:
4164 and_(vf, rd, rn, rm);
4165 break;
4166 case NEON_ORR:
4167 orr(vf, rd, rn, rm);
4168 break;
4169 case NEON_ORN:
4170 orn(vf, rd, rn, rm);
4171 break;
4172 case NEON_EOR:
4173 eor(vf, rd, rn, rm);
4174 break;
4175 case NEON_BIC:
4176 bic(vf, rd, rn, rm);
4177 break;
4178 case NEON_BIF:
4179 bif(vf, rd, rn, rm);
4180 break;
4181 case NEON_BIT:
4182 bit(vf, rd, rn, rm);
4183 break;
4184 case NEON_BSL:
4185 bsl(vf, rd, rn, rm);
4186 break;
4187 default:
4188 VIXL_UNIMPLEMENTED();
4189 }
4190 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
4191 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4192 switch (instr->Mask(NEON3SameFPMask)) {
4193 case NEON_FADD:
4194 fadd(vf, rd, rn, rm);
4195 break;
4196 case NEON_FSUB:
4197 fsub(vf, rd, rn, rm);
4198 break;
4199 case NEON_FMUL:
4200 fmul(vf, rd, rn, rm);
4201 break;
4202 case NEON_FDIV:
4203 fdiv(vf, rd, rn, rm);
4204 break;
4205 case NEON_FMAX:
4206 fmax(vf, rd, rn, rm);
4207 break;
4208 case NEON_FMIN:
4209 fmin(vf, rd, rn, rm);
4210 break;
4211 case NEON_FMAXNM:
4212 fmaxnm(vf, rd, rn, rm);
4213 break;
4214 case NEON_FMINNM:
4215 fminnm(vf, rd, rn, rm);
4216 break;
4217 case NEON_FMLA:
4218 fmla(vf, rd, rn, rm);
4219 break;
4220 case NEON_FMLS:
4221 fmls(vf, rd, rn, rm);
4222 break;
4223 case NEON_FMULX:
4224 fmulx(vf, rd, rn, rm);
4225 break;
4226 case NEON_FACGE:
4227 fabscmp(vf, rd, rn, rm, ge);
4228 break;
4229 case NEON_FACGT:
4230 fabscmp(vf, rd, rn, rm, gt);
4231 break;
4232 case NEON_FCMEQ:
4233 fcmp(vf, rd, rn, rm, eq);
4234 break;
4235 case NEON_FCMGE:
4236 fcmp(vf, rd, rn, rm, ge);
4237 break;
4238 case NEON_FCMGT:
4239 fcmp(vf, rd, rn, rm, gt);
4240 break;
4241 case NEON_FRECPS:
4242 frecps(vf, rd, rn, rm);
4243 break;
4244 case NEON_FRSQRTS:
4245 frsqrts(vf, rd, rn, rm);
4246 break;
4247 case NEON_FABD:
4248 fabd(vf, rd, rn, rm);
4249 break;
4250 case NEON_FADDP:
4251 faddp(vf, rd, rn, rm);
4252 break;
4253 case NEON_FMAXP:
4254 fmaxp(vf, rd, rn, rm);
4255 break;
4256 case NEON_FMAXNMP:
4257 fmaxnmp(vf, rd, rn, rm);
4258 break;
4259 case NEON_FMINP:
4260 fminp(vf, rd, rn, rm);
4261 break;
4262 case NEON_FMINNMP:
4263 fminnmp(vf, rd, rn, rm);
4264 break;
4265 default:
4266 VIXL_UNIMPLEMENTED();
4267 }
4268 } else {
4269 VectorFormat vf = nfd.GetVectorFormat();
4270 switch (instr->Mask(NEON3SameMask)) {
4271 case NEON_ADD:
4272 add(vf, rd, rn, rm);
4273 break;
4274 case NEON_ADDP:
4275 addp(vf, rd, rn, rm);
4276 break;
4277 case NEON_CMEQ:
4278 cmp(vf, rd, rn, rm, eq);
4279 break;
4280 case NEON_CMGE:
4281 cmp(vf, rd, rn, rm, ge);
4282 break;
4283 case NEON_CMGT:
4284 cmp(vf, rd, rn, rm, gt);
4285 break;
4286 case NEON_CMHI:
4287 cmp(vf, rd, rn, rm, hi);
4288 break;
4289 case NEON_CMHS:
4290 cmp(vf, rd, rn, rm, hs);
4291 break;
4292 case NEON_CMTST:
4293 cmptst(vf, rd, rn, rm);
4294 break;
4295 case NEON_MLS:
4296 mls(vf, rd, rn, rm);
4297 break;
4298 case NEON_MLA:
4299 mla(vf, rd, rn, rm);
4300 break;
4301 case NEON_MUL:
4302 mul(vf, rd, rn, rm);
4303 break;
4304 case NEON_PMUL:
4305 pmul(vf, rd, rn, rm);
4306 break;
4307 case NEON_SMAX:
4308 smax(vf, rd, rn, rm);
4309 break;
4310 case NEON_SMAXP:
4311 smaxp(vf, rd, rn, rm);
4312 break;
4313 case NEON_SMIN:
4314 smin(vf, rd, rn, rm);
4315 break;
4316 case NEON_SMINP:
4317 sminp(vf, rd, rn, rm);
4318 break;
4319 case NEON_SUB:
4320 sub(vf, rd, rn, rm);
4321 break;
4322 case NEON_UMAX:
4323 umax(vf, rd, rn, rm);
4324 break;
4325 case NEON_UMAXP:
4326 umaxp(vf, rd, rn, rm);
4327 break;
4328 case NEON_UMIN:
4329 umin(vf, rd, rn, rm);
4330 break;
4331 case NEON_UMINP:
4332 uminp(vf, rd, rn, rm);
4333 break;
4334 case NEON_SSHL:
4335 sshl(vf, rd, rn, rm);
4336 break;
4337 case NEON_USHL:
4338 ushl(vf, rd, rn, rm);
4339 break;
4340 case NEON_SABD:
4341 absdiff(vf, rd, rn, rm, true);
4342 break;
4343 case NEON_UABD:
4344 absdiff(vf, rd, rn, rm, false);
4345 break;
4346 case NEON_SABA:
4347 saba(vf, rd, rn, rm);
4348 break;
4349 case NEON_UABA:
4350 uaba(vf, rd, rn, rm);
4351 break;
4352 case NEON_UQADD:
4353 add(vf, rd, rn, rm).UnsignedSaturate(vf);
4354 break;
4355 case NEON_SQADD:
4356 add(vf, rd, rn, rm).SignedSaturate(vf);
4357 break;
4358 case NEON_UQSUB:
4359 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
4360 break;
4361 case NEON_SQSUB:
4362 sub(vf, rd, rn, rm).SignedSaturate(vf);
4363 break;
4364 case NEON_SQDMULH:
4365 sqdmulh(vf, rd, rn, rm);
4366 break;
4367 case NEON_SQRDMULH:
4368 sqrdmulh(vf, rd, rn, rm);
4369 break;
4370 case NEON_UQSHL:
4371 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
4372 break;
4373 case NEON_SQSHL:
4374 sshl(vf, rd, rn, rm).SignedSaturate(vf);
4375 break;
4376 case NEON_URSHL:
4377 ushl(vf, rd, rn, rm).Round(vf);
4378 break;
4379 case NEON_SRSHL:
4380 sshl(vf, rd, rn, rm).Round(vf);
4381 break;
4382 case NEON_UQRSHL:
4383 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
4384 break;
4385 case NEON_SQRSHL:
4386 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
4387 break;
4388 case NEON_UHADD:
4389 add(vf, rd, rn, rm).Uhalve(vf);
4390 break;
4391 case NEON_URHADD:
4392 add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
4393 break;
4394 case NEON_SHADD:
4395 add(vf, rd, rn, rm).Halve(vf);
4396 break;
4397 case NEON_SRHADD:
4398 add(vf, rd, rn, rm).Halve(vf).Round(vf);
4399 break;
4400 case NEON_UHSUB:
4401 sub(vf, rd, rn, rm).Uhalve(vf);
4402 break;
4403 case NEON_SHSUB:
4404 sub(vf, rd, rn, rm).Halve(vf);
4405 break;
4406 default:
4407 VIXL_UNIMPLEMENTED();
4408 }
4409 }
4410 }
4411
4412
VisitNEON3SameFP16(const Instruction * instr)4413 void Simulator::VisitNEON3SameFP16(const Instruction* instr) {
4414 NEONFormatDecoder nfd(instr);
4415 SimVRegister& rd = ReadVRegister(instr->GetRd());
4416 SimVRegister& rn = ReadVRegister(instr->GetRn());
4417 SimVRegister& rm = ReadVRegister(instr->GetRm());
4418
4419 VectorFormat vf = nfd.GetVectorFormat(nfd.FP16FormatMap());
4420 switch (instr->Mask(NEON3SameFP16Mask)) {
4421 #define SIM_FUNC(A, B) \
4422 case NEON_##A##_H: \
4423 B(vf, rd, rn, rm); \
4424 break;
4425 SIM_FUNC(FMAXNM, fmaxnm);
4426 SIM_FUNC(FMLA, fmla);
4427 SIM_FUNC(FADD, fadd);
4428 SIM_FUNC(FMULX, fmulx);
4429 SIM_FUNC(FMAX, fmax);
4430 SIM_FUNC(FRECPS, frecps);
4431 SIM_FUNC(FMINNM, fminnm);
4432 SIM_FUNC(FMLS, fmls);
4433 SIM_FUNC(FSUB, fsub);
4434 SIM_FUNC(FMIN, fmin);
4435 SIM_FUNC(FRSQRTS, frsqrts);
4436 SIM_FUNC(FMAXNMP, fmaxnmp);
4437 SIM_FUNC(FADDP, faddp);
4438 SIM_FUNC(FMUL, fmul);
4439 SIM_FUNC(FMAXP, fmaxp);
4440 SIM_FUNC(FDIV, fdiv);
4441 SIM_FUNC(FMINNMP, fminnmp);
4442 SIM_FUNC(FABD, fabd);
4443 SIM_FUNC(FMINP, fminp);
4444 #undef SIM_FUNC
4445 case NEON_FCMEQ_H:
4446 fcmp(vf, rd, rn, rm, eq);
4447 break;
4448 case NEON_FCMGE_H:
4449 fcmp(vf, rd, rn, rm, ge);
4450 break;
4451 case NEON_FACGE_H:
4452 fabscmp(vf, rd, rn, rm, ge);
4453 break;
4454 case NEON_FCMGT_H:
4455 fcmp(vf, rd, rn, rm, gt);
4456 break;
4457 case NEON_FACGT_H:
4458 fabscmp(vf, rd, rn, rm, gt);
4459 break;
4460 default:
4461 VIXL_UNIMPLEMENTED();
4462 break;
4463 }
4464 }
4465
VisitNEON3SameExtra(const Instruction * instr)4466 void Simulator::VisitNEON3SameExtra(const Instruction* instr) {
4467 NEONFormatDecoder nfd(instr);
4468 SimVRegister& rd = ReadVRegister(instr->GetRd());
4469 SimVRegister& rn = ReadVRegister(instr->GetRn());
4470 SimVRegister& rm = ReadVRegister(instr->GetRm());
4471 int rot = 0;
4472 VectorFormat vf = nfd.GetVectorFormat();
4473 if (instr->Mask(NEON3SameExtraFCMLAMask) == NEON_FCMLA) {
4474 rot = instr->GetImmRotFcmlaVec();
4475 fcmla(vf, rd, rn, rm, rot);
4476 } else if (instr->Mask(NEON3SameExtraFCADDMask) == NEON_FCADD) {
4477 rot = instr->GetImmRotFcadd();
4478 fcadd(vf, rd, rn, rm, rot);
4479 } else {
4480 switch (instr->Mask(NEON3SameExtraMask)) {
4481 case NEON_SDOT:
4482 sdot(vf, rd, rn, rm);
4483 break;
4484 case NEON_SQRDMLAH:
4485 sqrdmlah(vf, rd, rn, rm);
4486 break;
4487 case NEON_UDOT:
4488 udot(vf, rd, rn, rm);
4489 break;
4490 case NEON_SQRDMLSH:
4491 sqrdmlsh(vf, rd, rn, rm);
4492 break;
4493 default:
4494 VIXL_UNIMPLEMENTED();
4495 break;
4496 }
4497 }
4498 }
4499
4500
VisitNEON3Different(const Instruction * instr)4501 void Simulator::VisitNEON3Different(const Instruction* instr) {
4502 NEONFormatDecoder nfd(instr);
4503 VectorFormat vf = nfd.GetVectorFormat();
4504 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4505
4506 SimVRegister& rd = ReadVRegister(instr->GetRd());
4507 SimVRegister& rn = ReadVRegister(instr->GetRn());
4508 SimVRegister& rm = ReadVRegister(instr->GetRm());
4509
4510 switch (instr->Mask(NEON3DifferentMask)) {
4511 case NEON_PMULL:
4512 pmull(vf_l, rd, rn, rm);
4513 break;
4514 case NEON_PMULL2:
4515 pmull2(vf_l, rd, rn, rm);
4516 break;
4517 case NEON_UADDL:
4518 uaddl(vf_l, rd, rn, rm);
4519 break;
4520 case NEON_UADDL2:
4521 uaddl2(vf_l, rd, rn, rm);
4522 break;
4523 case NEON_SADDL:
4524 saddl(vf_l, rd, rn, rm);
4525 break;
4526 case NEON_SADDL2:
4527 saddl2(vf_l, rd, rn, rm);
4528 break;
4529 case NEON_USUBL:
4530 usubl(vf_l, rd, rn, rm);
4531 break;
4532 case NEON_USUBL2:
4533 usubl2(vf_l, rd, rn, rm);
4534 break;
4535 case NEON_SSUBL:
4536 ssubl(vf_l, rd, rn, rm);
4537 break;
4538 case NEON_SSUBL2:
4539 ssubl2(vf_l, rd, rn, rm);
4540 break;
4541 case NEON_SABAL:
4542 sabal(vf_l, rd, rn, rm);
4543 break;
4544 case NEON_SABAL2:
4545 sabal2(vf_l, rd, rn, rm);
4546 break;
4547 case NEON_UABAL:
4548 uabal(vf_l, rd, rn, rm);
4549 break;
4550 case NEON_UABAL2:
4551 uabal2(vf_l, rd, rn, rm);
4552 break;
4553 case NEON_SABDL:
4554 sabdl(vf_l, rd, rn, rm);
4555 break;
4556 case NEON_SABDL2:
4557 sabdl2(vf_l, rd, rn, rm);
4558 break;
4559 case NEON_UABDL:
4560 uabdl(vf_l, rd, rn, rm);
4561 break;
4562 case NEON_UABDL2:
4563 uabdl2(vf_l, rd, rn, rm);
4564 break;
4565 case NEON_SMLAL:
4566 smlal(vf_l, rd, rn, rm);
4567 break;
4568 case NEON_SMLAL2:
4569 smlal2(vf_l, rd, rn, rm);
4570 break;
4571 case NEON_UMLAL:
4572 umlal(vf_l, rd, rn, rm);
4573 break;
4574 case NEON_UMLAL2:
4575 umlal2(vf_l, rd, rn, rm);
4576 break;
4577 case NEON_SMLSL:
4578 smlsl(vf_l, rd, rn, rm);
4579 break;
4580 case NEON_SMLSL2:
4581 smlsl2(vf_l, rd, rn, rm);
4582 break;
4583 case NEON_UMLSL:
4584 umlsl(vf_l, rd, rn, rm);
4585 break;
4586 case NEON_UMLSL2:
4587 umlsl2(vf_l, rd, rn, rm);
4588 break;
4589 case NEON_SMULL:
4590 smull(vf_l, rd, rn, rm);
4591 break;
4592 case NEON_SMULL2:
4593 smull2(vf_l, rd, rn, rm);
4594 break;
4595 case NEON_UMULL:
4596 umull(vf_l, rd, rn, rm);
4597 break;
4598 case NEON_UMULL2:
4599 umull2(vf_l, rd, rn, rm);
4600 break;
4601 case NEON_SQDMLAL:
4602 sqdmlal(vf_l, rd, rn, rm);
4603 break;
4604 case NEON_SQDMLAL2:
4605 sqdmlal2(vf_l, rd, rn, rm);
4606 break;
4607 case NEON_SQDMLSL:
4608 sqdmlsl(vf_l, rd, rn, rm);
4609 break;
4610 case NEON_SQDMLSL2:
4611 sqdmlsl2(vf_l, rd, rn, rm);
4612 break;
4613 case NEON_SQDMULL:
4614 sqdmull(vf_l, rd, rn, rm);
4615 break;
4616 case NEON_SQDMULL2:
4617 sqdmull2(vf_l, rd, rn, rm);
4618 break;
4619 case NEON_UADDW:
4620 uaddw(vf_l, rd, rn, rm);
4621 break;
4622 case NEON_UADDW2:
4623 uaddw2(vf_l, rd, rn, rm);
4624 break;
4625 case NEON_SADDW:
4626 saddw(vf_l, rd, rn, rm);
4627 break;
4628 case NEON_SADDW2:
4629 saddw2(vf_l, rd, rn, rm);
4630 break;
4631 case NEON_USUBW:
4632 usubw(vf_l, rd, rn, rm);
4633 break;
4634 case NEON_USUBW2:
4635 usubw2(vf_l, rd, rn, rm);
4636 break;
4637 case NEON_SSUBW:
4638 ssubw(vf_l, rd, rn, rm);
4639 break;
4640 case NEON_SSUBW2:
4641 ssubw2(vf_l, rd, rn, rm);
4642 break;
4643 case NEON_ADDHN:
4644 addhn(vf, rd, rn, rm);
4645 break;
4646 case NEON_ADDHN2:
4647 addhn2(vf, rd, rn, rm);
4648 break;
4649 case NEON_RADDHN:
4650 raddhn(vf, rd, rn, rm);
4651 break;
4652 case NEON_RADDHN2:
4653 raddhn2(vf, rd, rn, rm);
4654 break;
4655 case NEON_SUBHN:
4656 subhn(vf, rd, rn, rm);
4657 break;
4658 case NEON_SUBHN2:
4659 subhn2(vf, rd, rn, rm);
4660 break;
4661 case NEON_RSUBHN:
4662 rsubhn(vf, rd, rn, rm);
4663 break;
4664 case NEON_RSUBHN2:
4665 rsubhn2(vf, rd, rn, rm);
4666 break;
4667 default:
4668 VIXL_UNIMPLEMENTED();
4669 }
4670 }
4671
4672
VisitNEONAcrossLanes(const Instruction * instr)4673 void Simulator::VisitNEONAcrossLanes(const Instruction* instr) {
4674 NEONFormatDecoder nfd(instr);
4675
4676 static const NEONFormatMap map_half = {{30}, {NF_4H, NF_8H}};
4677
4678 SimVRegister& rd = ReadVRegister(instr->GetRd());
4679 SimVRegister& rn = ReadVRegister(instr->GetRn());
4680
4681 if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) {
4682 VectorFormat vf = nfd.GetVectorFormat(&map_half);
4683 switch (instr->Mask(NEONAcrossLanesFP16Mask)) {
4684 case NEON_FMAXV_H:
4685 fmaxv(vf, rd, rn);
4686 break;
4687 case NEON_FMINV_H:
4688 fminv(vf, rd, rn);
4689 break;
4690 case NEON_FMAXNMV_H:
4691 fmaxnmv(vf, rd, rn);
4692 break;
4693 case NEON_FMINNMV_H:
4694 fminnmv(vf, rd, rn);
4695 break;
4696 default:
4697 VIXL_UNIMPLEMENTED();
4698 }
4699 } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
4700 // The input operand's VectorFormat is passed for these instructions.
4701 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4702
4703 switch (instr->Mask(NEONAcrossLanesFPMask)) {
4704 case NEON_FMAXV:
4705 fmaxv(vf, rd, rn);
4706 break;
4707 case NEON_FMINV:
4708 fminv(vf, rd, rn);
4709 break;
4710 case NEON_FMAXNMV:
4711 fmaxnmv(vf, rd, rn);
4712 break;
4713 case NEON_FMINNMV:
4714 fminnmv(vf, rd, rn);
4715 break;
4716 default:
4717 VIXL_UNIMPLEMENTED();
4718 }
4719 } else {
4720 VectorFormat vf = nfd.GetVectorFormat();
4721
4722 switch (instr->Mask(NEONAcrossLanesMask)) {
4723 case NEON_ADDV:
4724 addv(vf, rd, rn);
4725 break;
4726 case NEON_SMAXV:
4727 smaxv(vf, rd, rn);
4728 break;
4729 case NEON_SMINV:
4730 sminv(vf, rd, rn);
4731 break;
4732 case NEON_UMAXV:
4733 umaxv(vf, rd, rn);
4734 break;
4735 case NEON_UMINV:
4736 uminv(vf, rd, rn);
4737 break;
4738 case NEON_SADDLV:
4739 saddlv(vf, rd, rn);
4740 break;
4741 case NEON_UADDLV:
4742 uaddlv(vf, rd, rn);
4743 break;
4744 default:
4745 VIXL_UNIMPLEMENTED();
4746 }
4747 }
4748 }
4749
4750
VisitNEONByIndexedElement(const Instruction * instr)4751 void Simulator::VisitNEONByIndexedElement(const Instruction* instr) {
4752 NEONFormatDecoder nfd(instr);
4753 static const NEONFormatMap map_half = {{30}, {NF_4H, NF_8H}};
4754 VectorFormat vf_r = nfd.GetVectorFormat();
4755 VectorFormat vf_half = nfd.GetVectorFormat(&map_half);
4756 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4757
4758 SimVRegister& rd = ReadVRegister(instr->GetRd());
4759 SimVRegister& rn = ReadVRegister(instr->GetRn());
4760
4761 ByElementOp Op = NULL;
4762
4763 int rm_reg = instr->GetRm();
4764 int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
4765 if (instr->GetNEONSize() == 1) {
4766 rm_reg &= 0xf;
4767 index = (index << 1) | instr->GetNEONM();
4768 }
4769
4770 switch (instr->Mask(NEONByIndexedElementMask)) {
4771 case NEON_MUL_byelement:
4772 Op = &Simulator::mul;
4773 vf = vf_r;
4774 break;
4775 case NEON_MLA_byelement:
4776 Op = &Simulator::mla;
4777 vf = vf_r;
4778 break;
4779 case NEON_MLS_byelement:
4780 Op = &Simulator::mls;
4781 vf = vf_r;
4782 break;
4783 case NEON_SQDMULH_byelement:
4784 Op = &Simulator::sqdmulh;
4785 vf = vf_r;
4786 break;
4787 case NEON_SQRDMULH_byelement:
4788 Op = &Simulator::sqrdmulh;
4789 vf = vf_r;
4790 break;
4791 case NEON_SDOT_byelement:
4792 Op = &Simulator::sdot;
4793 vf = vf_r;
4794 break;
4795 case NEON_SQRDMLAH_byelement:
4796 Op = &Simulator::sqrdmlah;
4797 vf = vf_r;
4798 break;
4799 case NEON_UDOT_byelement:
4800 Op = &Simulator::udot;
4801 vf = vf_r;
4802 break;
4803 case NEON_SQRDMLSH_byelement:
4804 Op = &Simulator::sqrdmlsh;
4805 vf = vf_r;
4806 break;
4807 case NEON_SMULL_byelement:
4808 if (instr->Mask(NEON_Q)) {
4809 Op = &Simulator::smull2;
4810 } else {
4811 Op = &Simulator::smull;
4812 }
4813 break;
4814 case NEON_UMULL_byelement:
4815 if (instr->Mask(NEON_Q)) {
4816 Op = &Simulator::umull2;
4817 } else {
4818 Op = &Simulator::umull;
4819 }
4820 break;
4821 case NEON_SMLAL_byelement:
4822 if (instr->Mask(NEON_Q)) {
4823 Op = &Simulator::smlal2;
4824 } else {
4825 Op = &Simulator::smlal;
4826 }
4827 break;
4828 case NEON_UMLAL_byelement:
4829 if (instr->Mask(NEON_Q)) {
4830 Op = &Simulator::umlal2;
4831 } else {
4832 Op = &Simulator::umlal;
4833 }
4834 break;
4835 case NEON_SMLSL_byelement:
4836 if (instr->Mask(NEON_Q)) {
4837 Op = &Simulator::smlsl2;
4838 } else {
4839 Op = &Simulator::smlsl;
4840 }
4841 break;
4842 case NEON_UMLSL_byelement:
4843 if (instr->Mask(NEON_Q)) {
4844 Op = &Simulator::umlsl2;
4845 } else {
4846 Op = &Simulator::umlsl;
4847 }
4848 break;
4849 case NEON_SQDMULL_byelement:
4850 if (instr->Mask(NEON_Q)) {
4851 Op = &Simulator::sqdmull2;
4852 } else {
4853 Op = &Simulator::sqdmull;
4854 }
4855 break;
4856 case NEON_SQDMLAL_byelement:
4857 if (instr->Mask(NEON_Q)) {
4858 Op = &Simulator::sqdmlal2;
4859 } else {
4860 Op = &Simulator::sqdmlal;
4861 }
4862 break;
4863 case NEON_SQDMLSL_byelement:
4864 if (instr->Mask(NEON_Q)) {
4865 Op = &Simulator::sqdmlsl2;
4866 } else {
4867 Op = &Simulator::sqdmlsl;
4868 }
4869 break;
4870 default:
4871 index = instr->GetNEONH();
4872 if (instr->GetFPType() == 0) {
4873 rm_reg &= 0xf;
4874 index = (index << 2) | (instr->GetNEONL() << 1) | instr->GetNEONM();
4875 } else if ((instr->GetFPType() & 1) == 0) {
4876 index = (index << 1) | instr->GetNEONL();
4877 }
4878
4879 vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4880
4881 switch (instr->Mask(NEONByIndexedElementFPMask)) {
4882 case NEON_FMUL_H_byelement:
4883 vf = vf_half;
4884 VIXL_FALLTHROUGH();
4885 case NEON_FMUL_byelement:
4886 Op = &Simulator::fmul;
4887 break;
4888 case NEON_FMLA_H_byelement:
4889 vf = vf_half;
4890 VIXL_FALLTHROUGH();
4891 case NEON_FMLA_byelement:
4892 Op = &Simulator::fmla;
4893 break;
4894 case NEON_FMLS_H_byelement:
4895 vf = vf_half;
4896 VIXL_FALLTHROUGH();
4897 case NEON_FMLS_byelement:
4898 Op = &Simulator::fmls;
4899 break;
4900 case NEON_FMULX_H_byelement:
4901 vf = vf_half;
4902 VIXL_FALLTHROUGH();
4903 case NEON_FMULX_byelement:
4904 Op = &Simulator::fmulx;
4905 break;
4906 default:
4907 if (instr->GetNEONSize() == 2)
4908 index = instr->GetNEONH();
4909 else
4910 index = (instr->GetNEONH() << 1) | instr->GetNEONL();
4911 switch (instr->Mask(NEONByIndexedElementFPComplexMask)) {
4912 case NEON_FCMLA_byelement:
4913 vf = vf_r;
4914 fcmla(vf,
4915 rd,
4916 rn,
4917 ReadVRegister(instr->GetRm()),
4918 index,
4919 instr->GetImmRotFcmlaSca());
4920 return;
4921 default:
4922 VIXL_UNIMPLEMENTED();
4923 }
4924 }
4925 }
4926
4927 (this->*Op)(vf, rd, rn, ReadVRegister(rm_reg), index);
4928 }
4929
4930
VisitNEONCopy(const Instruction * instr)4931 void Simulator::VisitNEONCopy(const Instruction* instr) {
4932 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
4933 VectorFormat vf = nfd.GetVectorFormat();
4934
4935 SimVRegister& rd = ReadVRegister(instr->GetRd());
4936 SimVRegister& rn = ReadVRegister(instr->GetRn());
4937 int imm5 = instr->GetImmNEON5();
4938 int tz = CountTrailingZeros(imm5, 32);
4939 int reg_index = imm5 >> (tz + 1);
4940
4941 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
4942 int imm4 = instr->GetImmNEON4();
4943 int rn_index = imm4 >> tz;
4944 ins_element(vf, rd, reg_index, rn, rn_index);
4945 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
4946 ins_immediate(vf, rd, reg_index, ReadXRegister(instr->GetRn()));
4947 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
4948 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
4949 value &= MaxUintFromFormat(vf);
4950 WriteXRegister(instr->GetRd(), value);
4951 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
4952 int64_t value = LogicVRegister(rn).Int(vf, reg_index);
4953 if (instr->GetNEONQ()) {
4954 WriteXRegister(instr->GetRd(), value);
4955 } else {
4956 WriteWRegister(instr->GetRd(), (int32_t)value);
4957 }
4958 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
4959 dup_element(vf, rd, rn, reg_index);
4960 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
4961 dup_immediate(vf, rd, ReadXRegister(instr->GetRn()));
4962 } else {
4963 VIXL_UNIMPLEMENTED();
4964 }
4965 }
4966
4967
VisitNEONExtract(const Instruction * instr)4968 void Simulator::VisitNEONExtract(const Instruction* instr) {
4969 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
4970 VectorFormat vf = nfd.GetVectorFormat();
4971 SimVRegister& rd = ReadVRegister(instr->GetRd());
4972 SimVRegister& rn = ReadVRegister(instr->GetRn());
4973 SimVRegister& rm = ReadVRegister(instr->GetRm());
4974 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
4975 int index = instr->GetImmNEONExt();
4976 ext(vf, rd, rn, rm, index);
4977 } else {
4978 VIXL_UNIMPLEMENTED();
4979 }
4980 }
4981
4982
NEONLoadStoreMultiStructHelper(const Instruction * instr,AddrMode addr_mode)4983 void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
4984 AddrMode addr_mode) {
4985 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
4986 VectorFormat vf = nfd.GetVectorFormat();
4987
4988 uint64_t addr_base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
4989 int reg_size = RegisterSizeInBytesFromFormat(vf);
4990
4991 int reg[4];
4992 uint64_t addr[4];
4993 for (int i = 0; i < 4; i++) {
4994 reg[i] = (instr->GetRt() + i) % kNumberOfVRegisters;
4995 addr[i] = addr_base + (i * reg_size);
4996 }
4997 int count = 1;
4998 bool log_read = true;
4999
5000 // Bit 23 determines whether this is an offset or post-index addressing mode.
5001 // In offset mode, bits 20 to 16 should be zero; these bits encode the
5002 // register or immediate in post-index mode.
5003 if ((instr->ExtractBit(23) == 0) && (instr->ExtractBits(20, 16) != 0)) {
5004 VIXL_UNREACHABLE();
5005 }
5006
5007 // We use the PostIndex mask here, as it works in this case for both Offset
5008 // and PostIndex addressing.
5009 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
5010 case NEON_LD1_4v:
5011 case NEON_LD1_4v_post:
5012 ld1(vf, ReadVRegister(reg[3]), addr[3]);
5013 count++;
5014 VIXL_FALLTHROUGH();
5015 case NEON_LD1_3v:
5016 case NEON_LD1_3v_post:
5017 ld1(vf, ReadVRegister(reg[2]), addr[2]);
5018 count++;
5019 VIXL_FALLTHROUGH();
5020 case NEON_LD1_2v:
5021 case NEON_LD1_2v_post:
5022 ld1(vf, ReadVRegister(reg[1]), addr[1]);
5023 count++;
5024 VIXL_FALLTHROUGH();
5025 case NEON_LD1_1v:
5026 case NEON_LD1_1v_post:
5027 ld1(vf, ReadVRegister(reg[0]), addr[0]);
5028 break;
5029 case NEON_ST1_4v:
5030 case NEON_ST1_4v_post:
5031 st1(vf, ReadVRegister(reg[3]), addr[3]);
5032 count++;
5033 VIXL_FALLTHROUGH();
5034 case NEON_ST1_3v:
5035 case NEON_ST1_3v_post:
5036 st1(vf, ReadVRegister(reg[2]), addr[2]);
5037 count++;
5038 VIXL_FALLTHROUGH();
5039 case NEON_ST1_2v:
5040 case NEON_ST1_2v_post:
5041 st1(vf, ReadVRegister(reg[1]), addr[1]);
5042 count++;
5043 VIXL_FALLTHROUGH();
5044 case NEON_ST1_1v:
5045 case NEON_ST1_1v_post:
5046 st1(vf, ReadVRegister(reg[0]), addr[0]);
5047 log_read = false;
5048 break;
5049 case NEON_LD2_post:
5050 case NEON_LD2:
5051 ld2(vf, ReadVRegister(reg[0]), ReadVRegister(reg[1]), addr[0]);
5052 count = 2;
5053 break;
5054 case NEON_ST2:
5055 case NEON_ST2_post:
5056 st2(vf, ReadVRegister(reg[0]), ReadVRegister(reg[1]), addr[0]);
5057 count = 2;
5058 log_read = false;
5059 break;
5060 case NEON_LD3_post:
5061 case NEON_LD3:
5062 ld3(vf,
5063 ReadVRegister(reg[0]),
5064 ReadVRegister(reg[1]),
5065 ReadVRegister(reg[2]),
5066 addr[0]);
5067 count = 3;
5068 break;
5069 case NEON_ST3:
5070 case NEON_ST3_post:
5071 st3(vf,
5072 ReadVRegister(reg[0]),
5073 ReadVRegister(reg[1]),
5074 ReadVRegister(reg[2]),
5075 addr[0]);
5076 count = 3;
5077 log_read = false;
5078 break;
5079 case NEON_ST4:
5080 case NEON_ST4_post:
5081 st4(vf,
5082 ReadVRegister(reg[0]),
5083 ReadVRegister(reg[1]),
5084 ReadVRegister(reg[2]),
5085 ReadVRegister(reg[3]),
5086 addr[0]);
5087 count = 4;
5088 log_read = false;
5089 break;
5090 case NEON_LD4_post:
5091 case NEON_LD4:
5092 ld4(vf,
5093 ReadVRegister(reg[0]),
5094 ReadVRegister(reg[1]),
5095 ReadVRegister(reg[2]),
5096 ReadVRegister(reg[3]),
5097 addr[0]);
5098 count = 4;
5099 break;
5100 default:
5101 VIXL_UNIMPLEMENTED();
5102 }
5103
5104 // Explicitly log the register update whilst we have type information.
5105 for (int i = 0; i < count; i++) {
5106 // For de-interleaving loads, only print the base address.
5107 int lane_size = LaneSizeInBytesFromFormat(vf);
5108 PrintRegisterFormat format = GetPrintRegisterFormatTryFP(
5109 GetPrintRegisterFormatForSize(reg_size, lane_size));
5110 if (log_read) {
5111 LogVRead(addr_base, reg[i], format);
5112 } else {
5113 LogVWrite(addr_base, reg[i], format);
5114 }
5115 }
5116
5117 if (addr_mode == PostIndex) {
5118 int rm = instr->GetRm();
5119 // The immediate post index addressing mode is indicated by rm = 31.
5120 // The immediate is implied by the number of vector registers used.
5121 addr_base += (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count
5122 : ReadXRegister(rm);
5123 WriteXRegister(instr->GetRn(), addr_base);
5124 } else {
5125 VIXL_ASSERT(addr_mode == Offset);
5126 }
5127 }
5128
5129
VisitNEONLoadStoreMultiStruct(const Instruction * instr)5130 void Simulator::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
5131 NEONLoadStoreMultiStructHelper(instr, Offset);
5132 }
5133
5134
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)5135 void Simulator::VisitNEONLoadStoreMultiStructPostIndex(
5136 const Instruction* instr) {
5137 NEONLoadStoreMultiStructHelper(instr, PostIndex);
5138 }
5139
5140
NEONLoadStoreSingleStructHelper(const Instruction * instr,AddrMode addr_mode)5141 void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
5142 AddrMode addr_mode) {
5143 uint64_t addr = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
5144 int rt = instr->GetRt();
5145
5146 // Bit 23 determines whether this is an offset or post-index addressing mode.
5147 // In offset mode, bits 20 to 16 should be zero; these bits encode the
5148 // register or immediate in post-index mode.
5149 if ((instr->ExtractBit(23) == 0) && (instr->ExtractBits(20, 16) != 0)) {
5150 VIXL_UNREACHABLE();
5151 }
5152
5153 // We use the PostIndex mask here, as it works in this case for both Offset
5154 // and PostIndex addressing.
5155 bool do_load = false;
5156
5157 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
5158 VectorFormat vf_t = nfd.GetVectorFormat();
5159
5160 VectorFormat vf = kFormat16B;
5161 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
5162 case NEON_LD1_b:
5163 case NEON_LD1_b_post:
5164 case NEON_LD2_b:
5165 case NEON_LD2_b_post:
5166 case NEON_LD3_b:
5167 case NEON_LD3_b_post:
5168 case NEON_LD4_b:
5169 case NEON_LD4_b_post:
5170 do_load = true;
5171 VIXL_FALLTHROUGH();
5172 case NEON_ST1_b:
5173 case NEON_ST1_b_post:
5174 case NEON_ST2_b:
5175 case NEON_ST2_b_post:
5176 case NEON_ST3_b:
5177 case NEON_ST3_b_post:
5178 case NEON_ST4_b:
5179 case NEON_ST4_b_post:
5180 break;
5181
5182 case NEON_LD1_h:
5183 case NEON_LD1_h_post:
5184 case NEON_LD2_h:
5185 case NEON_LD2_h_post:
5186 case NEON_LD3_h:
5187 case NEON_LD3_h_post:
5188 case NEON_LD4_h:
5189 case NEON_LD4_h_post:
5190 do_load = true;
5191 VIXL_FALLTHROUGH();
5192 case NEON_ST1_h:
5193 case NEON_ST1_h_post:
5194 case NEON_ST2_h:
5195 case NEON_ST2_h_post:
5196 case NEON_ST3_h:
5197 case NEON_ST3_h_post:
5198 case NEON_ST4_h:
5199 case NEON_ST4_h_post:
5200 vf = kFormat8H;
5201 break;
5202 case NEON_LD1_s:
5203 case NEON_LD1_s_post:
5204 case NEON_LD2_s:
5205 case NEON_LD2_s_post:
5206 case NEON_LD3_s:
5207 case NEON_LD3_s_post:
5208 case NEON_LD4_s:
5209 case NEON_LD4_s_post:
5210 do_load = true;
5211 VIXL_FALLTHROUGH();
5212 case NEON_ST1_s:
5213 case NEON_ST1_s_post:
5214 case NEON_ST2_s:
5215 case NEON_ST2_s_post:
5216 case NEON_ST3_s:
5217 case NEON_ST3_s_post:
5218 case NEON_ST4_s:
5219 case NEON_ST4_s_post: {
5220 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
5221 VIXL_STATIC_ASSERT((NEON_LD1_s_post | (1 << NEONLSSize_offset)) ==
5222 NEON_LD1_d_post);
5223 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
5224 VIXL_STATIC_ASSERT((NEON_ST1_s_post | (1 << NEONLSSize_offset)) ==
5225 NEON_ST1_d_post);
5226 vf = ((instr->GetNEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
5227 break;
5228 }
5229
5230 case NEON_LD1R:
5231 case NEON_LD1R_post: {
5232 vf = vf_t;
5233 ld1r(vf, ReadVRegister(rt), addr);
5234 do_load = true;
5235 break;
5236 }
5237
5238 case NEON_LD2R:
5239 case NEON_LD2R_post: {
5240 vf = vf_t;
5241 int rt2 = (rt + 1) % kNumberOfVRegisters;
5242 ld2r(vf, ReadVRegister(rt), ReadVRegister(rt2), addr);
5243 do_load = true;
5244 break;
5245 }
5246
5247 case NEON_LD3R:
5248 case NEON_LD3R_post: {
5249 vf = vf_t;
5250 int rt2 = (rt + 1) % kNumberOfVRegisters;
5251 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5252 ld3r(vf, ReadVRegister(rt), ReadVRegister(rt2), ReadVRegister(rt3), addr);
5253 do_load = true;
5254 break;
5255 }
5256
5257 case NEON_LD4R:
5258 case NEON_LD4R_post: {
5259 vf = vf_t;
5260 int rt2 = (rt + 1) % kNumberOfVRegisters;
5261 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5262 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
5263 ld4r(vf,
5264 ReadVRegister(rt),
5265 ReadVRegister(rt2),
5266 ReadVRegister(rt3),
5267 ReadVRegister(rt4),
5268 addr);
5269 do_load = true;
5270 break;
5271 }
5272 default:
5273 VIXL_UNIMPLEMENTED();
5274 }
5275
5276 PrintRegisterFormat print_format =
5277 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
5278 // Make sure that the print_format only includes a single lane.
5279 print_format =
5280 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask);
5281
5282 int esize = LaneSizeInBytesFromFormat(vf);
5283 int index_shift = LaneSizeInBytesLog2FromFormat(vf);
5284 int lane = instr->GetNEONLSIndex(index_shift);
5285 int scale = 0;
5286 int rt2 = (rt + 1) % kNumberOfVRegisters;
5287 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5288 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
5289 switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
5290 case NEONLoadStoreSingle1:
5291 scale = 1;
5292 if (do_load) {
5293 ld1(vf, ReadVRegister(rt), lane, addr);
5294 LogVRead(addr, rt, print_format, lane);
5295 } else {
5296 st1(vf, ReadVRegister(rt), lane, addr);
5297 LogVWrite(addr, rt, print_format, lane);
5298 }
5299 break;
5300 case NEONLoadStoreSingle2:
5301 scale = 2;
5302 if (do_load) {
5303 ld2(vf, ReadVRegister(rt), ReadVRegister(rt2), lane, addr);
5304 LogVRead(addr, rt, print_format, lane);
5305 LogVRead(addr + esize, rt2, print_format, lane);
5306 } else {
5307 st2(vf, ReadVRegister(rt), ReadVRegister(rt2), lane, addr);
5308 LogVWrite(addr, rt, print_format, lane);
5309 LogVWrite(addr + esize, rt2, print_format, lane);
5310 }
5311 break;
5312 case NEONLoadStoreSingle3:
5313 scale = 3;
5314 if (do_load) {
5315 ld3(vf,
5316 ReadVRegister(rt),
5317 ReadVRegister(rt2),
5318 ReadVRegister(rt3),
5319 lane,
5320 addr);
5321 LogVRead(addr, rt, print_format, lane);
5322 LogVRead(addr + esize, rt2, print_format, lane);
5323 LogVRead(addr + (2 * esize), rt3, print_format, lane);
5324 } else {
5325 st3(vf,
5326 ReadVRegister(rt),
5327 ReadVRegister(rt2),
5328 ReadVRegister(rt3),
5329 lane,
5330 addr);
5331 LogVWrite(addr, rt, print_format, lane);
5332 LogVWrite(addr + esize, rt2, print_format, lane);
5333 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
5334 }
5335 break;
5336 case NEONLoadStoreSingle4:
5337 scale = 4;
5338 if (do_load) {
5339 ld4(vf,
5340 ReadVRegister(rt),
5341 ReadVRegister(rt2),
5342 ReadVRegister(rt3),
5343 ReadVRegister(rt4),
5344 lane,
5345 addr);
5346 LogVRead(addr, rt, print_format, lane);
5347 LogVRead(addr + esize, rt2, print_format, lane);
5348 LogVRead(addr + (2 * esize), rt3, print_format, lane);
5349 LogVRead(addr + (3 * esize), rt4, print_format, lane);
5350 } else {
5351 st4(vf,
5352 ReadVRegister(rt),
5353 ReadVRegister(rt2),
5354 ReadVRegister(rt3),
5355 ReadVRegister(rt4),
5356 lane,
5357 addr);
5358 LogVWrite(addr, rt, print_format, lane);
5359 LogVWrite(addr + esize, rt2, print_format, lane);
5360 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
5361 LogVWrite(addr + (3 * esize), rt4, print_format, lane);
5362 }
5363 break;
5364 default:
5365 VIXL_UNIMPLEMENTED();
5366 }
5367
5368 if (addr_mode == PostIndex) {
5369 int rm = instr->GetRm();
5370 int lane_size = LaneSizeInBytesFromFormat(vf);
5371 WriteXRegister(instr->GetRn(),
5372 addr +
5373 ((rm == 31) ? (scale * lane_size) : ReadXRegister(rm)));
5374 }
5375 }
5376
5377
VisitNEONLoadStoreSingleStruct(const Instruction * instr)5378 void Simulator::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
5379 NEONLoadStoreSingleStructHelper(instr, Offset);
5380 }
5381
5382
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)5383 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(
5384 const Instruction* instr) {
5385 NEONLoadStoreSingleStructHelper(instr, PostIndex);
5386 }
5387
5388
VisitNEONModifiedImmediate(const Instruction * instr)5389 void Simulator::VisitNEONModifiedImmediate(const Instruction* instr) {
5390 SimVRegister& rd = ReadVRegister(instr->GetRd());
5391 int cmode = instr->GetNEONCmode();
5392 int cmode_3_1 = (cmode >> 1) & 7;
5393 int cmode_3 = (cmode >> 3) & 1;
5394 int cmode_2 = (cmode >> 2) & 1;
5395 int cmode_1 = (cmode >> 1) & 1;
5396 int cmode_0 = cmode & 1;
5397 int half_enc = instr->ExtractBit(11);
5398 int q = instr->GetNEONQ();
5399 int op_bit = instr->GetNEONModImmOp();
5400 uint64_t imm8 = instr->GetImmNEONabcdefgh();
5401 // Find the format and immediate value
5402 uint64_t imm = 0;
5403 VectorFormat vform = kFormatUndefined;
5404 switch (cmode_3_1) {
5405 case 0x0:
5406 case 0x1:
5407 case 0x2:
5408 case 0x3:
5409 vform = (q == 1) ? kFormat4S : kFormat2S;
5410 imm = imm8 << (8 * cmode_3_1);
5411 break;
5412 case 0x4:
5413 case 0x5:
5414 vform = (q == 1) ? kFormat8H : kFormat4H;
5415 imm = imm8 << (8 * cmode_1);
5416 break;
5417 case 0x6:
5418 vform = (q == 1) ? kFormat4S : kFormat2S;
5419 if (cmode_0 == 0) {
5420 imm = imm8 << 8 | 0x000000ff;
5421 } else {
5422 imm = imm8 << 16 | 0x0000ffff;
5423 }
5424 break;
5425 case 0x7:
5426 if (cmode_0 == 0 && op_bit == 0) {
5427 vform = q ? kFormat16B : kFormat8B;
5428 imm = imm8;
5429 } else if (cmode_0 == 0 && op_bit == 1) {
5430 vform = q ? kFormat2D : kFormat1D;
5431 imm = 0;
5432 for (int i = 0; i < 8; ++i) {
5433 if (imm8 & (1 << i)) {
5434 imm |= (UINT64_C(0xff) << (8 * i));
5435 }
5436 }
5437 } else { // cmode_0 == 1, cmode == 0xf.
5438 if (half_enc == 1) {
5439 vform = q ? kFormat8H : kFormat4H;
5440 imm = Float16ToRawbits(instr->GetImmNEONFP16());
5441 } else if (op_bit == 0) {
5442 vform = q ? kFormat4S : kFormat2S;
5443 imm = FloatToRawbits(instr->GetImmNEONFP32());
5444 } else if (q == 1) {
5445 vform = kFormat2D;
5446 imm = DoubleToRawbits(instr->GetImmNEONFP64());
5447 } else {
5448 VIXL_ASSERT((q == 0) && (op_bit == 1) && (cmode == 0xf));
5449 VisitUnallocated(instr);
5450 }
5451 }
5452 break;
5453 default:
5454 VIXL_UNREACHABLE();
5455 break;
5456 }
5457
5458 // Find the operation
5459 NEONModifiedImmediateOp op;
5460 if (cmode_3 == 0) {
5461 if (cmode_0 == 0) {
5462 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5463 } else { // cmode<0> == '1'
5464 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
5465 }
5466 } else { // cmode<3> == '1'
5467 if (cmode_2 == 0) {
5468 if (cmode_0 == 0) {
5469 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5470 } else { // cmode<0> == '1'
5471 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
5472 }
5473 } else { // cmode<2> == '1'
5474 if (cmode_1 == 0) {
5475 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5476 } else { // cmode<1> == '1'
5477 if (cmode_0 == 0) {
5478 op = NEONModifiedImmediate_MOVI;
5479 } else { // cmode<0> == '1'
5480 op = NEONModifiedImmediate_MOVI;
5481 }
5482 }
5483 }
5484 }
5485
5486 // Call the logic function
5487 if (op == NEONModifiedImmediate_ORR) {
5488 orr(vform, rd, rd, imm);
5489 } else if (op == NEONModifiedImmediate_BIC) {
5490 bic(vform, rd, rd, imm);
5491 } else if (op == NEONModifiedImmediate_MOVI) {
5492 movi(vform, rd, imm);
5493 } else if (op == NEONModifiedImmediate_MVNI) {
5494 mvni(vform, rd, imm);
5495 } else {
5496 VisitUnimplemented(instr);
5497 }
5498 }
5499
5500
VisitNEONScalar2RegMisc(const Instruction * instr)5501 void Simulator::VisitNEONScalar2RegMisc(const Instruction* instr) {
5502 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
5503 VectorFormat vf = nfd.GetVectorFormat();
5504
5505 SimVRegister& rd = ReadVRegister(instr->GetRd());
5506 SimVRegister& rn = ReadVRegister(instr->GetRn());
5507
5508 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
5509 // These instructions all use a two bit size field, except NOT and RBIT,
5510 // which use the field to encode the operation.
5511 switch (instr->Mask(NEONScalar2RegMiscMask)) {
5512 case NEON_CMEQ_zero_scalar:
5513 cmp(vf, rd, rn, 0, eq);
5514 break;
5515 case NEON_CMGE_zero_scalar:
5516 cmp(vf, rd, rn, 0, ge);
5517 break;
5518 case NEON_CMGT_zero_scalar:
5519 cmp(vf, rd, rn, 0, gt);
5520 break;
5521 case NEON_CMLT_zero_scalar:
5522 cmp(vf, rd, rn, 0, lt);
5523 break;
5524 case NEON_CMLE_zero_scalar:
5525 cmp(vf, rd, rn, 0, le);
5526 break;
5527 case NEON_ABS_scalar:
5528 abs(vf, rd, rn);
5529 break;
5530 case NEON_SQABS_scalar:
5531 abs(vf, rd, rn).SignedSaturate(vf);
5532 break;
5533 case NEON_NEG_scalar:
5534 neg(vf, rd, rn);
5535 break;
5536 case NEON_SQNEG_scalar:
5537 neg(vf, rd, rn).SignedSaturate(vf);
5538 break;
5539 case NEON_SUQADD_scalar:
5540 suqadd(vf, rd, rn);
5541 break;
5542 case NEON_USQADD_scalar:
5543 usqadd(vf, rd, rn);
5544 break;
5545 default:
5546 VIXL_UNIMPLEMENTED();
5547 break;
5548 }
5549 } else {
5550 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5551 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
5552
5553 // These instructions all use a one bit size field, except SQXTUN, SQXTN
5554 // and UQXTN, which use a two bit size field.
5555 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
5556 case NEON_FRECPE_scalar:
5557 frecpe(fpf, rd, rn, fpcr_rounding);
5558 break;
5559 case NEON_FRECPX_scalar:
5560 frecpx(fpf, rd, rn);
5561 break;
5562 case NEON_FRSQRTE_scalar:
5563 frsqrte(fpf, rd, rn);
5564 break;
5565 case NEON_FCMGT_zero_scalar:
5566 fcmp_zero(fpf, rd, rn, gt);
5567 break;
5568 case NEON_FCMGE_zero_scalar:
5569 fcmp_zero(fpf, rd, rn, ge);
5570 break;
5571 case NEON_FCMEQ_zero_scalar:
5572 fcmp_zero(fpf, rd, rn, eq);
5573 break;
5574 case NEON_FCMLE_zero_scalar:
5575 fcmp_zero(fpf, rd, rn, le);
5576 break;
5577 case NEON_FCMLT_zero_scalar:
5578 fcmp_zero(fpf, rd, rn, lt);
5579 break;
5580 case NEON_SCVTF_scalar:
5581 scvtf(fpf, rd, rn, 0, fpcr_rounding);
5582 break;
5583 case NEON_UCVTF_scalar:
5584 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
5585 break;
5586 case NEON_FCVTNS_scalar:
5587 fcvts(fpf, rd, rn, FPTieEven);
5588 break;
5589 case NEON_FCVTNU_scalar:
5590 fcvtu(fpf, rd, rn, FPTieEven);
5591 break;
5592 case NEON_FCVTPS_scalar:
5593 fcvts(fpf, rd, rn, FPPositiveInfinity);
5594 break;
5595 case NEON_FCVTPU_scalar:
5596 fcvtu(fpf, rd, rn, FPPositiveInfinity);
5597 break;
5598 case NEON_FCVTMS_scalar:
5599 fcvts(fpf, rd, rn, FPNegativeInfinity);
5600 break;
5601 case NEON_FCVTMU_scalar:
5602 fcvtu(fpf, rd, rn, FPNegativeInfinity);
5603 break;
5604 case NEON_FCVTZS_scalar:
5605 fcvts(fpf, rd, rn, FPZero);
5606 break;
5607 case NEON_FCVTZU_scalar:
5608 fcvtu(fpf, rd, rn, FPZero);
5609 break;
5610 case NEON_FCVTAS_scalar:
5611 fcvts(fpf, rd, rn, FPTieAway);
5612 break;
5613 case NEON_FCVTAU_scalar:
5614 fcvtu(fpf, rd, rn, FPTieAway);
5615 break;
5616 case NEON_FCVTXN_scalar:
5617 // Unlike all of the other FP instructions above, fcvtxn encodes dest
5618 // size S as size<0>=1. There's only one case, so we ignore the form.
5619 VIXL_ASSERT(instr->ExtractBit(22) == 1);
5620 fcvtxn(kFormatS, rd, rn);
5621 break;
5622 default:
5623 switch (instr->Mask(NEONScalar2RegMiscMask)) {
5624 case NEON_SQXTN_scalar:
5625 sqxtn(vf, rd, rn);
5626 break;
5627 case NEON_UQXTN_scalar:
5628 uqxtn(vf, rd, rn);
5629 break;
5630 case NEON_SQXTUN_scalar:
5631 sqxtun(vf, rd, rn);
5632 break;
5633 default:
5634 VIXL_UNIMPLEMENTED();
5635 }
5636 }
5637 }
5638 }
5639
5640
VisitNEONScalar2RegMiscFP16(const Instruction * instr)5641 void Simulator::VisitNEONScalar2RegMiscFP16(const Instruction* instr) {
5642 VectorFormat fpf = kFormatH;
5643 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
5644
5645 SimVRegister& rd = ReadVRegister(instr->GetRd());
5646 SimVRegister& rn = ReadVRegister(instr->GetRn());
5647
5648 switch (instr->Mask(NEONScalar2RegMiscFP16Mask)) {
5649 case NEON_FRECPE_H_scalar:
5650 frecpe(fpf, rd, rn, fpcr_rounding);
5651 break;
5652 case NEON_FRECPX_H_scalar:
5653 frecpx(fpf, rd, rn);
5654 break;
5655 case NEON_FRSQRTE_H_scalar:
5656 frsqrte(fpf, rd, rn);
5657 break;
5658 case NEON_FCMGT_H_zero_scalar:
5659 fcmp_zero(fpf, rd, rn, gt);
5660 break;
5661 case NEON_FCMGE_H_zero_scalar:
5662 fcmp_zero(fpf, rd, rn, ge);
5663 break;
5664 case NEON_FCMEQ_H_zero_scalar:
5665 fcmp_zero(fpf, rd, rn, eq);
5666 break;
5667 case NEON_FCMLE_H_zero_scalar:
5668 fcmp_zero(fpf, rd, rn, le);
5669 break;
5670 case NEON_FCMLT_H_zero_scalar:
5671 fcmp_zero(fpf, rd, rn, lt);
5672 break;
5673 case NEON_SCVTF_H_scalar:
5674 scvtf(fpf, rd, rn, 0, fpcr_rounding);
5675 break;
5676 case NEON_UCVTF_H_scalar:
5677 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
5678 break;
5679 case NEON_FCVTNS_H_scalar:
5680 fcvts(fpf, rd, rn, FPTieEven);
5681 break;
5682 case NEON_FCVTNU_H_scalar:
5683 fcvtu(fpf, rd, rn, FPTieEven);
5684 break;
5685 case NEON_FCVTPS_H_scalar:
5686 fcvts(fpf, rd, rn, FPPositiveInfinity);
5687 break;
5688 case NEON_FCVTPU_H_scalar:
5689 fcvtu(fpf, rd, rn, FPPositiveInfinity);
5690 break;
5691 case NEON_FCVTMS_H_scalar:
5692 fcvts(fpf, rd, rn, FPNegativeInfinity);
5693 break;
5694 case NEON_FCVTMU_H_scalar:
5695 fcvtu(fpf, rd, rn, FPNegativeInfinity);
5696 break;
5697 case NEON_FCVTZS_H_scalar:
5698 fcvts(fpf, rd, rn, FPZero);
5699 break;
5700 case NEON_FCVTZU_H_scalar:
5701 fcvtu(fpf, rd, rn, FPZero);
5702 break;
5703 case NEON_FCVTAS_H_scalar:
5704 fcvts(fpf, rd, rn, FPTieAway);
5705 break;
5706 case NEON_FCVTAU_H_scalar:
5707 fcvtu(fpf, rd, rn, FPTieAway);
5708 break;
5709 }
5710 }
5711
5712
VisitNEONScalar3Diff(const Instruction * instr)5713 void Simulator::VisitNEONScalar3Diff(const Instruction* instr) {
5714 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
5715 VectorFormat vf = nfd.GetVectorFormat();
5716
5717 SimVRegister& rd = ReadVRegister(instr->GetRd());
5718 SimVRegister& rn = ReadVRegister(instr->GetRn());
5719 SimVRegister& rm = ReadVRegister(instr->GetRm());
5720 switch (instr->Mask(NEONScalar3DiffMask)) {
5721 case NEON_SQDMLAL_scalar:
5722 sqdmlal(vf, rd, rn, rm);
5723 break;
5724 case NEON_SQDMLSL_scalar:
5725 sqdmlsl(vf, rd, rn, rm);
5726 break;
5727 case NEON_SQDMULL_scalar:
5728 sqdmull(vf, rd, rn, rm);
5729 break;
5730 default:
5731 VIXL_UNIMPLEMENTED();
5732 }
5733 }
5734
5735
VisitNEONScalar3Same(const Instruction * instr)5736 void Simulator::VisitNEONScalar3Same(const Instruction* instr) {
5737 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
5738 VectorFormat vf = nfd.GetVectorFormat();
5739
5740 SimVRegister& rd = ReadVRegister(instr->GetRd());
5741 SimVRegister& rn = ReadVRegister(instr->GetRn());
5742 SimVRegister& rm = ReadVRegister(instr->GetRm());
5743
5744 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
5745 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5746 switch (instr->Mask(NEONScalar3SameFPMask)) {
5747 case NEON_FMULX_scalar:
5748 fmulx(vf, rd, rn, rm);
5749 break;
5750 case NEON_FACGE_scalar:
5751 fabscmp(vf, rd, rn, rm, ge);
5752 break;
5753 case NEON_FACGT_scalar:
5754 fabscmp(vf, rd, rn, rm, gt);
5755 break;
5756 case NEON_FCMEQ_scalar:
5757 fcmp(vf, rd, rn, rm, eq);
5758 break;
5759 case NEON_FCMGE_scalar:
5760 fcmp(vf, rd, rn, rm, ge);
5761 break;
5762 case NEON_FCMGT_scalar:
5763 fcmp(vf, rd, rn, rm, gt);
5764 break;
5765 case NEON_FRECPS_scalar:
5766 frecps(vf, rd, rn, rm);
5767 break;
5768 case NEON_FRSQRTS_scalar:
5769 frsqrts(vf, rd, rn, rm);
5770 break;
5771 case NEON_FABD_scalar:
5772 fabd(vf, rd, rn, rm);
5773 break;
5774 default:
5775 VIXL_UNIMPLEMENTED();
5776 }
5777 } else {
5778 switch (instr->Mask(NEONScalar3SameMask)) {
5779 case NEON_ADD_scalar:
5780 add(vf, rd, rn, rm);
5781 break;
5782 case NEON_SUB_scalar:
5783 sub(vf, rd, rn, rm);
5784 break;
5785 case NEON_CMEQ_scalar:
5786 cmp(vf, rd, rn, rm, eq);
5787 break;
5788 case NEON_CMGE_scalar:
5789 cmp(vf, rd, rn, rm, ge);
5790 break;
5791 case NEON_CMGT_scalar:
5792 cmp(vf, rd, rn, rm, gt);
5793 break;
5794 case NEON_CMHI_scalar:
5795 cmp(vf, rd, rn, rm, hi);
5796 break;
5797 case NEON_CMHS_scalar:
5798 cmp(vf, rd, rn, rm, hs);
5799 break;
5800 case NEON_CMTST_scalar:
5801 cmptst(vf, rd, rn, rm);
5802 break;
5803 case NEON_USHL_scalar:
5804 ushl(vf, rd, rn, rm);
5805 break;
5806 case NEON_SSHL_scalar:
5807 sshl(vf, rd, rn, rm);
5808 break;
5809 case NEON_SQDMULH_scalar:
5810 sqdmulh(vf, rd, rn, rm);
5811 break;
5812 case NEON_SQRDMULH_scalar:
5813 sqrdmulh(vf, rd, rn, rm);
5814 break;
5815 case NEON_UQADD_scalar:
5816 add(vf, rd, rn, rm).UnsignedSaturate(vf);
5817 break;
5818 case NEON_SQADD_scalar:
5819 add(vf, rd, rn, rm).SignedSaturate(vf);
5820 break;
5821 case NEON_UQSUB_scalar:
5822 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
5823 break;
5824 case NEON_SQSUB_scalar:
5825 sub(vf, rd, rn, rm).SignedSaturate(vf);
5826 break;
5827 case NEON_UQSHL_scalar:
5828 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
5829 break;
5830 case NEON_SQSHL_scalar:
5831 sshl(vf, rd, rn, rm).SignedSaturate(vf);
5832 break;
5833 case NEON_URSHL_scalar:
5834 ushl(vf, rd, rn, rm).Round(vf);
5835 break;
5836 case NEON_SRSHL_scalar:
5837 sshl(vf, rd, rn, rm).Round(vf);
5838 break;
5839 case NEON_UQRSHL_scalar:
5840 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
5841 break;
5842 case NEON_SQRSHL_scalar:
5843 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
5844 break;
5845 default:
5846 VIXL_UNIMPLEMENTED();
5847 }
5848 }
5849 }
5850
VisitNEONScalar3SameFP16(const Instruction * instr)5851 void Simulator::VisitNEONScalar3SameFP16(const Instruction* instr) {
5852 SimVRegister& rd = ReadVRegister(instr->GetRd());
5853 SimVRegister& rn = ReadVRegister(instr->GetRn());
5854 SimVRegister& rm = ReadVRegister(instr->GetRm());
5855
5856 switch (instr->Mask(NEONScalar3SameFP16Mask)) {
5857 case NEON_FABD_H_scalar:
5858 fabd(kFormatH, rd, rn, rm);
5859 break;
5860 case NEON_FMULX_H_scalar:
5861 fmulx(kFormatH, rd, rn, rm);
5862 break;
5863 case NEON_FCMEQ_H_scalar:
5864 fcmp(kFormatH, rd, rn, rm, eq);
5865 break;
5866 case NEON_FCMGE_H_scalar:
5867 fcmp(kFormatH, rd, rn, rm, ge);
5868 break;
5869 case NEON_FCMGT_H_scalar:
5870 fcmp(kFormatH, rd, rn, rm, gt);
5871 break;
5872 case NEON_FACGE_H_scalar:
5873 fabscmp(kFormatH, rd, rn, rm, ge);
5874 break;
5875 case NEON_FACGT_H_scalar:
5876 fabscmp(kFormatH, rd, rn, rm, gt);
5877 break;
5878 case NEON_FRECPS_H_scalar:
5879 frecps(kFormatH, rd, rn, rm);
5880 break;
5881 case NEON_FRSQRTS_H_scalar:
5882 frsqrts(kFormatH, rd, rn, rm);
5883 break;
5884 default:
5885 VIXL_UNREACHABLE();
5886 }
5887 }
5888
5889
VisitNEONScalar3SameExtra(const Instruction * instr)5890 void Simulator::VisitNEONScalar3SameExtra(const Instruction* instr) {
5891 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
5892 VectorFormat vf = nfd.GetVectorFormat();
5893
5894 SimVRegister& rd = ReadVRegister(instr->GetRd());
5895 SimVRegister& rn = ReadVRegister(instr->GetRn());
5896 SimVRegister& rm = ReadVRegister(instr->GetRm());
5897
5898 switch (instr->Mask(NEONScalar3SameExtraMask)) {
5899 case NEON_SQRDMLAH_scalar:
5900 sqrdmlah(vf, rd, rn, rm);
5901 break;
5902 case NEON_SQRDMLSH_scalar:
5903 sqrdmlsh(vf, rd, rn, rm);
5904 break;
5905 default:
5906 VIXL_UNIMPLEMENTED();
5907 }
5908 }
5909
VisitNEONScalarByIndexedElement(const Instruction * instr)5910 void Simulator::VisitNEONScalarByIndexedElement(const Instruction* instr) {
5911 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
5912 VectorFormat vf = nfd.GetVectorFormat();
5913 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());
5914
5915 SimVRegister& rd = ReadVRegister(instr->GetRd());
5916 SimVRegister& rn = ReadVRegister(instr->GetRn());
5917 ByElementOp Op = NULL;
5918
5919 int rm_reg = instr->GetRm();
5920 int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
5921 if (instr->GetNEONSize() == 1) {
5922 rm_reg &= 0xf;
5923 index = (index << 1) | instr->GetNEONM();
5924 }
5925
5926 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
5927 case NEON_SQDMULL_byelement_scalar:
5928 Op = &Simulator::sqdmull;
5929 break;
5930 case NEON_SQDMLAL_byelement_scalar:
5931 Op = &Simulator::sqdmlal;
5932 break;
5933 case NEON_SQDMLSL_byelement_scalar:
5934 Op = &Simulator::sqdmlsl;
5935 break;
5936 case NEON_SQDMULH_byelement_scalar:
5937 Op = &Simulator::sqdmulh;
5938 vf = vf_r;
5939 break;
5940 case NEON_SQRDMULH_byelement_scalar:
5941 Op = &Simulator::sqrdmulh;
5942 vf = vf_r;
5943 break;
5944 case NEON_SQRDMLAH_byelement_scalar:
5945 Op = &Simulator::sqrdmlah;
5946 vf = vf_r;
5947 break;
5948 case NEON_SQRDMLSH_byelement_scalar:
5949 Op = &Simulator::sqrdmlsh;
5950 vf = vf_r;
5951 break;
5952 default:
5953 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5954 index = instr->GetNEONH();
5955 if (instr->GetFPType() == 0) {
5956 index = (index << 2) | (instr->GetNEONL() << 1) | instr->GetNEONM();
5957 rm_reg &= 0xf;
5958 vf = kFormatH;
5959 } else if ((instr->GetFPType() & 1) == 0) {
5960 index = (index << 1) | instr->GetNEONL();
5961 }
5962 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
5963 case NEON_FMUL_H_byelement_scalar:
5964 case NEON_FMUL_byelement_scalar:
5965 Op = &Simulator::fmul;
5966 break;
5967 case NEON_FMLA_H_byelement_scalar:
5968 case NEON_FMLA_byelement_scalar:
5969 Op = &Simulator::fmla;
5970 break;
5971 case NEON_FMLS_H_byelement_scalar:
5972 case NEON_FMLS_byelement_scalar:
5973 Op = &Simulator::fmls;
5974 break;
5975 case NEON_FMULX_H_byelement_scalar:
5976 case NEON_FMULX_byelement_scalar:
5977 Op = &Simulator::fmulx;
5978 break;
5979 default:
5980 VIXL_UNIMPLEMENTED();
5981 }
5982 }
5983
5984 (this->*Op)(vf, rd, rn, ReadVRegister(rm_reg), index);
5985 }
5986
5987
VisitNEONScalarCopy(const Instruction * instr)5988 void Simulator::VisitNEONScalarCopy(const Instruction* instr) {
5989 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
5990 VectorFormat vf = nfd.GetVectorFormat();
5991
5992 SimVRegister& rd = ReadVRegister(instr->GetRd());
5993 SimVRegister& rn = ReadVRegister(instr->GetRn());
5994
5995 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
5996 int imm5 = instr->GetImmNEON5();
5997 int tz = CountTrailingZeros(imm5, 32);
5998 int rn_index = imm5 >> (tz + 1);
5999 dup_element(vf, rd, rn, rn_index);
6000 } else {
6001 VIXL_UNIMPLEMENTED();
6002 }
6003 }
6004
6005
VisitNEONScalarPairwise(const Instruction * instr)6006 void Simulator::VisitNEONScalarPairwise(const Instruction* instr) {
6007 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarPairwiseFormatMap());
6008 VectorFormat vf = nfd.GetVectorFormat();
6009
6010 SimVRegister& rd = ReadVRegister(instr->GetRd());
6011 SimVRegister& rn = ReadVRegister(instr->GetRn());
6012 switch (instr->Mask(NEONScalarPairwiseMask)) {
6013 case NEON_ADDP_scalar: {
6014 // All pairwise operations except ADDP use bit U to differentiate FP16
6015 // from FP32/FP64 variations.
6016 NEONFormatDecoder nfd_addp(instr, NEONFormatDecoder::FPScalarFormatMap());
6017 addp(nfd_addp.GetVectorFormat(), rd, rn);
6018 break;
6019 }
6020 case NEON_FADDP_h_scalar:
6021 case NEON_FADDP_scalar:
6022 faddp(vf, rd, rn);
6023 break;
6024 case NEON_FMAXP_h_scalar:
6025 case NEON_FMAXP_scalar:
6026 fmaxp(vf, rd, rn);
6027 break;
6028 case NEON_FMAXNMP_h_scalar:
6029 case NEON_FMAXNMP_scalar:
6030 fmaxnmp(vf, rd, rn);
6031 break;
6032 case NEON_FMINP_h_scalar:
6033 case NEON_FMINP_scalar:
6034 fminp(vf, rd, rn);
6035 break;
6036 case NEON_FMINNMP_h_scalar:
6037 case NEON_FMINNMP_scalar:
6038 fminnmp(vf, rd, rn);
6039 break;
6040 default:
6041 VIXL_UNIMPLEMENTED();
6042 }
6043 }
6044
6045
VisitNEONScalarShiftImmediate(const Instruction * instr)6046 void Simulator::VisitNEONScalarShiftImmediate(const Instruction* instr) {
6047 SimVRegister& rd = ReadVRegister(instr->GetRd());
6048 SimVRegister& rn = ReadVRegister(instr->GetRn());
6049 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
6050
6051 static const NEONFormatMap map = {{22, 21, 20, 19},
6052 {NF_UNDEF,
6053 NF_B,
6054 NF_H,
6055 NF_H,
6056 NF_S,
6057 NF_S,
6058 NF_S,
6059 NF_S,
6060 NF_D,
6061 NF_D,
6062 NF_D,
6063 NF_D,
6064 NF_D,
6065 NF_D,
6066 NF_D,
6067 NF_D}};
6068 NEONFormatDecoder nfd(instr, &map);
6069 VectorFormat vf = nfd.GetVectorFormat();
6070
6071 int highestSetBit = HighestSetBitPosition(instr->GetImmNEONImmh());
6072 int immhimmb = instr->GetImmNEONImmhImmb();
6073 int right_shift = (16 << highestSetBit) - immhimmb;
6074 int left_shift = immhimmb - (8 << highestSetBit);
6075 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
6076 case NEON_SHL_scalar:
6077 shl(vf, rd, rn, left_shift);
6078 break;
6079 case NEON_SLI_scalar:
6080 sli(vf, rd, rn, left_shift);
6081 break;
6082 case NEON_SQSHL_imm_scalar:
6083 sqshl(vf, rd, rn, left_shift);
6084 break;
6085 case NEON_UQSHL_imm_scalar:
6086 uqshl(vf, rd, rn, left_shift);
6087 break;
6088 case NEON_SQSHLU_scalar:
6089 sqshlu(vf, rd, rn, left_shift);
6090 break;
6091 case NEON_SRI_scalar:
6092 sri(vf, rd, rn, right_shift);
6093 break;
6094 case NEON_SSHR_scalar:
6095 sshr(vf, rd, rn, right_shift);
6096 break;
6097 case NEON_USHR_scalar:
6098 ushr(vf, rd, rn, right_shift);
6099 break;
6100 case NEON_SRSHR_scalar:
6101 sshr(vf, rd, rn, right_shift).Round(vf);
6102 break;
6103 case NEON_URSHR_scalar:
6104 ushr(vf, rd, rn, right_shift).Round(vf);
6105 break;
6106 case NEON_SSRA_scalar:
6107 ssra(vf, rd, rn, right_shift);
6108 break;
6109 case NEON_USRA_scalar:
6110 usra(vf, rd, rn, right_shift);
6111 break;
6112 case NEON_SRSRA_scalar:
6113 srsra(vf, rd, rn, right_shift);
6114 break;
6115 case NEON_URSRA_scalar:
6116 ursra(vf, rd, rn, right_shift);
6117 break;
6118 case NEON_UQSHRN_scalar:
6119 uqshrn(vf, rd, rn, right_shift);
6120 break;
6121 case NEON_UQRSHRN_scalar:
6122 uqrshrn(vf, rd, rn, right_shift);
6123 break;
6124 case NEON_SQSHRN_scalar:
6125 sqshrn(vf, rd, rn, right_shift);
6126 break;
6127 case NEON_SQRSHRN_scalar:
6128 sqrshrn(vf, rd, rn, right_shift);
6129 break;
6130 case NEON_SQSHRUN_scalar:
6131 sqshrun(vf, rd, rn, right_shift);
6132 break;
6133 case NEON_SQRSHRUN_scalar:
6134 sqrshrun(vf, rd, rn, right_shift);
6135 break;
6136 case NEON_FCVTZS_imm_scalar:
6137 fcvts(vf, rd, rn, FPZero, right_shift);
6138 break;
6139 case NEON_FCVTZU_imm_scalar:
6140 fcvtu(vf, rd, rn, FPZero, right_shift);
6141 break;
6142 case NEON_SCVTF_imm_scalar:
6143 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
6144 break;
6145 case NEON_UCVTF_imm_scalar:
6146 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
6147 break;
6148 default:
6149 VIXL_UNIMPLEMENTED();
6150 }
6151 }
6152
6153
VisitNEONShiftImmediate(const Instruction * instr)6154 void Simulator::VisitNEONShiftImmediate(const Instruction* instr) {
6155 SimVRegister& rd = ReadVRegister(instr->GetRd());
6156 SimVRegister& rn = ReadVRegister(instr->GetRn());
6157 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
6158
6159 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
6160 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
6161 static const NEONFormatMap map = {{22, 21, 20, 19, 30},
6162 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B,
6163 NF_4H, NF_8H, NF_4H, NF_8H,
6164 NF_2S, NF_4S, NF_2S, NF_4S,
6165 NF_2S, NF_4S, NF_2S, NF_4S,
6166 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
6167 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
6168 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
6169 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}};
6170 NEONFormatDecoder nfd(instr, &map);
6171 VectorFormat vf = nfd.GetVectorFormat();
6172
6173 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
6174 static const NEONFormatMap map_l =
6175 {{22, 21, 20, 19},
6176 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}};
6177 VectorFormat vf_l = nfd.GetVectorFormat(&map_l);
6178
6179 int highestSetBit = HighestSetBitPosition(instr->GetImmNEONImmh());
6180 int immhimmb = instr->GetImmNEONImmhImmb();
6181 int right_shift = (16 << highestSetBit) - immhimmb;
6182 int left_shift = immhimmb - (8 << highestSetBit);
6183
6184 switch (instr->Mask(NEONShiftImmediateMask)) {
6185 case NEON_SHL:
6186 shl(vf, rd, rn, left_shift);
6187 break;
6188 case NEON_SLI:
6189 sli(vf, rd, rn, left_shift);
6190 break;
6191 case NEON_SQSHLU:
6192 sqshlu(vf, rd, rn, left_shift);
6193 break;
6194 case NEON_SRI:
6195 sri(vf, rd, rn, right_shift);
6196 break;
6197 case NEON_SSHR:
6198 sshr(vf, rd, rn, right_shift);
6199 break;
6200 case NEON_USHR:
6201 ushr(vf, rd, rn, right_shift);
6202 break;
6203 case NEON_SRSHR:
6204 sshr(vf, rd, rn, right_shift).Round(vf);
6205 break;
6206 case NEON_URSHR:
6207 ushr(vf, rd, rn, right_shift).Round(vf);
6208 break;
6209 case NEON_SSRA:
6210 ssra(vf, rd, rn, right_shift);
6211 break;
6212 case NEON_USRA:
6213 usra(vf, rd, rn, right_shift);
6214 break;
6215 case NEON_SRSRA:
6216 srsra(vf, rd, rn, right_shift);
6217 break;
6218 case NEON_URSRA:
6219 ursra(vf, rd, rn, right_shift);
6220 break;
6221 case NEON_SQSHL_imm:
6222 sqshl(vf, rd, rn, left_shift);
6223 break;
6224 case NEON_UQSHL_imm:
6225 uqshl(vf, rd, rn, left_shift);
6226 break;
6227 case NEON_SCVTF_imm:
6228 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
6229 break;
6230 case NEON_UCVTF_imm:
6231 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
6232 break;
6233 case NEON_FCVTZS_imm:
6234 fcvts(vf, rd, rn, FPZero, right_shift);
6235 break;
6236 case NEON_FCVTZU_imm:
6237 fcvtu(vf, rd, rn, FPZero, right_shift);
6238 break;
6239 case NEON_SSHLL:
6240 vf = vf_l;
6241 if (instr->Mask(NEON_Q)) {
6242 sshll2(vf, rd, rn, left_shift);
6243 } else {
6244 sshll(vf, rd, rn, left_shift);
6245 }
6246 break;
6247 case NEON_USHLL:
6248 vf = vf_l;
6249 if (instr->Mask(NEON_Q)) {
6250 ushll2(vf, rd, rn, left_shift);
6251 } else {
6252 ushll(vf, rd, rn, left_shift);
6253 }
6254 break;
6255 case NEON_SHRN:
6256 if (instr->Mask(NEON_Q)) {
6257 shrn2(vf, rd, rn, right_shift);
6258 } else {
6259 shrn(vf, rd, rn, right_shift);
6260 }
6261 break;
6262 case NEON_RSHRN:
6263 if (instr->Mask(NEON_Q)) {
6264 rshrn2(vf, rd, rn, right_shift);
6265 } else {
6266 rshrn(vf, rd, rn, right_shift);
6267 }
6268 break;
6269 case NEON_UQSHRN:
6270 if (instr->Mask(NEON_Q)) {
6271 uqshrn2(vf, rd, rn, right_shift);
6272 } else {
6273 uqshrn(vf, rd, rn, right_shift);
6274 }
6275 break;
6276 case NEON_UQRSHRN:
6277 if (instr->Mask(NEON_Q)) {
6278 uqrshrn2(vf, rd, rn, right_shift);
6279 } else {
6280 uqrshrn(vf, rd, rn, right_shift);
6281 }
6282 break;
6283 case NEON_SQSHRN:
6284 if (instr->Mask(NEON_Q)) {
6285 sqshrn2(vf, rd, rn, right_shift);
6286 } else {
6287 sqshrn(vf, rd, rn, right_shift);
6288 }
6289 break;
6290 case NEON_SQRSHRN:
6291 if (instr->Mask(NEON_Q)) {
6292 sqrshrn2(vf, rd, rn, right_shift);
6293 } else {
6294 sqrshrn(vf, rd, rn, right_shift);
6295 }
6296 break;
6297 case NEON_SQSHRUN:
6298 if (instr->Mask(NEON_Q)) {
6299 sqshrun2(vf, rd, rn, right_shift);
6300 } else {
6301 sqshrun(vf, rd, rn, right_shift);
6302 }
6303 break;
6304 case NEON_SQRSHRUN:
6305 if (instr->Mask(NEON_Q)) {
6306 sqrshrun2(vf, rd, rn, right_shift);
6307 } else {
6308 sqrshrun(vf, rd, rn, right_shift);
6309 }
6310 break;
6311 default:
6312 VIXL_UNIMPLEMENTED();
6313 }
6314 }
6315
6316
VisitNEONTable(const Instruction * instr)6317 void Simulator::VisitNEONTable(const Instruction* instr) {
6318 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
6319 VectorFormat vf = nfd.GetVectorFormat();
6320
6321 SimVRegister& rd = ReadVRegister(instr->GetRd());
6322 SimVRegister& rn = ReadVRegister(instr->GetRn());
6323 SimVRegister& rn2 = ReadVRegister((instr->GetRn() + 1) % kNumberOfVRegisters);
6324 SimVRegister& rn3 = ReadVRegister((instr->GetRn() + 2) % kNumberOfVRegisters);
6325 SimVRegister& rn4 = ReadVRegister((instr->GetRn() + 3) % kNumberOfVRegisters);
6326 SimVRegister& rm = ReadVRegister(instr->GetRm());
6327
6328 switch (instr->Mask(NEONTableMask)) {
6329 case NEON_TBL_1v:
6330 tbl(vf, rd, rn, rm);
6331 break;
6332 case NEON_TBL_2v:
6333 tbl(vf, rd, rn, rn2, rm);
6334 break;
6335 case NEON_TBL_3v:
6336 tbl(vf, rd, rn, rn2, rn3, rm);
6337 break;
6338 case NEON_TBL_4v:
6339 tbl(vf, rd, rn, rn2, rn3, rn4, rm);
6340 break;
6341 case NEON_TBX_1v:
6342 tbx(vf, rd, rn, rm);
6343 break;
6344 case NEON_TBX_2v:
6345 tbx(vf, rd, rn, rn2, rm);
6346 break;
6347 case NEON_TBX_3v:
6348 tbx(vf, rd, rn, rn2, rn3, rm);
6349 break;
6350 case NEON_TBX_4v:
6351 tbx(vf, rd, rn, rn2, rn3, rn4, rm);
6352 break;
6353 default:
6354 VIXL_UNIMPLEMENTED();
6355 }
6356 }
6357
6358
VisitNEONPerm(const Instruction * instr)6359 void Simulator::VisitNEONPerm(const Instruction* instr) {
6360 NEONFormatDecoder nfd(instr);
6361 VectorFormat vf = nfd.GetVectorFormat();
6362
6363 SimVRegister& rd = ReadVRegister(instr->GetRd());
6364 SimVRegister& rn = ReadVRegister(instr->GetRn());
6365 SimVRegister& rm = ReadVRegister(instr->GetRm());
6366
6367 switch (instr->Mask(NEONPermMask)) {
6368 case NEON_TRN1:
6369 trn1(vf, rd, rn, rm);
6370 break;
6371 case NEON_TRN2:
6372 trn2(vf, rd, rn, rm);
6373 break;
6374 case NEON_UZP1:
6375 uzp1(vf, rd, rn, rm);
6376 break;
6377 case NEON_UZP2:
6378 uzp2(vf, rd, rn, rm);
6379 break;
6380 case NEON_ZIP1:
6381 zip1(vf, rd, rn, rm);
6382 break;
6383 case NEON_ZIP2:
6384 zip2(vf, rd, rn, rm);
6385 break;
6386 default:
6387 VIXL_UNIMPLEMENTED();
6388 }
6389 }
6390
6391
DoUnreachable(const Instruction * instr)6392 void Simulator::DoUnreachable(const Instruction* instr) {
6393 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6394 (instr->GetImmException() == kUnreachableOpcode));
6395
6396 fprintf(stream_,
6397 "Hit UNREACHABLE marker at pc=%p.\n",
6398 reinterpret_cast<const void*>(instr));
6399 abort();
6400 }
6401
6402
DoTrace(const Instruction * instr)6403 void Simulator::DoTrace(const Instruction* instr) {
6404 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6405 (instr->GetImmException() == kTraceOpcode));
6406
6407 // Read the arguments encoded inline in the instruction stream.
6408 uint32_t parameters;
6409 uint32_t command;
6410
6411 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
6412 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
6413 memcpy(&command, instr + kTraceCommandOffset, sizeof(command));
6414
6415 switch (command) {
6416 case TRACE_ENABLE:
6417 SetTraceParameters(GetTraceParameters() | parameters);
6418 break;
6419 case TRACE_DISABLE:
6420 SetTraceParameters(GetTraceParameters() & ~parameters);
6421 break;
6422 default:
6423 VIXL_UNREACHABLE();
6424 }
6425
6426 WritePc(instr->GetInstructionAtOffset(kTraceLength));
6427 }
6428
6429
DoLog(const Instruction * instr)6430 void Simulator::DoLog(const Instruction* instr) {
6431 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6432 (instr->GetImmException() == kLogOpcode));
6433
6434 // Read the arguments encoded inline in the instruction stream.
6435 uint32_t parameters;
6436
6437 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
6438 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
6439
6440 // We don't support a one-shot LOG_DISASM.
6441 VIXL_ASSERT((parameters & LOG_DISASM) == 0);
6442 // Print the requested information.
6443 if (parameters & LOG_SYSREGS) PrintSystemRegisters();
6444 if (parameters & LOG_REGS) PrintRegisters();
6445 if (parameters & LOG_VREGS) PrintVRegisters();
6446
6447 WritePc(instr->GetInstructionAtOffset(kLogLength));
6448 }
6449
6450
DoPrintf(const Instruction * instr)6451 void Simulator::DoPrintf(const Instruction* instr) {
6452 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6453 (instr->GetImmException() == kPrintfOpcode));
6454
6455 // Read the arguments encoded inline in the instruction stream.
6456 uint32_t arg_count;
6457 uint32_t arg_pattern_list;
6458 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
6459 memcpy(&arg_count, instr + kPrintfArgCountOffset, sizeof(arg_count));
6460 memcpy(&arg_pattern_list,
6461 instr + kPrintfArgPatternListOffset,
6462 sizeof(arg_pattern_list));
6463
6464 VIXL_ASSERT(arg_count <= kPrintfMaxArgCount);
6465 VIXL_ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
6466
6467 // We need to call the host printf function with a set of arguments defined by
6468 // arg_pattern_list. Because we don't know the types and sizes of the
6469 // arguments, this is very difficult to do in a robust and portable way. To
6470 // work around the problem, we pick apart the format string, and print one
6471 // format placeholder at a time.
6472
6473 // Allocate space for the format string. We take a copy, so we can modify it.
6474 // Leave enough space for one extra character per expected argument (plus the
6475 // '\0' termination).
6476 const char* format_base = ReadRegister<const char*>(0);
6477 VIXL_ASSERT(format_base != NULL);
6478 size_t length = strlen(format_base) + 1;
6479 char* const format = new char[length + arg_count];
6480
6481 // A list of chunks, each with exactly one format placeholder.
6482 const char* chunks[kPrintfMaxArgCount];
6483
6484 // Copy the format string and search for format placeholders.
6485 uint32_t placeholder_count = 0;
6486 char* format_scratch = format;
6487 for (size_t i = 0; i < length; i++) {
6488 if (format_base[i] != '%') {
6489 *format_scratch++ = format_base[i];
6490 } else {
6491 if (format_base[i + 1] == '%') {
6492 // Ignore explicit "%%" sequences.
6493 *format_scratch++ = format_base[i];
6494 i++;
6495 // Chunks after the first are passed as format strings to printf, so we
6496 // need to escape '%' characters in those chunks.
6497 if (placeholder_count > 0) *format_scratch++ = format_base[i];
6498 } else {
6499 VIXL_CHECK(placeholder_count < arg_count);
6500 // Insert '\0' before placeholders, and store their locations.
6501 *format_scratch++ = '\0';
6502 chunks[placeholder_count++] = format_scratch;
6503 *format_scratch++ = format_base[i];
6504 }
6505 }
6506 }
6507 VIXL_CHECK(placeholder_count == arg_count);
6508
6509 // Finally, call printf with each chunk, passing the appropriate register
6510 // argument. Normally, printf returns the number of bytes transmitted, so we
6511 // can emulate a single printf call by adding the result from each chunk. If
6512 // any call returns a negative (error) value, though, just return that value.
6513
6514 printf("%s", clr_printf);
6515
6516 // Because '\0' is inserted before each placeholder, the first string in
6517 // 'format' contains no format placeholders and should be printed literally.
6518 int result = printf("%s", format);
6519 int pcs_r = 1; // Start at x1. x0 holds the format string.
6520 int pcs_f = 0; // Start at d0.
6521 if (result >= 0) {
6522 for (uint32_t i = 0; i < placeholder_count; i++) {
6523 int part_result = -1;
6524
6525 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
6526 arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
6527 switch (arg_pattern) {
6528 case kPrintfArgW:
6529 part_result = printf(chunks[i], ReadWRegister(pcs_r++));
6530 break;
6531 case kPrintfArgX:
6532 part_result = printf(chunks[i], ReadXRegister(pcs_r++));
6533 break;
6534 case kPrintfArgD:
6535 part_result = printf(chunks[i], ReadDRegister(pcs_f++));
6536 break;
6537 default:
6538 VIXL_UNREACHABLE();
6539 }
6540
6541 if (part_result < 0) {
6542 // Handle error values.
6543 result = part_result;
6544 break;
6545 }
6546
6547 result += part_result;
6548 }
6549 }
6550
6551 printf("%s", clr_normal);
6552
6553 // Printf returns its result in x0 (just like the C library's printf).
6554 WriteXRegister(0, result);
6555
6556 // The printf parameters are inlined in the code, so skip them.
6557 WritePc(instr->GetInstructionAtOffset(kPrintfLength));
6558
6559 // Set LR as if we'd just called a native printf function.
6560 WriteLr(ReadPc());
6561
6562 delete[] format;
6563 }
6564
6565
6566 #ifdef VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT
DoRuntimeCall(const Instruction * instr)6567 void Simulator::DoRuntimeCall(const Instruction* instr) {
6568 VIXL_STATIC_ASSERT(kRuntimeCallAddressSize == sizeof(uintptr_t));
6569 // The appropriate `Simulator::SimulateRuntimeCall()` wrapper and the function
6570 // to call are passed inlined in the assembly.
6571 uintptr_t call_wrapper_address =
6572 Memory::Read<uintptr_t>(instr + kRuntimeCallWrapperOffset);
6573 uintptr_t function_address =
6574 Memory::Read<uintptr_t>(instr + kRuntimeCallFunctionOffset);
6575 RuntimeCallType call_type = static_cast<RuntimeCallType>(
6576 Memory::Read<uint32_t>(instr + kRuntimeCallTypeOffset));
6577 auto runtime_call_wrapper =
6578 reinterpret_cast<void (*)(Simulator*, uintptr_t)>(call_wrapper_address);
6579
6580 if (call_type == kCallRuntime) {
6581 WriteRegister(kLinkRegCode,
6582 instr->GetInstructionAtOffset(kRuntimeCallLength));
6583 }
6584 runtime_call_wrapper(this, function_address);
6585 // Read the return address from `lr` and write it into `pc`.
6586 WritePc(ReadRegister<Instruction*>(kLinkRegCode));
6587 }
6588 #else
DoRuntimeCall(const Instruction * instr)6589 void Simulator::DoRuntimeCall(const Instruction* instr) {
6590 USE(instr);
6591 VIXL_UNREACHABLE();
6592 }
6593 #endif
6594
6595
DoConfigureCPUFeatures(const Instruction * instr)6596 void Simulator::DoConfigureCPUFeatures(const Instruction* instr) {
6597 VIXL_ASSERT(instr->Mask(ExceptionMask) == HLT);
6598
6599 typedef ConfigureCPUFeaturesElementType ElementType;
6600 VIXL_ASSERT(CPUFeatures::kNumberOfFeatures <
6601 std::numeric_limits<ElementType>::max());
6602
6603 // k{Set,Enable,Disable}CPUFeatures have the same parameter encoding.
6604
6605 size_t element_size = sizeof(ElementType);
6606 size_t offset = kConfigureCPUFeaturesListOffset;
6607
6608 // Read the kNone-terminated list of features.
6609 CPUFeatures parameters;
6610 while (true) {
6611 ElementType feature = Memory::Read<ElementType>(instr + offset);
6612 offset += element_size;
6613 if (feature == static_cast<ElementType>(CPUFeatures::kNone)) break;
6614 parameters.Combine(static_cast<CPUFeatures::Feature>(feature));
6615 }
6616
6617 switch (instr->GetImmException()) {
6618 case kSetCPUFeaturesOpcode:
6619 SetCPUFeatures(parameters);
6620 break;
6621 case kEnableCPUFeaturesOpcode:
6622 GetCPUFeatures()->Combine(parameters);
6623 break;
6624 case kDisableCPUFeaturesOpcode:
6625 GetCPUFeatures()->Remove(parameters);
6626 break;
6627 default:
6628 VIXL_UNREACHABLE();
6629 break;
6630 }
6631
6632 WritePc(instr->GetInstructionAtOffset(AlignUp(offset, kInstructionSize)));
6633 }
6634
6635
DoSaveCPUFeatures(const Instruction * instr)6636 void Simulator::DoSaveCPUFeatures(const Instruction* instr) {
6637 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6638 (instr->GetImmException() == kSaveCPUFeaturesOpcode));
6639 USE(instr);
6640
6641 saved_cpu_features_.push_back(*GetCPUFeatures());
6642 }
6643
6644
DoRestoreCPUFeatures(const Instruction * instr)6645 void Simulator::DoRestoreCPUFeatures(const Instruction* instr) {
6646 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
6647 (instr->GetImmException() == kRestoreCPUFeaturesOpcode));
6648 USE(instr);
6649
6650 SetCPUFeatures(saved_cpu_features_.back());
6651 saved_cpu_features_.pop_back();
6652 }
6653
6654
6655 } // namespace aarch64
6656 } // namespace vixl
6657
6658 #endif // VIXL_INCLUDE_SIMULATOR_AARCH64
6659