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