1 // Copyright 2015, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #ifdef USE_SIMULATOR
28
29 #include <string.h>
30 #include <cmath>
31 #include "vixl/a64/simulator-a64.h"
32
33 namespace vixl {
34
35 const Instruction* Simulator::kEndOfSimAddress = NULL;
36
SetBits(int msb,int lsb,uint32_t bits)37 void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
38 int width = msb - lsb + 1;
39 VIXL_ASSERT(is_uintn(width, bits) || is_intn(width, bits));
40
41 bits <<= lsb;
42 uint32_t mask = ((1 << width) - 1) << lsb;
43 VIXL_ASSERT((mask & write_ignore_mask_) == 0);
44
45 value_ = (value_ & ~mask) | (bits & mask);
46 }
47
48
DefaultValueFor(SystemRegister id)49 SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
50 switch (id) {
51 case NZCV:
52 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
53 case FPCR:
54 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
55 default:
56 VIXL_UNREACHABLE();
57 return SimSystemRegister();
58 }
59 }
60
61
Simulator(Decoder * decoder,FILE * stream)62 Simulator::Simulator(Decoder* decoder, FILE* stream) {
63 // Ensure that shift operations act as the simulator expects.
64 VIXL_ASSERT((static_cast<int32_t>(-1) >> 1) == -1);
65 VIXL_ASSERT((static_cast<uint32_t>(-1) >> 1) == 0x7fffffff);
66
67 instruction_stats_ = false;
68
69 // Set up the decoder.
70 decoder_ = decoder;
71 decoder_->AppendVisitor(this);
72
73 stream_ = stream;
74 print_disasm_ = new PrintDisassembler(stream_);
75 set_coloured_trace(false);
76 trace_parameters_ = LOG_NONE;
77
78 ResetState();
79
80 // Allocate and set up the simulator stack.
81 stack_ = new byte[stack_size_];
82 stack_limit_ = stack_ + stack_protection_size_;
83 // Configure the starting stack pointer.
84 // - Find the top of the stack.
85 byte * tos = stack_ + stack_size_;
86 // - There's a protection region at both ends of the stack.
87 tos -= stack_protection_size_;
88 // - The stack pointer must be 16-byte aligned.
89 tos = AlignDown(tos, 16);
90 set_sp(tos);
91
92 // Set the sample period to 10, as the VIXL examples and tests are short.
93 instrumentation_ = new Instrument("vixl_stats.csv", 10);
94
95 // Print a warning about exclusive-access instructions, but only the first
96 // time they are encountered. This warning can be silenced using
97 // SilenceExclusiveAccessWarning().
98 print_exclusive_access_warning_ = true;
99 }
100
101
ResetState()102 void Simulator::ResetState() {
103 // Reset the system registers.
104 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
105 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
106
107 // Reset registers to 0.
108 pc_ = NULL;
109 pc_modified_ = false;
110 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
111 set_xreg(i, 0xbadbeef);
112 }
113 // Set FP registers to a value that is a NaN in both 32-bit and 64-bit FP.
114 uint64_t nan_bits = UINT64_C(0x7ff0dead7f8beef1);
115 VIXL_ASSERT(IsSignallingNaN(rawbits_to_double(nan_bits & kDRegMask)));
116 VIXL_ASSERT(IsSignallingNaN(rawbits_to_float(nan_bits & kSRegMask)));
117 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
118 set_dreg_bits(i, nan_bits);
119 }
120 // Returning to address 0 exits the Simulator.
121 set_lr(kEndOfSimAddress);
122 }
123
124
~Simulator()125 Simulator::~Simulator() {
126 delete[] stack_;
127 // The decoder may outlive the simulator.
128 decoder_->RemoveVisitor(print_disasm_);
129 delete print_disasm_;
130
131 decoder_->RemoveVisitor(instrumentation_);
132 delete instrumentation_;
133 }
134
135
Run()136 void Simulator::Run() {
137 pc_modified_ = false;
138 while (pc_ != kEndOfSimAddress) {
139 ExecuteInstruction();
140 LogAllWrittenRegisters();
141 }
142 }
143
144
RunFrom(const Instruction * first)145 void Simulator::RunFrom(const Instruction* first) {
146 set_pc(first);
147 Run();
148 }
149
150
151 const char* Simulator::xreg_names[] = {
152 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
153 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
154 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
155 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "xzr", "sp"};
156
157 const char* Simulator::wreg_names[] = {
158 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
159 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
160 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
161 "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr", "wsp"};
162
163 const char* Simulator::sreg_names[] = {
164 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
165 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
166 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
167 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
168
169 const char* Simulator::dreg_names[] = {
170 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
171 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
172 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
173 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
174
175 const char* Simulator::vreg_names[] = {
176 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
177 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
178 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
179 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
180
181
182
WRegNameForCode(unsigned code,Reg31Mode mode)183 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
184 VIXL_ASSERT(code < kNumberOfRegisters);
185 // If the code represents the stack pointer, index the name after zr.
186 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
187 code = kZeroRegCode + 1;
188 }
189 return wreg_names[code];
190 }
191
192
XRegNameForCode(unsigned code,Reg31Mode mode)193 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
194 VIXL_ASSERT(code < kNumberOfRegisters);
195 // If the code represents the stack pointer, index the name after zr.
196 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
197 code = kZeroRegCode + 1;
198 }
199 return xreg_names[code];
200 }
201
202
SRegNameForCode(unsigned code)203 const char* Simulator::SRegNameForCode(unsigned code) {
204 VIXL_ASSERT(code < kNumberOfFPRegisters);
205 return sreg_names[code];
206 }
207
208
DRegNameForCode(unsigned code)209 const char* Simulator::DRegNameForCode(unsigned code) {
210 VIXL_ASSERT(code < kNumberOfFPRegisters);
211 return dreg_names[code];
212 }
213
214
VRegNameForCode(unsigned code)215 const char* Simulator::VRegNameForCode(unsigned code) {
216 VIXL_ASSERT(code < kNumberOfVRegisters);
217 return vreg_names[code];
218 }
219
220
221 #define COLOUR(colour_code) "\033[0;" colour_code "m"
222 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
223 #define NORMAL ""
224 #define GREY "30"
225 #define RED "31"
226 #define GREEN "32"
227 #define YELLOW "33"
228 #define BLUE "34"
229 #define MAGENTA "35"
230 #define CYAN "36"
231 #define WHITE "37"
set_coloured_trace(bool value)232 void Simulator::set_coloured_trace(bool value) {
233 coloured_trace_ = value;
234
235 clr_normal = value ? COLOUR(NORMAL) : "";
236 clr_flag_name = value ? COLOUR_BOLD(WHITE) : "";
237 clr_flag_value = value ? COLOUR(NORMAL) : "";
238 clr_reg_name = value ? COLOUR_BOLD(CYAN) : "";
239 clr_reg_value = value ? COLOUR(CYAN) : "";
240 clr_vreg_name = value ? COLOUR_BOLD(MAGENTA) : "";
241 clr_vreg_value = value ? COLOUR(MAGENTA) : "";
242 clr_memory_address = value ? COLOUR_BOLD(BLUE) : "";
243 clr_warning = value ? COLOUR_BOLD(YELLOW) : "";
244 clr_warning_message = value ? COLOUR(YELLOW) : "";
245 clr_printf = value ? COLOUR(GREEN) : "";
246 }
247
248
set_trace_parameters(int parameters)249 void Simulator::set_trace_parameters(int parameters) {
250 bool disasm_before = trace_parameters_ & LOG_DISASM;
251 trace_parameters_ = parameters;
252 bool disasm_after = trace_parameters_ & LOG_DISASM;
253
254 if (disasm_before != disasm_after) {
255 if (disasm_after) {
256 decoder_->InsertVisitorBefore(print_disasm_, this);
257 } else {
258 decoder_->RemoveVisitor(print_disasm_);
259 }
260 }
261 }
262
263
set_instruction_stats(bool value)264 void Simulator::set_instruction_stats(bool value) {
265 if (value != instruction_stats_) {
266 if (value) {
267 decoder_->AppendVisitor(instrumentation_);
268 } else {
269 decoder_->RemoveVisitor(instrumentation_);
270 }
271 instruction_stats_ = value;
272 }
273 }
274
275 // Helpers ---------------------------------------------------------------------
AddWithCarry(unsigned reg_size,bool set_flags,int64_t src1,int64_t src2,int64_t carry_in)276 int64_t Simulator::AddWithCarry(unsigned reg_size,
277 bool set_flags,
278 int64_t src1,
279 int64_t src2,
280 int64_t carry_in) {
281 VIXL_ASSERT((carry_in == 0) || (carry_in == 1));
282 VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));
283
284 uint64_t u1, u2;
285 int64_t result;
286 int64_t signed_sum = src1 + src2 + carry_in;
287
288 uint32_t N, Z, C, V;
289
290 if (reg_size == kWRegSize) {
291 u1 = static_cast<uint64_t>(src1) & kWRegMask;
292 u2 = static_cast<uint64_t>(src2) & kWRegMask;
293
294 result = signed_sum & kWRegMask;
295 // Compute the C flag by comparing the sum to the max unsigned integer.
296 C = ((kWMaxUInt - u1) < (u2 + carry_in)) ||
297 ((kWMaxUInt - u1 - carry_in) < u2);
298 // Overflow iff the sign bit is the same for the two inputs and different
299 // for the result.
300 int64_t s_src1 = src1 << (kXRegSize - kWRegSize);
301 int64_t s_src2 = src2 << (kXRegSize - kWRegSize);
302 int64_t s_result = result << (kXRegSize - kWRegSize);
303 V = ((s_src1 ^ s_src2) >= 0) && ((s_src1 ^ s_result) < 0);
304
305 } else {
306 u1 = static_cast<uint64_t>(src1);
307 u2 = static_cast<uint64_t>(src2);
308
309 result = signed_sum;
310 // Compute the C flag by comparing the sum to the max unsigned integer.
311 C = ((kXMaxUInt - u1) < (u2 + carry_in)) ||
312 ((kXMaxUInt - u1 - carry_in) < u2);
313 // Overflow iff the sign bit is the same for the two inputs and different
314 // for the result.
315 V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
316 }
317
318 N = CalcNFlag(result, reg_size);
319 Z = CalcZFlag(result);
320
321 if (set_flags) {
322 nzcv().SetN(N);
323 nzcv().SetZ(Z);
324 nzcv().SetC(C);
325 nzcv().SetV(V);
326 LogSystemRegister(NZCV);
327 }
328 return result;
329 }
330
331
ShiftOperand(unsigned reg_size,int64_t value,Shift shift_type,unsigned amount)332 int64_t Simulator::ShiftOperand(unsigned reg_size,
333 int64_t value,
334 Shift shift_type,
335 unsigned amount) {
336 if (amount == 0) {
337 return value;
338 }
339 int64_t mask = reg_size == kXRegSize ? kXRegMask : kWRegMask;
340 switch (shift_type) {
341 case LSL:
342 return (value << amount) & mask;
343 case LSR:
344 return static_cast<uint64_t>(value) >> amount;
345 case ASR: {
346 // Shift used to restore the sign.
347 unsigned s_shift = kXRegSize - reg_size;
348 // Value with its sign restored.
349 int64_t s_value = (value << s_shift) >> s_shift;
350 return (s_value >> amount) & mask;
351 }
352 case ROR: {
353 if (reg_size == kWRegSize) {
354 value &= kWRegMask;
355 }
356 return (static_cast<uint64_t>(value) >> amount) |
357 ((value & ((INT64_C(1) << amount) - 1)) <<
358 (reg_size - amount));
359 }
360 default:
361 VIXL_UNIMPLEMENTED();
362 return 0;
363 }
364 }
365
366
ExtendValue(unsigned reg_size,int64_t value,Extend extend_type,unsigned left_shift)367 int64_t Simulator::ExtendValue(unsigned reg_size,
368 int64_t value,
369 Extend extend_type,
370 unsigned left_shift) {
371 switch (extend_type) {
372 case UXTB:
373 value &= kByteMask;
374 break;
375 case UXTH:
376 value &= kHalfWordMask;
377 break;
378 case UXTW:
379 value &= kWordMask;
380 break;
381 case SXTB:
382 value = (value << 56) >> 56;
383 break;
384 case SXTH:
385 value = (value << 48) >> 48;
386 break;
387 case SXTW:
388 value = (value << 32) >> 32;
389 break;
390 case UXTX:
391 case SXTX:
392 break;
393 default:
394 VIXL_UNREACHABLE();
395 }
396 int64_t mask = (reg_size == kXRegSize) ? kXRegMask : kWRegMask;
397 return (value << left_shift) & mask;
398 }
399
400
FPCompare(double val0,double val1,FPTrapFlags trap)401 void Simulator::FPCompare(double val0, double val1, FPTrapFlags trap) {
402 AssertSupportedFPCR();
403
404 // TODO: This assumes that the C++ implementation handles comparisons in the
405 // way that we expect (as per AssertSupportedFPCR()).
406 bool process_exception = false;
407 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
408 nzcv().SetRawValue(FPUnorderedFlag);
409 if (IsSignallingNaN(val0) || IsSignallingNaN(val1) ||
410 (trap == EnableTrap)) {
411 process_exception = true;
412 }
413 } else if (val0 < val1) {
414 nzcv().SetRawValue(FPLessThanFlag);
415 } else if (val0 > val1) {
416 nzcv().SetRawValue(FPGreaterThanFlag);
417 } else if (val0 == val1) {
418 nzcv().SetRawValue(FPEqualFlag);
419 } else {
420 VIXL_UNREACHABLE();
421 }
422 LogSystemRegister(NZCV);
423 if (process_exception) FPProcessException();
424 }
425
426
GetPrintRegisterFormatForSize(unsigned reg_size,unsigned lane_size)427 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
428 unsigned reg_size, unsigned lane_size) {
429 VIXL_ASSERT(reg_size >= lane_size);
430
431 uint32_t format = 0;
432 if (reg_size != lane_size) {
433 switch (reg_size) {
434 default: VIXL_UNREACHABLE(); break;
435 case kQRegSizeInBytes: format = kPrintRegAsQVector; break;
436 case kDRegSizeInBytes: format = kPrintRegAsDVector; break;
437 }
438 }
439
440 switch (lane_size) {
441 default: VIXL_UNREACHABLE(); break;
442 case kQRegSizeInBytes: format |= kPrintReg1Q; break;
443 case kDRegSizeInBytes: format |= kPrintReg1D; break;
444 case kSRegSizeInBytes: format |= kPrintReg1S; break;
445 case kHRegSizeInBytes: format |= kPrintReg1H; break;
446 case kBRegSizeInBytes: format |= kPrintReg1B; break;
447 }
448 // These sizes would be duplicate case labels.
449 VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes);
450 VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes);
451 VIXL_STATIC_ASSERT(kPrintXReg == kPrintReg1D);
452 VIXL_STATIC_ASSERT(kPrintWReg == kPrintReg1S);
453
454 return static_cast<PrintRegisterFormat>(format);
455 }
456
457
GetPrintRegisterFormat(VectorFormat vform)458 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
459 VectorFormat vform) {
460 switch (vform) {
461 default: VIXL_UNREACHABLE(); return kPrintReg16B;
462 case kFormat16B: return kPrintReg16B;
463 case kFormat8B: return kPrintReg8B;
464 case kFormat8H: return kPrintReg8H;
465 case kFormat4H: return kPrintReg4H;
466 case kFormat4S: return kPrintReg4S;
467 case kFormat2S: return kPrintReg2S;
468 case kFormat2D: return kPrintReg2D;
469 case kFormat1D: return kPrintReg1D;
470 }
471 }
472
473
PrintWrittenRegisters()474 void Simulator::PrintWrittenRegisters() {
475 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
476 if (registers_[i].WrittenSinceLastLog()) PrintRegister(i);
477 }
478 }
479
480
PrintWrittenVRegisters()481 void Simulator::PrintWrittenVRegisters() {
482 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
483 // At this point there is no type information, so print as a raw 1Q.
484 if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q);
485 }
486 }
487
488
PrintSystemRegisters()489 void Simulator::PrintSystemRegisters() {
490 PrintSystemRegister(NZCV);
491 PrintSystemRegister(FPCR);
492 }
493
494
PrintRegisters()495 void Simulator::PrintRegisters() {
496 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
497 PrintRegister(i);
498 }
499 }
500
501
PrintVRegisters()502 void Simulator::PrintVRegisters() {
503 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
504 // At this point there is no type information, so print as a raw 1Q.
505 PrintVRegister(i, kPrintReg1Q);
506 }
507 }
508
509
510 // Print a register's name and raw value.
511 //
512 // Only the least-significant `size_in_bytes` bytes of the register are printed,
513 // but the value is aligned as if the whole register had been printed.
514 //
515 // For typical register updates, size_in_bytes should be set to kXRegSizeInBytes
516 // -- the default -- so that the whole register is printed. Other values of
517 // size_in_bytes are intended for use when the register hasn't actually been
518 // updated (such as in PrintWrite).
519 //
520 // No newline is printed. This allows the caller to print more details (such as
521 // a memory access annotation).
PrintRegisterRawHelper(unsigned code,Reg31Mode r31mode,int size_in_bytes)522 void Simulator::PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode,
523 int size_in_bytes) {
524 // The template for all supported sizes.
525 // "# x{code}: 0xffeeddccbbaa9988"
526 // "# w{code}: 0xbbaa9988"
527 // "# w{code}<15:0>: 0x9988"
528 // "# w{code}<7:0>: 0x88"
529 unsigned padding_chars = (kXRegSizeInBytes - size_in_bytes) * 2;
530
531 const char * name = "";
532 const char * suffix = "";
533 switch (size_in_bytes) {
534 case kXRegSizeInBytes: name = XRegNameForCode(code, r31mode); break;
535 case kWRegSizeInBytes: name = WRegNameForCode(code, r31mode); break;
536 case 2:
537 name = WRegNameForCode(code, r31mode);
538 suffix = "<15:0>";
539 padding_chars -= strlen(suffix);
540 break;
541 case 1:
542 name = WRegNameForCode(code, r31mode);
543 suffix = "<7:0>";
544 padding_chars -= strlen(suffix);
545 break;
546 default:
547 VIXL_UNREACHABLE();
548 }
549 fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix);
550
551 // Print leading padding spaces.
552 VIXL_ASSERT(padding_chars < (kXRegSizeInBytes * 2));
553 for (unsigned i = 0; i < padding_chars; i++) {
554 putc(' ', stream_);
555 }
556
557 // Print the specified bits in hexadecimal format.
558 uint64_t bits = reg<uint64_t>(code, r31mode);
559 bits &= kXRegMask >> ((kXRegSizeInBytes - size_in_bytes) * 8);
560 VIXL_STATIC_ASSERT(sizeof(bits) == kXRegSizeInBytes);
561
562 int chars = size_in_bytes * 2;
563 fprintf(stream_, "%s0x%0*" PRIx64 "%s",
564 clr_reg_value, chars, bits, clr_normal);
565 }
566
567
PrintRegister(unsigned code,Reg31Mode r31mode)568 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
569 registers_[code].NotifyRegisterLogged();
570
571 // Don't print writes into xzr.
572 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
573 return;
574 }
575
576 // The template for all x and w registers:
577 // "# x{code}: 0x{value}"
578 // "# w{code}: 0x{value}"
579
580 PrintRegisterRawHelper(code, r31mode);
581 fprintf(stream_, "\n");
582 }
583
584
585 // Print a register's name and raw value.
586 //
587 // The `bytes` and `lsb` arguments can be used to limit the bytes that are
588 // printed. These arguments are intended for use in cases where register hasn't
589 // actually been updated (such as in PrintVWrite).
590 //
591 // No newline is printed. This allows the caller to print more details (such as
592 // a floating-point interpretation or a memory access annotation).
PrintVRegisterRawHelper(unsigned code,int bytes,int lsb)593 void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) {
594 // The template for vector types:
595 // "# v{code}: 0xffeeddccbbaa99887766554433221100".
596 // An example with bytes=4 and lsb=8:
597 // "# v{code}: 0xbbaa9988 ".
598 fprintf(stream_, "# %s%5s: %s",
599 clr_vreg_name, VRegNameForCode(code), clr_vreg_value);
600
601 int msb = lsb + bytes - 1;
602 int byte = kQRegSizeInBytes - 1;
603
604 // Print leading padding spaces. (Two spaces per byte.)
605 while (byte > msb) {
606 fprintf(stream_, " ");
607 byte--;
608 }
609
610 // Print the specified part of the value, byte by byte.
611 qreg_t rawbits = qreg(code);
612 fprintf(stream_, "0x");
613 while (byte >= lsb) {
614 fprintf(stream_, "%02x", rawbits.val[byte]);
615 byte--;
616 }
617
618 // Print trailing padding spaces.
619 while (byte >= 0) {
620 fprintf(stream_, " ");
621 byte--;
622 }
623 fprintf(stream_, "%s", clr_normal);
624 }
625
626
627 // Print each of the specified lanes of a register as a float or double value.
628 //
629 // The `lane_count` and `lslane` arguments can be used to limit the lanes that
630 // are printed. These arguments are intended for use in cases where register
631 // hasn't actually been updated (such as in PrintVWrite).
632 //
633 // No newline is printed. This allows the caller to print more details (such as
634 // a memory access annotation).
PrintVRegisterFPHelper(unsigned code,unsigned lane_size_in_bytes,int lane_count,int rightmost_lane)635 void Simulator::PrintVRegisterFPHelper(unsigned code,
636 unsigned lane_size_in_bytes,
637 int lane_count,
638 int rightmost_lane) {
639 VIXL_ASSERT((lane_size_in_bytes == kSRegSizeInBytes) ||
640 (lane_size_in_bytes == kDRegSizeInBytes));
641
642 unsigned msb = ((lane_count + rightmost_lane) * lane_size_in_bytes);
643 VIXL_ASSERT(msb <= kQRegSizeInBytes);
644
645 // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register
646 // name is used:
647 // " (s{code}: {value})"
648 // " (d{code}: {value})"
649 // For vector types, "..." is used to represent one or more omitted lanes.
650 // " (..., {value}, {value}, ...)"
651 if ((lane_count == 1) && (rightmost_lane == 0)) {
652 const char * name =
653 (lane_size_in_bytes == kSRegSizeInBytes) ? SRegNameForCode(code)
654 : DRegNameForCode(code);
655 fprintf(stream_, " (%s%s: ", clr_vreg_name, name);
656 } else {
657 if (msb < (kQRegSizeInBytes - 1)) {
658 fprintf(stream_, " (..., ");
659 } else {
660 fprintf(stream_, " (");
661 }
662 }
663
664 // Print the list of values.
665 const char * separator = "";
666 int leftmost_lane = rightmost_lane + lane_count - 1;
667 for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) {
668 double value =
669 (lane_size_in_bytes == kSRegSizeInBytes) ? vreg(code).Get<float>(lane)
670 : vreg(code).Get<double>(lane);
671 fprintf(stream_, "%s%s%#g%s", separator, clr_vreg_value, value, clr_normal);
672 separator = ", ";
673 }
674
675 if (rightmost_lane > 0) {
676 fprintf(stream_, ", ...");
677 }
678 fprintf(stream_, ")");
679 }
680
681
PrintVRegister(unsigned code,PrintRegisterFormat format)682 void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) {
683 vregisters_[code].NotifyRegisterLogged();
684
685 int lane_size_log2 = format & kPrintRegLaneSizeMask;
686
687 int reg_size_log2;
688 if (format & kPrintRegAsQVector) {
689 reg_size_log2 = kQRegSizeInBytesLog2;
690 } else if (format & kPrintRegAsDVector) {
691 reg_size_log2 = kDRegSizeInBytesLog2;
692 } else {
693 // Scalar types.
694 reg_size_log2 = lane_size_log2;
695 }
696
697 int lane_count = 1 << (reg_size_log2 - lane_size_log2);
698 int lane_size = 1 << lane_size_log2;
699
700 // The template for vector types:
701 // "# v{code}: 0x{rawbits} (..., {value}, ...)".
702 // The template for scalar types:
703 // "# v{code}: 0x{rawbits} ({reg}:{value})".
704 // The values in parentheses after the bit representations are floating-point
705 // interpretations. They are displayed only if the kPrintVRegAsFP bit is set.
706
707 PrintVRegisterRawHelper(code);
708 if (format & kPrintRegAsFP) {
709 PrintVRegisterFPHelper(code, lane_size, lane_count);
710 }
711
712 fprintf(stream_, "\n");
713 }
714
715
PrintSystemRegister(SystemRegister id)716 void Simulator::PrintSystemRegister(SystemRegister id) {
717 switch (id) {
718 case NZCV:
719 fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
720 clr_flag_name, clr_flag_value,
721 nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
722 clr_normal);
723 break;
724 case FPCR: {
725 static const char * rmode[] = {
726 "0b00 (Round to Nearest)",
727 "0b01 (Round towards Plus Infinity)",
728 "0b10 (Round towards Minus Infinity)",
729 "0b11 (Round towards Zero)"
730 };
731 VIXL_ASSERT(fpcr().RMode() < (sizeof(rmode) / sizeof(rmode[0])));
732 fprintf(stream_,
733 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
734 clr_flag_name, clr_flag_value,
735 fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
736 clr_normal);
737 break;
738 }
739 default:
740 VIXL_UNREACHABLE();
741 }
742 }
743
744
PrintRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)745 void Simulator::PrintRead(uintptr_t address,
746 unsigned reg_code,
747 PrintRegisterFormat format) {
748 registers_[reg_code].NotifyRegisterLogged();
749
750 USE(format);
751
752 // The template is "# {reg}: 0x{value} <- {address}".
753 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister);
754 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
755 clr_memory_address, address, clr_normal);
756 }
757
758
PrintVRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)759 void Simulator::PrintVRead(uintptr_t address,
760 unsigned reg_code,
761 PrintRegisterFormat format,
762 unsigned lane) {
763 vregisters_[reg_code].NotifyRegisterLogged();
764
765 // The template is "# v{code}: 0x{rawbits} <- address".
766 PrintVRegisterRawHelper(reg_code);
767 if (format & kPrintRegAsFP) {
768 PrintVRegisterFPHelper(reg_code, GetPrintRegLaneSizeInBytes(format),
769 GetPrintRegLaneCount(format), lane);
770 }
771 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
772 clr_memory_address, address, clr_normal);
773 }
774
775
PrintWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)776 void Simulator::PrintWrite(uintptr_t address,
777 unsigned reg_code,
778 PrintRegisterFormat format) {
779 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
780
781 // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy
782 // and readable, the value is aligned with the values in the register trace.
783 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister,
784 GetPrintRegSizeInBytes(format));
785 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
786 clr_memory_address, address, clr_normal);
787 }
788
789
PrintVWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)790 void Simulator::PrintVWrite(uintptr_t address,
791 unsigned reg_code,
792 PrintRegisterFormat format,
793 unsigned lane) {
794 // The templates:
795 // "# v{code}: 0x{rawbits} -> {address}"
796 // "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}".
797 // "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}"
798 // Because this trace doesn't represent a change to the source register's
799 // value, only the relevant part of the value is printed. To keep the trace
800 // tidy and readable, the raw value is aligned with the other values in the
801 // register trace.
802 int lane_count = GetPrintRegLaneCount(format);
803 int lane_size = GetPrintRegLaneSizeInBytes(format);
804 int reg_size = GetPrintRegSizeInBytes(format);
805 PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane);
806 if (format & kPrintRegAsFP) {
807 PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane);
808 }
809 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
810 clr_memory_address, address, clr_normal);
811 }
812
813
814 // Visitors---------------------------------------------------------------------
815
VisitUnimplemented(const Instruction * instr)816 void Simulator::VisitUnimplemented(const Instruction* instr) {
817 printf("Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
818 reinterpret_cast<const void*>(instr), instr->InstructionBits());
819 VIXL_UNIMPLEMENTED();
820 }
821
822
VisitUnallocated(const Instruction * instr)823 void Simulator::VisitUnallocated(const Instruction* instr) {
824 printf("Unallocated instruction at %p: 0x%08" PRIx32 "\n",
825 reinterpret_cast<const void*>(instr), instr->InstructionBits());
826 VIXL_UNIMPLEMENTED();
827 }
828
829
VisitPCRelAddressing(const Instruction * instr)830 void Simulator::VisitPCRelAddressing(const Instruction* instr) {
831 VIXL_ASSERT((instr->Mask(PCRelAddressingMask) == ADR) ||
832 (instr->Mask(PCRelAddressingMask) == ADRP));
833
834 set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
835 }
836
837
VisitUnconditionalBranch(const Instruction * instr)838 void Simulator::VisitUnconditionalBranch(const Instruction* instr) {
839 switch (instr->Mask(UnconditionalBranchMask)) {
840 case BL:
841 set_lr(instr->NextInstruction());
842 VIXL_FALLTHROUGH();
843 case B:
844 set_pc(instr->ImmPCOffsetTarget());
845 break;
846 default: VIXL_UNREACHABLE();
847 }
848 }
849
850
VisitConditionalBranch(const Instruction * instr)851 void Simulator::VisitConditionalBranch(const Instruction* instr) {
852 VIXL_ASSERT(instr->Mask(ConditionalBranchMask) == B_cond);
853 if (ConditionPassed(instr->ConditionBranch())) {
854 set_pc(instr->ImmPCOffsetTarget());
855 }
856 }
857
858
VisitUnconditionalBranchToRegister(const Instruction * instr)859 void Simulator::VisitUnconditionalBranchToRegister(const Instruction* instr) {
860 const Instruction* target = Instruction::Cast(xreg(instr->Rn()));
861
862 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
863 case BLR:
864 set_lr(instr->NextInstruction());
865 VIXL_FALLTHROUGH();
866 case BR:
867 case RET: set_pc(target); break;
868 default: VIXL_UNREACHABLE();
869 }
870 }
871
872
VisitTestBranch(const Instruction * instr)873 void Simulator::VisitTestBranch(const Instruction* instr) {
874 unsigned bit_pos = (instr->ImmTestBranchBit5() << 5) |
875 instr->ImmTestBranchBit40();
876 bool bit_zero = ((xreg(instr->Rt()) >> bit_pos) & 1) == 0;
877 bool take_branch = false;
878 switch (instr->Mask(TestBranchMask)) {
879 case TBZ: take_branch = bit_zero; break;
880 case TBNZ: take_branch = !bit_zero; break;
881 default: VIXL_UNIMPLEMENTED();
882 }
883 if (take_branch) {
884 set_pc(instr->ImmPCOffsetTarget());
885 }
886 }
887
888
VisitCompareBranch(const Instruction * instr)889 void Simulator::VisitCompareBranch(const Instruction* instr) {
890 unsigned rt = instr->Rt();
891 bool take_branch = false;
892 switch (instr->Mask(CompareBranchMask)) {
893 case CBZ_w: take_branch = (wreg(rt) == 0); break;
894 case CBZ_x: take_branch = (xreg(rt) == 0); break;
895 case CBNZ_w: take_branch = (wreg(rt) != 0); break;
896 case CBNZ_x: take_branch = (xreg(rt) != 0); break;
897 default: VIXL_UNIMPLEMENTED();
898 }
899 if (take_branch) {
900 set_pc(instr->ImmPCOffsetTarget());
901 }
902 }
903
904
AddSubHelper(const Instruction * instr,int64_t op2)905 void Simulator::AddSubHelper(const Instruction* instr, int64_t op2) {
906 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
907 bool set_flags = instr->FlagsUpdate();
908 int64_t new_val = 0;
909 Instr operation = instr->Mask(AddSubOpMask);
910
911 switch (operation) {
912 case ADD:
913 case ADDS: {
914 new_val = AddWithCarry(reg_size,
915 set_flags,
916 reg(reg_size, instr->Rn(), instr->RnMode()),
917 op2);
918 break;
919 }
920 case SUB:
921 case SUBS: {
922 new_val = AddWithCarry(reg_size,
923 set_flags,
924 reg(reg_size, instr->Rn(), instr->RnMode()),
925 ~op2,
926 1);
927 break;
928 }
929 default: VIXL_UNREACHABLE();
930 }
931
932 set_reg(reg_size, instr->Rd(), new_val, LogRegWrites, instr->RdMode());
933 }
934
935
VisitAddSubShifted(const Instruction * instr)936 void Simulator::VisitAddSubShifted(const Instruction* instr) {
937 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
938 int64_t op2 = ShiftOperand(reg_size,
939 reg(reg_size, instr->Rm()),
940 static_cast<Shift>(instr->ShiftDP()),
941 instr->ImmDPShift());
942 AddSubHelper(instr, op2);
943 }
944
945
VisitAddSubImmediate(const Instruction * instr)946 void Simulator::VisitAddSubImmediate(const Instruction* instr) {
947 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
948 AddSubHelper(instr, op2);
949 }
950
951
VisitAddSubExtended(const Instruction * instr)952 void Simulator::VisitAddSubExtended(const Instruction* instr) {
953 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
954 int64_t op2 = ExtendValue(reg_size,
955 reg(reg_size, instr->Rm()),
956 static_cast<Extend>(instr->ExtendMode()),
957 instr->ImmExtendShift());
958 AddSubHelper(instr, op2);
959 }
960
961
VisitAddSubWithCarry(const Instruction * instr)962 void Simulator::VisitAddSubWithCarry(const Instruction* instr) {
963 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
964 int64_t op2 = reg(reg_size, instr->Rm());
965 int64_t new_val;
966
967 if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
968 op2 = ~op2;
969 }
970
971 new_val = AddWithCarry(reg_size,
972 instr->FlagsUpdate(),
973 reg(reg_size, instr->Rn()),
974 op2,
975 C());
976
977 set_reg(reg_size, instr->Rd(), new_val);
978 }
979
980
VisitLogicalShifted(const Instruction * instr)981 void Simulator::VisitLogicalShifted(const Instruction* instr) {
982 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
983 Shift shift_type = static_cast<Shift>(instr->ShiftDP());
984 unsigned shift_amount = instr->ImmDPShift();
985 int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type,
986 shift_amount);
987 if (instr->Mask(NOT) == NOT) {
988 op2 = ~op2;
989 }
990 LogicalHelper(instr, op2);
991 }
992
993
VisitLogicalImmediate(const Instruction * instr)994 void Simulator::VisitLogicalImmediate(const Instruction* instr) {
995 LogicalHelper(instr, instr->ImmLogical());
996 }
997
998
LogicalHelper(const Instruction * instr,int64_t op2)999 void Simulator::LogicalHelper(const Instruction* instr, int64_t op2) {
1000 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1001 int64_t op1 = reg(reg_size, instr->Rn());
1002 int64_t result = 0;
1003 bool update_flags = false;
1004
1005 // Switch on the logical operation, stripping out the NOT bit, as it has a
1006 // different meaning for logical immediate instructions.
1007 switch (instr->Mask(LogicalOpMask & ~NOT)) {
1008 case ANDS: update_flags = true; VIXL_FALLTHROUGH();
1009 case AND: result = op1 & op2; break;
1010 case ORR: result = op1 | op2; break;
1011 case EOR: result = op1 ^ op2; break;
1012 default:
1013 VIXL_UNIMPLEMENTED();
1014 }
1015
1016 if (update_flags) {
1017 nzcv().SetN(CalcNFlag(result, reg_size));
1018 nzcv().SetZ(CalcZFlag(result));
1019 nzcv().SetC(0);
1020 nzcv().SetV(0);
1021 LogSystemRegister(NZCV);
1022 }
1023
1024 set_reg(reg_size, instr->Rd(), result, LogRegWrites, instr->RdMode());
1025 }
1026
1027
VisitConditionalCompareRegister(const Instruction * instr)1028 void Simulator::VisitConditionalCompareRegister(const Instruction* instr) {
1029 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1030 ConditionalCompareHelper(instr, reg(reg_size, instr->Rm()));
1031 }
1032
1033
VisitConditionalCompareImmediate(const Instruction * instr)1034 void Simulator::VisitConditionalCompareImmediate(const Instruction* instr) {
1035 ConditionalCompareHelper(instr, instr->ImmCondCmp());
1036 }
1037
1038
ConditionalCompareHelper(const Instruction * instr,int64_t op2)1039 void Simulator::ConditionalCompareHelper(const Instruction* instr,
1040 int64_t op2) {
1041 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1042 int64_t op1 = reg(reg_size, instr->Rn());
1043
1044 if (ConditionPassed(instr->Condition())) {
1045 // If the condition passes, set the status flags to the result of comparing
1046 // the operands.
1047 if (instr->Mask(ConditionalCompareMask) == CCMP) {
1048 AddWithCarry(reg_size, true, op1, ~op2, 1);
1049 } else {
1050 VIXL_ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
1051 AddWithCarry(reg_size, true, op1, op2, 0);
1052 }
1053 } else {
1054 // If the condition fails, set the status flags to the nzcv immediate.
1055 nzcv().SetFlags(instr->Nzcv());
1056 LogSystemRegister(NZCV);
1057 }
1058 }
1059
1060
VisitLoadStoreUnsignedOffset(const Instruction * instr)1061 void Simulator::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
1062 int offset = instr->ImmLSUnsigned() << instr->SizeLS();
1063 LoadStoreHelper(instr, offset, Offset);
1064 }
1065
1066
VisitLoadStoreUnscaledOffset(const Instruction * instr)1067 void Simulator::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
1068 LoadStoreHelper(instr, instr->ImmLS(), Offset);
1069 }
1070
1071
VisitLoadStorePreIndex(const Instruction * instr)1072 void Simulator::VisitLoadStorePreIndex(const Instruction* instr) {
1073 LoadStoreHelper(instr, instr->ImmLS(), PreIndex);
1074 }
1075
1076
VisitLoadStorePostIndex(const Instruction * instr)1077 void Simulator::VisitLoadStorePostIndex(const Instruction* instr) {
1078 LoadStoreHelper(instr, instr->ImmLS(), PostIndex);
1079 }
1080
1081
VisitLoadStoreRegisterOffset(const Instruction * instr)1082 void Simulator::VisitLoadStoreRegisterOffset(const Instruction* instr) {
1083 Extend ext = static_cast<Extend>(instr->ExtendMode());
1084 VIXL_ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
1085 unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
1086
1087 int64_t offset = ExtendValue(kXRegSize, xreg(instr->Rm()), ext,
1088 shift_amount);
1089 LoadStoreHelper(instr, offset, Offset);
1090 }
1091
1092
1093
LoadStoreHelper(const Instruction * instr,int64_t offset,AddrMode addrmode)1094 void Simulator::LoadStoreHelper(const Instruction* instr,
1095 int64_t offset,
1096 AddrMode addrmode) {
1097 unsigned srcdst = instr->Rt();
1098 uintptr_t address = AddressModeHelper(instr->Rn(), offset, addrmode);
1099
1100 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
1101 switch (op) {
1102 case LDRB_w:
1103 set_wreg(srcdst, Memory::Read<uint8_t>(address), NoRegLog); break;
1104 case LDRH_w:
1105 set_wreg(srcdst, Memory::Read<uint16_t>(address), NoRegLog); break;
1106 case LDR_w:
1107 set_wreg(srcdst, Memory::Read<uint32_t>(address), NoRegLog); break;
1108 case LDR_x:
1109 set_xreg(srcdst, Memory::Read<uint64_t>(address), NoRegLog); break;
1110 case LDRSB_w:
1111 set_wreg(srcdst, Memory::Read<int8_t>(address), NoRegLog); break;
1112 case LDRSH_w:
1113 set_wreg(srcdst, Memory::Read<int16_t>(address), NoRegLog); break;
1114 case LDRSB_x:
1115 set_xreg(srcdst, Memory::Read<int8_t>(address), NoRegLog); break;
1116 case LDRSH_x:
1117 set_xreg(srcdst, Memory::Read<int16_t>(address), NoRegLog); break;
1118 case LDRSW_x:
1119 set_xreg(srcdst, Memory::Read<int32_t>(address), NoRegLog); break;
1120 case LDR_b:
1121 set_breg(srcdst, Memory::Read<uint8_t>(address), NoRegLog); break;
1122 case LDR_h:
1123 set_hreg(srcdst, Memory::Read<uint16_t>(address), NoRegLog); break;
1124 case LDR_s:
1125 set_sreg(srcdst, Memory::Read<float>(address), NoRegLog); break;
1126 case LDR_d:
1127 set_dreg(srcdst, Memory::Read<double>(address), NoRegLog); break;
1128 case LDR_q:
1129 set_qreg(srcdst, Memory::Read<qreg_t>(address), NoRegLog); break;
1130
1131 case STRB_w: Memory::Write<uint8_t>(address, wreg(srcdst)); break;
1132 case STRH_w: Memory::Write<uint16_t>(address, wreg(srcdst)); break;
1133 case STR_w: Memory::Write<uint32_t>(address, wreg(srcdst)); break;
1134 case STR_x: Memory::Write<uint64_t>(address, xreg(srcdst)); break;
1135 case STR_b: Memory::Write<uint8_t>(address, breg(srcdst)); break;
1136 case STR_h: Memory::Write<uint16_t>(address, hreg(srcdst)); break;
1137 case STR_s: Memory::Write<float>(address, sreg(srcdst)); break;
1138 case STR_d: Memory::Write<double>(address, dreg(srcdst)); break;
1139 case STR_q: Memory::Write<qreg_t>(address, qreg(srcdst)); break;
1140
1141 // Ignore prfm hint instructions.
1142 case PRFM: break;
1143
1144 default: VIXL_UNIMPLEMENTED();
1145 }
1146
1147 size_t access_size = 1 << instr->SizeLS();
1148 if (instr->IsLoad()) {
1149 if ((op == LDR_s) || (op == LDR_d)) {
1150 LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1151 } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) {
1152 LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1153 } else {
1154 LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1155 }
1156 } else {
1157 if ((op == STR_s) || (op == STR_d)) {
1158 LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1159 } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) {
1160 LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1161 } else {
1162 LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1163 }
1164 }
1165
1166 local_monitor_.MaybeClear();
1167 }
1168
1169
VisitLoadStorePairOffset(const Instruction * instr)1170 void Simulator::VisitLoadStorePairOffset(const Instruction* instr) {
1171 LoadStorePairHelper(instr, Offset);
1172 }
1173
1174
VisitLoadStorePairPreIndex(const Instruction * instr)1175 void Simulator::VisitLoadStorePairPreIndex(const Instruction* instr) {
1176 LoadStorePairHelper(instr, PreIndex);
1177 }
1178
1179
VisitLoadStorePairPostIndex(const Instruction * instr)1180 void Simulator::VisitLoadStorePairPostIndex(const Instruction* instr) {
1181 LoadStorePairHelper(instr, PostIndex);
1182 }
1183
1184
VisitLoadStorePairNonTemporal(const Instruction * instr)1185 void Simulator::VisitLoadStorePairNonTemporal(const Instruction* instr) {
1186 LoadStorePairHelper(instr, Offset);
1187 }
1188
1189
LoadStorePairHelper(const Instruction * instr,AddrMode addrmode)1190 void Simulator::LoadStorePairHelper(const Instruction* instr,
1191 AddrMode addrmode) {
1192 unsigned rt = instr->Rt();
1193 unsigned rt2 = instr->Rt2();
1194 size_t element_size = 1 << instr->SizeLSPair();
1195 int64_t offset = instr->ImmLSPair() * element_size;
1196 uintptr_t address = AddressModeHelper(instr->Rn(), offset, addrmode);
1197 uintptr_t address2 = address + element_size;
1198
1199 LoadStorePairOp op =
1200 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
1201
1202 // 'rt' and 'rt2' can only be aliased for stores.
1203 VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2));
1204
1205 switch (op) {
1206 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
1207 // will print a more detailed log.
1208 case LDP_w: {
1209 set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
1210 set_wreg(rt2, Memory::Read<uint32_t>(address2), NoRegLog);
1211 break;
1212 }
1213 case LDP_s: {
1214 set_sreg(rt, Memory::Read<float>(address), NoRegLog);
1215 set_sreg(rt2, Memory::Read<float>(address2), NoRegLog);
1216 break;
1217 }
1218 case LDP_x: {
1219 set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
1220 set_xreg(rt2, Memory::Read<uint64_t>(address2), NoRegLog);
1221 break;
1222 }
1223 case LDP_d: {
1224 set_dreg(rt, Memory::Read<double>(address), NoRegLog);
1225 set_dreg(rt2, Memory::Read<double>(address2), NoRegLog);
1226 break;
1227 }
1228 case LDP_q: {
1229 set_qreg(rt, Memory::Read<qreg_t>(address), NoRegLog);
1230 set_qreg(rt2, Memory::Read<qreg_t>(address2), NoRegLog);
1231 break;
1232 }
1233 case LDPSW_x: {
1234 set_xreg(rt, Memory::Read<int32_t>(address), NoRegLog);
1235 set_xreg(rt2, Memory::Read<int32_t>(address2), NoRegLog);
1236 break;
1237 }
1238 case STP_w: {
1239 Memory::Write<uint32_t>(address, wreg(rt));
1240 Memory::Write<uint32_t>(address2, wreg(rt2));
1241 break;
1242 }
1243 case STP_s: {
1244 Memory::Write<float>(address, sreg(rt));
1245 Memory::Write<float>(address2, sreg(rt2));
1246 break;
1247 }
1248 case STP_x: {
1249 Memory::Write<uint64_t>(address, xreg(rt));
1250 Memory::Write<uint64_t>(address2, xreg(rt2));
1251 break;
1252 }
1253 case STP_d: {
1254 Memory::Write<double>(address, dreg(rt));
1255 Memory::Write<double>(address2, dreg(rt2));
1256 break;
1257 }
1258 case STP_q: {
1259 Memory::Write<qreg_t>(address, qreg(rt));
1260 Memory::Write<qreg_t>(address2, qreg(rt2));
1261 break;
1262 }
1263 default: VIXL_UNREACHABLE();
1264 }
1265
1266 // Print a detailed trace (including the memory address) instead of the basic
1267 // register:value trace generated by set_*reg().
1268 if (instr->IsLoad()) {
1269 if ((op == LDP_s) || (op == LDP_d)) {
1270 LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1271 LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1272 } else if (op == LDP_q) {
1273 LogVRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1274 LogVRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1275 } else {
1276 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1277 LogRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1278 }
1279 } else {
1280 if ((op == STP_s) || (op == STP_d)) {
1281 LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1282 LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1283 } else if (op == STP_q) {
1284 LogVWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1285 LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1286 } else {
1287 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1288 LogWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1289 }
1290 }
1291
1292 local_monitor_.MaybeClear();
1293 }
1294
1295
PrintExclusiveAccessWarning()1296 void Simulator::PrintExclusiveAccessWarning() {
1297 if (print_exclusive_access_warning_) {
1298 fprintf(
1299 stderr,
1300 "%sWARNING:%s VIXL simulator support for load-/store-/clear-exclusive "
1301 "instructions is limited. Refer to the README for details.%s\n",
1302 clr_warning, clr_warning_message, clr_normal);
1303 print_exclusive_access_warning_ = false;
1304 }
1305 }
1306
1307
VisitLoadStoreExclusive(const Instruction * instr)1308 void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
1309 PrintExclusiveAccessWarning();
1310
1311 unsigned rs = instr->Rs();
1312 unsigned rt = instr->Rt();
1313 unsigned rt2 = instr->Rt2();
1314 unsigned rn = instr->Rn();
1315
1316 LoadStoreExclusive op =
1317 static_cast<LoadStoreExclusive>(instr->Mask(LoadStoreExclusiveMask));
1318
1319 bool is_acquire_release = instr->LdStXAcquireRelease();
1320 bool is_exclusive = !instr->LdStXNotExclusive();
1321 bool is_load = instr->LdStXLoad();
1322 bool is_pair = instr->LdStXPair();
1323
1324 size_t element_size = 1 << instr->LdStXSizeLog2();
1325 size_t access_size = is_pair ? element_size * 2 : element_size;
1326 uint64_t address = reg<uint64_t>(rn, Reg31IsStackPointer);
1327
1328 // Verify that the address is available to the host.
1329 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1330
1331 // Check the alignment of `address`.
1332 if (AlignDown(address, access_size) != address) {
1333 VIXL_ALIGNMENT_EXCEPTION();
1334 }
1335
1336 // The sp must be aligned to 16 bytes when it is accessed.
1337 if ((rn == 31) && (AlignDown(address, 16) != address)) {
1338 VIXL_ALIGNMENT_EXCEPTION();
1339 }
1340
1341 if (is_load) {
1342 if (is_exclusive) {
1343 local_monitor_.MarkExclusive(address, access_size);
1344 } else {
1345 // Any non-exclusive load can clear the local monitor as a side effect. We
1346 // don't need to do this, but it is useful to stress the simulated code.
1347 local_monitor_.Clear();
1348 }
1349
1350 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
1351 // will print a more detailed log.
1352 switch (op) {
1353 case LDXRB_w:
1354 case LDAXRB_w:
1355 case LDARB_w:
1356 set_wreg(rt, Memory::Read<uint8_t>(address), NoRegLog);
1357 break;
1358 case LDXRH_w:
1359 case LDAXRH_w:
1360 case LDARH_w:
1361 set_wreg(rt, Memory::Read<uint16_t>(address), NoRegLog);
1362 break;
1363 case LDXR_w:
1364 case LDAXR_w:
1365 case LDAR_w:
1366 set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
1367 break;
1368 case LDXR_x:
1369 case LDAXR_x:
1370 case LDAR_x:
1371 set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
1372 break;
1373 case LDXP_w:
1374 case LDAXP_w:
1375 set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
1376 set_wreg(rt2, Memory::Read<uint32_t>(address + element_size), NoRegLog);
1377 break;
1378 case LDXP_x:
1379 case LDAXP_x:
1380 set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
1381 set_xreg(rt2, Memory::Read<uint64_t>(address + element_size), NoRegLog);
1382 break;
1383 default:
1384 VIXL_UNREACHABLE();
1385 }
1386
1387 if (is_acquire_release) {
1388 // Approximate load-acquire by issuing a full barrier after the load.
1389 __sync_synchronize();
1390 }
1391
1392 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1393 if (is_pair) {
1394 LogRead(address + element_size, rt2,
1395 GetPrintRegisterFormatForSize(element_size));
1396 }
1397 } else {
1398 if (is_acquire_release) {
1399 // Approximate store-release by issuing a full barrier before the store.
1400 __sync_synchronize();
1401 }
1402
1403 bool do_store = true;
1404 if (is_exclusive) {
1405 do_store = local_monitor_.IsExclusive(address, access_size) &&
1406 global_monitor_.IsExclusive(address, access_size);
1407 set_wreg(rs, do_store ? 0 : 1);
1408
1409 // - All exclusive stores explicitly clear the local monitor.
1410 local_monitor_.Clear();
1411 } else {
1412 // - Any other store can clear the local monitor as a side effect.
1413 local_monitor_.MaybeClear();
1414 }
1415
1416 if (do_store) {
1417 switch (op) {
1418 case STXRB_w:
1419 case STLXRB_w:
1420 case STLRB_w:
1421 Memory::Write<uint8_t>(address, wreg(rt));
1422 break;
1423 case STXRH_w:
1424 case STLXRH_w:
1425 case STLRH_w:
1426 Memory::Write<uint16_t>(address, wreg(rt));
1427 break;
1428 case STXR_w:
1429 case STLXR_w:
1430 case STLR_w:
1431 Memory::Write<uint32_t>(address, wreg(rt));
1432 break;
1433 case STXR_x:
1434 case STLXR_x:
1435 case STLR_x:
1436 Memory::Write<uint64_t>(address, xreg(rt));
1437 break;
1438 case STXP_w:
1439 case STLXP_w:
1440 Memory::Write<uint32_t>(address, wreg(rt));
1441 Memory::Write<uint32_t>(address + element_size, wreg(rt2));
1442 break;
1443 case STXP_x:
1444 case STLXP_x:
1445 Memory::Write<uint64_t>(address, xreg(rt));
1446 Memory::Write<uint64_t>(address + element_size, xreg(rt2));
1447 break;
1448 default:
1449 VIXL_UNREACHABLE();
1450 }
1451
1452 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1453 if (is_pair) {
1454 LogWrite(address + element_size, rt2,
1455 GetPrintRegisterFormatForSize(element_size));
1456 }
1457 }
1458 }
1459 }
1460
1461
VisitLoadLiteral(const Instruction * instr)1462 void Simulator::VisitLoadLiteral(const Instruction* instr) {
1463 unsigned rt = instr->Rt();
1464 uint64_t address = instr->LiteralAddress<uint64_t>();
1465
1466 // Verify that the calculated address is available to the host.
1467 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1468
1469 switch (instr->Mask(LoadLiteralMask)) {
1470 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
1471 // print a more detailed log.
1472 case LDR_w_lit:
1473 set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
1474 LogRead(address, rt, kPrintWReg);
1475 break;
1476 case LDR_x_lit:
1477 set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
1478 LogRead(address, rt, kPrintXReg);
1479 break;
1480 case LDR_s_lit:
1481 set_sreg(rt, Memory::Read<float>(address), NoRegLog);
1482 LogVRead(address, rt, kPrintSReg);
1483 break;
1484 case LDR_d_lit:
1485 set_dreg(rt, Memory::Read<double>(address), NoRegLog);
1486 LogVRead(address, rt, kPrintDReg);
1487 break;
1488 case LDR_q_lit:
1489 set_qreg(rt, Memory::Read<qreg_t>(address), NoRegLog);
1490 LogVRead(address, rt, kPrintReg1Q);
1491 break;
1492 case LDRSW_x_lit:
1493 set_xreg(rt, Memory::Read<int32_t>(address), NoRegLog);
1494 LogRead(address, rt, kPrintWReg);
1495 break;
1496
1497 // Ignore prfm hint instructions.
1498 case PRFM_lit: break;
1499
1500 default: VIXL_UNREACHABLE();
1501 }
1502
1503 local_monitor_.MaybeClear();
1504 }
1505
1506
AddressModeHelper(unsigned addr_reg,int64_t offset,AddrMode addrmode)1507 uintptr_t Simulator::AddressModeHelper(unsigned addr_reg,
1508 int64_t offset,
1509 AddrMode addrmode) {
1510 uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
1511
1512 if ((addr_reg == 31) && ((address % 16) != 0)) {
1513 // When the base register is SP the stack pointer is required to be
1514 // quadword aligned prior to the address calculation and write-backs.
1515 // Misalignment will cause a stack alignment fault.
1516 VIXL_ALIGNMENT_EXCEPTION();
1517 }
1518
1519 if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
1520 VIXL_ASSERT(offset != 0);
1521 // Only preindex should log the register update here. For Postindex, the
1522 // update will be printed automatically by LogWrittenRegisters _after_ the
1523 // memory access itself is logged.
1524 RegLogMode log_mode = (addrmode == PreIndex) ? LogRegWrites : NoRegLog;
1525 set_xreg(addr_reg, address + offset, log_mode, Reg31IsStackPointer);
1526 }
1527
1528 if ((addrmode == Offset) || (addrmode == PreIndex)) {
1529 address += offset;
1530 }
1531
1532 // Verify that the calculated address is available to the host.
1533 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1534
1535 return static_cast<uintptr_t>(address);
1536 }
1537
1538
VisitMoveWideImmediate(const Instruction * instr)1539 void Simulator::VisitMoveWideImmediate(const Instruction* instr) {
1540 MoveWideImmediateOp mov_op =
1541 static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
1542 int64_t new_xn_val = 0;
1543
1544 bool is_64_bits = instr->SixtyFourBits() == 1;
1545 // Shift is limited for W operations.
1546 VIXL_ASSERT(is_64_bits || (instr->ShiftMoveWide() < 2));
1547
1548 // Get the shifted immediate.
1549 int64_t shift = instr->ShiftMoveWide() * 16;
1550 int64_t shifted_imm16 = instr->ImmMoveWide() << shift;
1551
1552 // Compute the new value.
1553 switch (mov_op) {
1554 case MOVN_w:
1555 case MOVN_x: {
1556 new_xn_val = ~shifted_imm16;
1557 if (!is_64_bits) new_xn_val &= kWRegMask;
1558 break;
1559 }
1560 case MOVK_w:
1561 case MOVK_x: {
1562 unsigned reg_code = instr->Rd();
1563 int64_t prev_xn_val = is_64_bits ? xreg(reg_code)
1564 : wreg(reg_code);
1565 new_xn_val =
1566 (prev_xn_val & ~(INT64_C(0xffff) << shift)) | shifted_imm16;
1567 break;
1568 }
1569 case MOVZ_w:
1570 case MOVZ_x: {
1571 new_xn_val = shifted_imm16;
1572 break;
1573 }
1574 default:
1575 VIXL_UNREACHABLE();
1576 }
1577
1578 // Update the destination register.
1579 set_xreg(instr->Rd(), new_xn_val);
1580 }
1581
1582
VisitConditionalSelect(const Instruction * instr)1583 void Simulator::VisitConditionalSelect(const Instruction* instr) {
1584 uint64_t new_val = xreg(instr->Rn());
1585
1586 if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
1587 new_val = xreg(instr->Rm());
1588 switch (instr->Mask(ConditionalSelectMask)) {
1589 case CSEL_w:
1590 case CSEL_x: break;
1591 case CSINC_w:
1592 case CSINC_x: new_val++; break;
1593 case CSINV_w:
1594 case CSINV_x: new_val = ~new_val; break;
1595 case CSNEG_w:
1596 case CSNEG_x: new_val = -new_val; break;
1597 default: VIXL_UNIMPLEMENTED();
1598 }
1599 }
1600 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1601 set_reg(reg_size, instr->Rd(), new_val);
1602 }
1603
1604
VisitDataProcessing1Source(const Instruction * instr)1605 void Simulator::VisitDataProcessing1Source(const Instruction* instr) {
1606 unsigned dst = instr->Rd();
1607 unsigned src = instr->Rn();
1608
1609 switch (instr->Mask(DataProcessing1SourceMask)) {
1610 case RBIT_w: set_wreg(dst, ReverseBits(wreg(src), kWRegSize)); break;
1611 case RBIT_x: set_xreg(dst, ReverseBits(xreg(src), kXRegSize)); break;
1612 case REV16_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse16)); break;
1613 case REV16_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse16)); break;
1614 case REV_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse32)); break;
1615 case REV32_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse32)); break;
1616 case REV_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse64)); break;
1617 case CLZ_w: set_wreg(dst, CountLeadingZeros(wreg(src))); break;
1618 case CLZ_x: set_xreg(dst, CountLeadingZeros(xreg(src))); break;
1619 case CLS_w: {
1620 set_wreg(dst, CountLeadingSignBits(wreg(src)));
1621 break;
1622 }
1623 case CLS_x: {
1624 set_xreg(dst, CountLeadingSignBits(xreg(src)));
1625 break;
1626 }
1627 default: VIXL_UNIMPLEMENTED();
1628 }
1629 }
1630
1631
ReverseBits(uint64_t value,unsigned num_bits)1632 uint64_t Simulator::ReverseBits(uint64_t value, unsigned num_bits) {
1633 VIXL_ASSERT((num_bits == kWRegSize) || (num_bits == kXRegSize) ||
1634 (num_bits == 8) || (num_bits == 16));
1635 uint64_t result = 0;
1636 for (unsigned i = 0; i < num_bits; i++) {
1637 result = (result << 1) | (value & 1);
1638 value >>= 1;
1639 }
1640 return result;
1641 }
1642
1643
ReverseBytes(uint64_t value,ReverseByteMode mode)1644 uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) {
1645 // Split the 64-bit value into an 8-bit array, where b[0] is the least
1646 // significant byte, and b[7] is the most significant.
1647 uint8_t bytes[8];
1648 uint64_t mask = 0xff00000000000000;
1649 for (int i = 7; i >= 0; i--) {
1650 bytes[i] = (value & mask) >> (i * 8);
1651 mask >>= 8;
1652 }
1653
1654 // Permutation tables for REV instructions.
1655 // permute_table[Reverse16] is used by REV16_x, REV16_w
1656 // permute_table[Reverse32] is used by REV32_x, REV_w
1657 // permute_table[Reverse64] is used by REV_x
1658 VIXL_STATIC_ASSERT((Reverse16 == 0) && (Reverse32 == 1) && (Reverse64 == 2));
1659 static const uint8_t permute_table[3][8] = { {6, 7, 4, 5, 2, 3, 0, 1},
1660 {4, 5, 6, 7, 0, 1, 2, 3},
1661 {0, 1, 2, 3, 4, 5, 6, 7} };
1662 uint64_t result = 0;
1663 for (int i = 0; i < 8; i++) {
1664 result <<= 8;
1665 result |= bytes[permute_table[mode][i]];
1666 }
1667 return result;
1668 }
1669
1670
Poly32Mod2(unsigned n,uint64_t data,uint32_t poly)1671 uint32_t Simulator::Poly32Mod2(unsigned n, uint64_t data, uint32_t poly) {
1672 VIXL_ASSERT((n > 32) && (n <= 64));
1673 for (unsigned i = (n - 1); i >= 32; i--) {
1674 if (((data >> i) & 1) != 0) {
1675 uint64_t polysh32 = (uint64_t)poly << (i - 32);
1676 uint64_t mask = (UINT64_C(1) << i) - 1;
1677 data = ((data & mask) ^ polysh32);
1678 }
1679 }
1680 return data & 0xffffffff;
1681 }
1682
1683
1684 template <typename T>
Crc32Checksum(uint32_t acc,T val,uint32_t poly)1685 uint32_t Simulator::Crc32Checksum(uint32_t acc, T val, uint32_t poly) {
1686 unsigned size = sizeof(val) * 8; // number of bits in type T
1687 VIXL_ASSERT((size == 8) || (size == 16) || (size == 32));
1688 uint64_t tempacc = ReverseBits(acc, 32) << size;
1689 uint64_t tempval = ReverseBits(val, size) << 32;
1690 return ReverseBits(Poly32Mod2(32 + size, tempacc ^ tempval, poly), 32);
1691 }
1692
1693
Crc32Checksum(uint32_t acc,uint64_t val,uint32_t poly)1694 uint32_t Simulator::Crc32Checksum(uint32_t acc, uint64_t val, uint32_t poly) {
1695 // Poly32Mod2 cannot handle inputs with more than 32 bits, so compute
1696 // the CRC of each 32-bit word sequentially.
1697 acc = Crc32Checksum(acc, (uint32_t)(val & 0xffffffff), poly);
1698 return Crc32Checksum(acc, (uint32_t)(val >> 32), poly);
1699 }
1700
1701
VisitDataProcessing2Source(const Instruction * instr)1702 void Simulator::VisitDataProcessing2Source(const Instruction* instr) {
1703 Shift shift_op = NO_SHIFT;
1704 int64_t result = 0;
1705 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1706
1707 switch (instr->Mask(DataProcessing2SourceMask)) {
1708 case SDIV_w: {
1709 int32_t rn = wreg(instr->Rn());
1710 int32_t rm = wreg(instr->Rm());
1711 if ((rn == kWMinInt) && (rm == -1)) {
1712 result = kWMinInt;
1713 } else if (rm == 0) {
1714 // Division by zero can be trapped, but not on A-class processors.
1715 result = 0;
1716 } else {
1717 result = rn / rm;
1718 }
1719 break;
1720 }
1721 case SDIV_x: {
1722 int64_t rn = xreg(instr->Rn());
1723 int64_t rm = xreg(instr->Rm());
1724 if ((rn == kXMinInt) && (rm == -1)) {
1725 result = kXMinInt;
1726 } else if (rm == 0) {
1727 // Division by zero can be trapped, but not on A-class processors.
1728 result = 0;
1729 } else {
1730 result = rn / rm;
1731 }
1732 break;
1733 }
1734 case UDIV_w: {
1735 uint32_t rn = static_cast<uint32_t>(wreg(instr->Rn()));
1736 uint32_t rm = static_cast<uint32_t>(wreg(instr->Rm()));
1737 if (rm == 0) {
1738 // Division by zero can be trapped, but not on A-class processors.
1739 result = 0;
1740 } else {
1741 result = rn / rm;
1742 }
1743 break;
1744 }
1745 case UDIV_x: {
1746 uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn()));
1747 uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm()));
1748 if (rm == 0) {
1749 // Division by zero can be trapped, but not on A-class processors.
1750 result = 0;
1751 } else {
1752 result = rn / rm;
1753 }
1754 break;
1755 }
1756 case LSLV_w:
1757 case LSLV_x: shift_op = LSL; break;
1758 case LSRV_w:
1759 case LSRV_x: shift_op = LSR; break;
1760 case ASRV_w:
1761 case ASRV_x: shift_op = ASR; break;
1762 case RORV_w:
1763 case RORV_x: shift_op = ROR; break;
1764 case CRC32B: {
1765 uint32_t acc = reg<uint32_t>(instr->Rn());
1766 uint8_t val = reg<uint8_t>(instr->Rm());
1767 result = Crc32Checksum(acc, val, CRC32_POLY);
1768 break;
1769 }
1770 case CRC32H: {
1771 uint32_t acc = reg<uint32_t>(instr->Rn());
1772 uint16_t val = reg<uint16_t>(instr->Rm());
1773 result = Crc32Checksum(acc, val, CRC32_POLY);
1774 break;
1775 }
1776 case CRC32W: {
1777 uint32_t acc = reg<uint32_t>(instr->Rn());
1778 uint32_t val = reg<uint32_t>(instr->Rm());
1779 result = Crc32Checksum(acc, val, CRC32_POLY);
1780 break;
1781 }
1782 case CRC32X: {
1783 uint32_t acc = reg<uint32_t>(instr->Rn());
1784 uint64_t val = reg<uint64_t>(instr->Rm());
1785 result = Crc32Checksum(acc, val, CRC32_POLY);
1786 reg_size = kWRegSize;
1787 break;
1788 }
1789 case CRC32CB: {
1790 uint32_t acc = reg<uint32_t>(instr->Rn());
1791 uint8_t val = reg<uint8_t>(instr->Rm());
1792 result = Crc32Checksum(acc, val, CRC32C_POLY);
1793 break;
1794 }
1795 case CRC32CH: {
1796 uint32_t acc = reg<uint32_t>(instr->Rn());
1797 uint16_t val = reg<uint16_t>(instr->Rm());
1798 result = Crc32Checksum(acc, val, CRC32C_POLY);
1799 break;
1800 }
1801 case CRC32CW: {
1802 uint32_t acc = reg<uint32_t>(instr->Rn());
1803 uint32_t val = reg<uint32_t>(instr->Rm());
1804 result = Crc32Checksum(acc, val, CRC32C_POLY);
1805 break;
1806 }
1807 case CRC32CX: {
1808 uint32_t acc = reg<uint32_t>(instr->Rn());
1809 uint64_t val = reg<uint64_t>(instr->Rm());
1810 result = Crc32Checksum(acc, val, CRC32C_POLY);
1811 reg_size = kWRegSize;
1812 break;
1813 }
1814 default: VIXL_UNIMPLEMENTED();
1815 }
1816
1817 if (shift_op != NO_SHIFT) {
1818 // Shift distance encoded in the least-significant five/six bits of the
1819 // register.
1820 int mask = (instr->SixtyFourBits() == 1) ? 0x3f : 0x1f;
1821 unsigned shift = wreg(instr->Rm()) & mask;
1822 result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op,
1823 shift);
1824 }
1825 set_reg(reg_size, instr->Rd(), result);
1826 }
1827
1828
1829 // The algorithm used is adapted from the one described in section 8.2 of
1830 // Hacker's Delight, by Henry S. Warren, Jr.
1831 // It assumes that a right shift on a signed integer is an arithmetic shift.
1832 // Type T must be either uint64_t or int64_t.
1833 template <typename T>
MultiplyHigh(T u,T v)1834 static T MultiplyHigh(T u, T v) {
1835 uint64_t u0, v0, w0;
1836 T u1, v1, w1, w2, t;
1837
1838 VIXL_ASSERT(sizeof(u) == sizeof(u0));
1839
1840 u0 = u & 0xffffffff;
1841 u1 = u >> 32;
1842 v0 = v & 0xffffffff;
1843 v1 = v >> 32;
1844
1845 w0 = u0 * v0;
1846 t = u1 * v0 + (w0 >> 32);
1847 w1 = t & 0xffffffff;
1848 w2 = t >> 32;
1849 w1 = u0 * v1 + w1;
1850
1851 return u1 * v1 + w2 + (w1 >> 32);
1852 }
1853
1854
VisitDataProcessing3Source(const Instruction * instr)1855 void Simulator::VisitDataProcessing3Source(const Instruction* instr) {
1856 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1857
1858 int64_t result = 0;
1859 // Extract and sign- or zero-extend 32-bit arguments for widening operations.
1860 uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
1861 uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
1862 int64_t rn_s32 = reg<int32_t>(instr->Rn());
1863 int64_t rm_s32 = reg<int32_t>(instr->Rm());
1864 switch (instr->Mask(DataProcessing3SourceMask)) {
1865 case MADD_w:
1866 case MADD_x:
1867 result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
1868 break;
1869 case MSUB_w:
1870 case MSUB_x:
1871 result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
1872 break;
1873 case SMADDL_x: result = xreg(instr->Ra()) + (rn_s32 * rm_s32); break;
1874 case SMSUBL_x: result = xreg(instr->Ra()) - (rn_s32 * rm_s32); break;
1875 case UMADDL_x: result = xreg(instr->Ra()) + (rn_u32 * rm_u32); break;
1876 case UMSUBL_x: result = xreg(instr->Ra()) - (rn_u32 * rm_u32); break;
1877 case UMULH_x:
1878 result = MultiplyHigh(reg<uint64_t>(instr->Rn()),
1879 reg<uint64_t>(instr->Rm()));
1880 break;
1881 case SMULH_x:
1882 result = MultiplyHigh(xreg(instr->Rn()), xreg(instr->Rm()));
1883 break;
1884 default: VIXL_UNIMPLEMENTED();
1885 }
1886 set_reg(reg_size, instr->Rd(), result);
1887 }
1888
1889
VisitBitfield(const Instruction * instr)1890 void Simulator::VisitBitfield(const Instruction* instr) {
1891 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1892 int64_t reg_mask = instr->SixtyFourBits() ? kXRegMask : kWRegMask;
1893 int64_t R = instr->ImmR();
1894 int64_t S = instr->ImmS();
1895 int64_t diff = S - R;
1896 int64_t mask;
1897 if (diff >= 0) {
1898 mask = (diff < (reg_size - 1)) ? (INT64_C(1) << (diff + 1)) - 1
1899 : reg_mask;
1900 } else {
1901 mask = (INT64_C(1) << (S + 1)) - 1;
1902 mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R));
1903 diff += reg_size;
1904 }
1905
1906 // inzero indicates if the extracted bitfield is inserted into the
1907 // destination register value or in zero.
1908 // If extend is true, extend the sign of the extracted bitfield.
1909 bool inzero = false;
1910 bool extend = false;
1911 switch (instr->Mask(BitfieldMask)) {
1912 case BFM_x:
1913 case BFM_w:
1914 break;
1915 case SBFM_x:
1916 case SBFM_w:
1917 inzero = true;
1918 extend = true;
1919 break;
1920 case UBFM_x:
1921 case UBFM_w:
1922 inzero = true;
1923 break;
1924 default:
1925 VIXL_UNIMPLEMENTED();
1926 }
1927
1928 int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd());
1929 int64_t src = reg(reg_size, instr->Rn());
1930 // Rotate source bitfield into place.
1931 int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R));
1932 // Determine the sign extension.
1933 int64_t topbits = ((INT64_C(1) << (reg_size - diff - 1)) - 1) << (diff + 1);
1934 int64_t signbits = extend && ((src >> S) & 1) ? topbits : 0;
1935
1936 // Merge sign extension, dest/zero and bitfield.
1937 result = signbits | (result & mask) | (dst & ~mask);
1938
1939 set_reg(reg_size, instr->Rd(), result);
1940 }
1941
1942
VisitExtract(const Instruction * instr)1943 void Simulator::VisitExtract(const Instruction* instr) {
1944 unsigned lsb = instr->ImmS();
1945 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
1946 : kWRegSize;
1947 uint64_t low_res = static_cast<uint64_t>(reg(reg_size, instr->Rm())) >> lsb;
1948 uint64_t high_res =
1949 (lsb == 0) ? 0 : reg(reg_size, instr->Rn()) << (reg_size - lsb);
1950 set_reg(reg_size, instr->Rd(), low_res | high_res);
1951 }
1952
1953
VisitFPImmediate(const Instruction * instr)1954 void Simulator::VisitFPImmediate(const Instruction* instr) {
1955 AssertSupportedFPCR();
1956
1957 unsigned dest = instr->Rd();
1958 switch (instr->Mask(FPImmediateMask)) {
1959 case FMOV_s_imm: set_sreg(dest, instr->ImmFP32()); break;
1960 case FMOV_d_imm: set_dreg(dest, instr->ImmFP64()); break;
1961 default: VIXL_UNREACHABLE();
1962 }
1963 }
1964
1965
VisitFPIntegerConvert(const Instruction * instr)1966 void Simulator::VisitFPIntegerConvert(const Instruction* instr) {
1967 AssertSupportedFPCR();
1968
1969 unsigned dst = instr->Rd();
1970 unsigned src = instr->Rn();
1971
1972 FPRounding round = RMode();
1973
1974 switch (instr->Mask(FPIntegerConvertMask)) {
1975 case FCVTAS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieAway)); break;
1976 case FCVTAS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieAway)); break;
1977 case FCVTAS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieAway)); break;
1978 case FCVTAS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieAway)); break;
1979 case FCVTAU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieAway)); break;
1980 case FCVTAU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieAway)); break;
1981 case FCVTAU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieAway)); break;
1982 case FCVTAU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieAway)); break;
1983 case FCVTMS_ws:
1984 set_wreg(dst, FPToInt32(sreg(src), FPNegativeInfinity));
1985 break;
1986 case FCVTMS_xs:
1987 set_xreg(dst, FPToInt64(sreg(src), FPNegativeInfinity));
1988 break;
1989 case FCVTMS_wd:
1990 set_wreg(dst, FPToInt32(dreg(src), FPNegativeInfinity));
1991 break;
1992 case FCVTMS_xd:
1993 set_xreg(dst, FPToInt64(dreg(src), FPNegativeInfinity));
1994 break;
1995 case FCVTMU_ws:
1996 set_wreg(dst, FPToUInt32(sreg(src), FPNegativeInfinity));
1997 break;
1998 case FCVTMU_xs:
1999 set_xreg(dst, FPToUInt64(sreg(src), FPNegativeInfinity));
2000 break;
2001 case FCVTMU_wd:
2002 set_wreg(dst, FPToUInt32(dreg(src), FPNegativeInfinity));
2003 break;
2004 case FCVTMU_xd:
2005 set_xreg(dst, FPToUInt64(dreg(src), FPNegativeInfinity));
2006 break;
2007 case FCVTPS_ws:
2008 set_wreg(dst, FPToInt32(sreg(src), FPPositiveInfinity));
2009 break;
2010 case FCVTPS_xs:
2011 set_xreg(dst, FPToInt64(sreg(src), FPPositiveInfinity));
2012 break;
2013 case FCVTPS_wd:
2014 set_wreg(dst, FPToInt32(dreg(src), FPPositiveInfinity));
2015 break;
2016 case FCVTPS_xd:
2017 set_xreg(dst, FPToInt64(dreg(src), FPPositiveInfinity));
2018 break;
2019 case FCVTPU_ws:
2020 set_wreg(dst, FPToUInt32(sreg(src), FPPositiveInfinity));
2021 break;
2022 case FCVTPU_xs:
2023 set_xreg(dst, FPToUInt64(sreg(src), FPPositiveInfinity));
2024 break;
2025 case FCVTPU_wd:
2026 set_wreg(dst, FPToUInt32(dreg(src), FPPositiveInfinity));
2027 break;
2028 case FCVTPU_xd:
2029 set_xreg(dst, FPToUInt64(dreg(src), FPPositiveInfinity));
2030 break;
2031 case FCVTNS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieEven)); break;
2032 case FCVTNS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieEven)); break;
2033 case FCVTNS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieEven)); break;
2034 case FCVTNS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieEven)); break;
2035 case FCVTNU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieEven)); break;
2036 case FCVTNU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieEven)); break;
2037 case FCVTNU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieEven)); break;
2038 case FCVTNU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieEven)); break;
2039 case FCVTZS_ws: set_wreg(dst, FPToInt32(sreg(src), FPZero)); break;
2040 case FCVTZS_xs: set_xreg(dst, FPToInt64(sreg(src), FPZero)); break;
2041 case FCVTZS_wd: set_wreg(dst, FPToInt32(dreg(src), FPZero)); break;
2042 case FCVTZS_xd: set_xreg(dst, FPToInt64(dreg(src), FPZero)); break;
2043 case FCVTZU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPZero)); break;
2044 case FCVTZU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPZero)); break;
2045 case FCVTZU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPZero)); break;
2046 case FCVTZU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPZero)); break;
2047 case FMOV_ws: set_wreg(dst, sreg_bits(src)); break;
2048 case FMOV_xd: set_xreg(dst, dreg_bits(src)); break;
2049 case FMOV_sw: set_sreg_bits(dst, wreg(src)); break;
2050 case FMOV_dx: set_dreg_bits(dst, xreg(src)); break;
2051 case FMOV_d1_x:
2052 LogicVRegister(vreg(dst)).SetUint(kFormatD, 1, xreg(src));
2053 break;
2054 case FMOV_x_d1:
2055 set_xreg(dst, LogicVRegister(vreg(src)).Uint(kFormatD, 1));
2056 break;
2057
2058 // A 32-bit input can be handled in the same way as a 64-bit input, since
2059 // the sign- or zero-extension will not affect the conversion.
2060 case SCVTF_dx: set_dreg(dst, FixedToDouble(xreg(src), 0, round)); break;
2061 case SCVTF_dw: set_dreg(dst, FixedToDouble(wreg(src), 0, round)); break;
2062 case UCVTF_dx: set_dreg(dst, UFixedToDouble(xreg(src), 0, round)); break;
2063 case UCVTF_dw: {
2064 set_dreg(dst, UFixedToDouble(static_cast<uint32_t>(wreg(src)), 0, round));
2065 break;
2066 }
2067 case SCVTF_sx: set_sreg(dst, FixedToFloat(xreg(src), 0, round)); break;
2068 case SCVTF_sw: set_sreg(dst, FixedToFloat(wreg(src), 0, round)); break;
2069 case UCVTF_sx: set_sreg(dst, UFixedToFloat(xreg(src), 0, round)); break;
2070 case UCVTF_sw: {
2071 set_sreg(dst, UFixedToFloat(static_cast<uint32_t>(wreg(src)), 0, round));
2072 break;
2073 }
2074
2075 default: VIXL_UNREACHABLE();
2076 }
2077 }
2078
2079
VisitFPFixedPointConvert(const Instruction * instr)2080 void Simulator::VisitFPFixedPointConvert(const Instruction* instr) {
2081 AssertSupportedFPCR();
2082
2083 unsigned dst = instr->Rd();
2084 unsigned src = instr->Rn();
2085 int fbits = 64 - instr->FPScale();
2086
2087 FPRounding round = RMode();
2088
2089 switch (instr->Mask(FPFixedPointConvertMask)) {
2090 // A 32-bit input can be handled in the same way as a 64-bit input, since
2091 // the sign- or zero-extension will not affect the conversion.
2092 case SCVTF_dx_fixed:
2093 set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
2094 break;
2095 case SCVTF_dw_fixed:
2096 set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
2097 break;
2098 case UCVTF_dx_fixed:
2099 set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
2100 break;
2101 case UCVTF_dw_fixed: {
2102 set_dreg(dst,
2103 UFixedToDouble(static_cast<uint32_t>(wreg(src)), fbits, round));
2104 break;
2105 }
2106 case SCVTF_sx_fixed:
2107 set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
2108 break;
2109 case SCVTF_sw_fixed:
2110 set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
2111 break;
2112 case UCVTF_sx_fixed:
2113 set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
2114 break;
2115 case UCVTF_sw_fixed: {
2116 set_sreg(dst,
2117 UFixedToFloat(static_cast<uint32_t>(wreg(src)), fbits, round));
2118 break;
2119 }
2120 case FCVTZS_xd_fixed:
2121 set_xreg(dst, FPToInt64(dreg(src) * std::pow(2.0, fbits), FPZero));
2122 break;
2123 case FCVTZS_wd_fixed:
2124 set_wreg(dst, FPToInt32(dreg(src) * std::pow(2.0, fbits), FPZero));
2125 break;
2126 case FCVTZU_xd_fixed:
2127 set_xreg(dst, FPToUInt64(dreg(src) * std::pow(2.0, fbits), FPZero));
2128 break;
2129 case FCVTZU_wd_fixed:
2130 set_wreg(dst, FPToUInt32(dreg(src) * std::pow(2.0, fbits), FPZero));
2131 break;
2132 case FCVTZS_xs_fixed:
2133 set_xreg(dst, FPToInt64(sreg(src) * std::pow(2.0f, fbits), FPZero));
2134 break;
2135 case FCVTZS_ws_fixed:
2136 set_wreg(dst, FPToInt32(sreg(src) * std::pow(2.0f, fbits), FPZero));
2137 break;
2138 case FCVTZU_xs_fixed:
2139 set_xreg(dst, FPToUInt64(sreg(src) * std::pow(2.0f, fbits), FPZero));
2140 break;
2141 case FCVTZU_ws_fixed:
2142 set_wreg(dst, FPToUInt32(sreg(src) * std::pow(2.0f, fbits), FPZero));
2143 break;
2144 default: VIXL_UNREACHABLE();
2145 }
2146 }
2147
2148
VisitFPCompare(const Instruction * instr)2149 void Simulator::VisitFPCompare(const Instruction* instr) {
2150 AssertSupportedFPCR();
2151
2152 FPTrapFlags trap = DisableTrap;
2153 switch (instr->Mask(FPCompareMask)) {
2154 case FCMPE_s: trap = EnableTrap; VIXL_FALLTHROUGH();
2155 case FCMP_s: FPCompare(sreg(instr->Rn()), sreg(instr->Rm()), trap); break;
2156 case FCMPE_d: trap = EnableTrap; VIXL_FALLTHROUGH();
2157 case FCMP_d: FPCompare(dreg(instr->Rn()), dreg(instr->Rm()), trap); break;
2158 case FCMPE_s_zero: trap = EnableTrap; VIXL_FALLTHROUGH();
2159 case FCMP_s_zero: FPCompare(sreg(instr->Rn()), 0.0f, trap); break;
2160 case FCMPE_d_zero: trap = EnableTrap; VIXL_FALLTHROUGH();
2161 case FCMP_d_zero: FPCompare(dreg(instr->Rn()), 0.0, trap); break;
2162 default: VIXL_UNIMPLEMENTED();
2163 }
2164 }
2165
2166
VisitFPConditionalCompare(const Instruction * instr)2167 void Simulator::VisitFPConditionalCompare(const Instruction* instr) {
2168 AssertSupportedFPCR();
2169
2170 FPTrapFlags trap = DisableTrap;
2171 switch (instr->Mask(FPConditionalCompareMask)) {
2172 case FCCMPE_s: trap = EnableTrap;
2173 VIXL_FALLTHROUGH();
2174 case FCCMP_s:
2175 if (ConditionPassed(instr->Condition())) {
2176 FPCompare(sreg(instr->Rn()), sreg(instr->Rm()), trap);
2177 } else {
2178 nzcv().SetFlags(instr->Nzcv());
2179 LogSystemRegister(NZCV);
2180 }
2181 break;
2182 case FCCMPE_d: trap = EnableTrap;
2183 VIXL_FALLTHROUGH();
2184 case FCCMP_d:
2185 if (ConditionPassed(instr->Condition())) {
2186 FPCompare(dreg(instr->Rn()), dreg(instr->Rm()), trap);
2187 } else {
2188 nzcv().SetFlags(instr->Nzcv());
2189 LogSystemRegister(NZCV);
2190 }
2191 break;
2192 default: VIXL_UNIMPLEMENTED();
2193 }
2194 }
2195
2196
VisitFPConditionalSelect(const Instruction * instr)2197 void Simulator::VisitFPConditionalSelect(const Instruction* instr) {
2198 AssertSupportedFPCR();
2199
2200 Instr selected;
2201 if (ConditionPassed(instr->Condition())) {
2202 selected = instr->Rn();
2203 } else {
2204 selected = instr->Rm();
2205 }
2206
2207 switch (instr->Mask(FPConditionalSelectMask)) {
2208 case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break;
2209 case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break;
2210 default: VIXL_UNIMPLEMENTED();
2211 }
2212 }
2213
2214
VisitFPDataProcessing1Source(const Instruction * instr)2215 void Simulator::VisitFPDataProcessing1Source(const Instruction* instr) {
2216 AssertSupportedFPCR();
2217
2218 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
2219 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
2220 SimVRegister& rd = vreg(instr->Rd());
2221 SimVRegister& rn = vreg(instr->Rn());
2222 bool inexact_exception = false;
2223
2224 unsigned fd = instr->Rd();
2225 unsigned fn = instr->Rn();
2226
2227 switch (instr->Mask(FPDataProcessing1SourceMask)) {
2228 case FMOV_s: set_sreg(fd, sreg(fn)); return;
2229 case FMOV_d: set_dreg(fd, dreg(fn)); return;
2230 case FABS_s: fabs_(kFormatS, vreg(fd), vreg(fn)); return;
2231 case FABS_d: fabs_(kFormatD, vreg(fd), vreg(fn)); return;
2232 case FNEG_s: fneg(kFormatS, vreg(fd), vreg(fn)); return;
2233 case FNEG_d: fneg(kFormatD, vreg(fd), vreg(fn)); return;
2234 case FCVT_ds: set_dreg(fd, FPToDouble(sreg(fn))); return;
2235 case FCVT_sd: set_sreg(fd, FPToFloat(dreg(fn), FPTieEven)); return;
2236 case FCVT_hs: set_hreg(fd, FPToFloat16(sreg(fn), FPTieEven)); return;
2237 case FCVT_sh: set_sreg(fd, FPToFloat(hreg(fn))); return;
2238 case FCVT_dh: set_dreg(fd, FPToDouble(FPToFloat(hreg(fn)))); return;
2239 case FCVT_hd: set_hreg(fd, FPToFloat16(dreg(fn), FPTieEven)); return;
2240 case FSQRT_s:
2241 case FSQRT_d: fsqrt(vform, rd, rn); return;
2242 case FRINTI_s:
2243 case FRINTI_d: break; // Use FPCR rounding mode.
2244 case FRINTX_s:
2245 case FRINTX_d: inexact_exception = true; break;
2246 case FRINTA_s:
2247 case FRINTA_d: fpcr_rounding = FPTieAway; break;
2248 case FRINTM_s:
2249 case FRINTM_d: fpcr_rounding = FPNegativeInfinity; break;
2250 case FRINTN_s:
2251 case FRINTN_d: fpcr_rounding = FPTieEven; break;
2252 case FRINTP_s:
2253 case FRINTP_d: fpcr_rounding = FPPositiveInfinity; break;
2254 case FRINTZ_s:
2255 case FRINTZ_d: fpcr_rounding = FPZero; break;
2256 default: VIXL_UNIMPLEMENTED();
2257 }
2258
2259 // Only FRINT* instructions fall through the switch above.
2260 frint(vform, rd, rn, fpcr_rounding, inexact_exception);
2261 }
2262
2263
VisitFPDataProcessing2Source(const Instruction * instr)2264 void Simulator::VisitFPDataProcessing2Source(const Instruction* instr) {
2265 AssertSupportedFPCR();
2266
2267 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
2268 SimVRegister& rd = vreg(instr->Rd());
2269 SimVRegister& rn = vreg(instr->Rn());
2270 SimVRegister& rm = vreg(instr->Rm());
2271
2272 switch (instr->Mask(FPDataProcessing2SourceMask)) {
2273 case FADD_s:
2274 case FADD_d: fadd(vform, rd, rn, rm); break;
2275 case FSUB_s:
2276 case FSUB_d: fsub(vform, rd, rn, rm); break;
2277 case FMUL_s:
2278 case FMUL_d: fmul(vform, rd, rn, rm); break;
2279 case FNMUL_s:
2280 case FNMUL_d: fnmul(vform, rd, rn, rm); break;
2281 case FDIV_s:
2282 case FDIV_d: fdiv(vform, rd, rn, rm); break;
2283 case FMAX_s:
2284 case FMAX_d: fmax(vform, rd, rn, rm); break;
2285 case FMIN_s:
2286 case FMIN_d: fmin(vform, rd, rn, rm); break;
2287 case FMAXNM_s:
2288 case FMAXNM_d: fmaxnm(vform, rd, rn, rm); break;
2289 case FMINNM_s:
2290 case FMINNM_d: fminnm(vform, rd, rn, rm); break;
2291 default:
2292 VIXL_UNREACHABLE();
2293 }
2294 }
2295
2296
VisitFPDataProcessing3Source(const Instruction * instr)2297 void Simulator::VisitFPDataProcessing3Source(const Instruction* instr) {
2298 AssertSupportedFPCR();
2299
2300 unsigned fd = instr->Rd();
2301 unsigned fn = instr->Rn();
2302 unsigned fm = instr->Rm();
2303 unsigned fa = instr->Ra();
2304
2305 switch (instr->Mask(FPDataProcessing3SourceMask)) {
2306 // fd = fa +/- (fn * fm)
2307 case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); break;
2308 case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); break;
2309 case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); break;
2310 case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); break;
2311 // Negated variants of the above.
2312 case FNMADD_s:
2313 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
2314 break;
2315 case FNMSUB_s:
2316 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
2317 break;
2318 case FNMADD_d:
2319 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
2320 break;
2321 case FNMSUB_d:
2322 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
2323 break;
2324 default: VIXL_UNIMPLEMENTED();
2325 }
2326 }
2327
2328
FPProcessNaNs(const Instruction * instr)2329 bool Simulator::FPProcessNaNs(const Instruction* instr) {
2330 unsigned fd = instr->Rd();
2331 unsigned fn = instr->Rn();
2332 unsigned fm = instr->Rm();
2333 bool done = false;
2334
2335 if (instr->Mask(FP64) == FP64) {
2336 double result = FPProcessNaNs(dreg(fn), dreg(fm));
2337 if (std::isnan(result)) {
2338 set_dreg(fd, result);
2339 done = true;
2340 }
2341 } else {
2342 float result = FPProcessNaNs(sreg(fn), sreg(fm));
2343 if (std::isnan(result)) {
2344 set_sreg(fd, result);
2345 done = true;
2346 }
2347 }
2348
2349 return done;
2350 }
2351
2352
SysOp_W(int op,int64_t val)2353 void Simulator::SysOp_W(int op, int64_t val) {
2354 switch (op) {
2355 case IVAU:
2356 case CVAC:
2357 case CVAU:
2358 case CIVAC: {
2359 // Perform a dummy memory access to ensure that we have read access
2360 // to the specified address.
2361 volatile uint8_t y = Memory::Read<uint8_t>(val);
2362 USE(y);
2363 // TODO: Implement "case ZVA:".
2364 break;
2365 }
2366 default:
2367 VIXL_UNIMPLEMENTED();
2368 }
2369 }
2370
2371
VisitSystem(const Instruction * instr)2372 void Simulator::VisitSystem(const Instruction* instr) {
2373 // Some system instructions hijack their Op and Cp fields to represent a
2374 // range of immediates instead of indicating a different instruction. This
2375 // makes the decoding tricky.
2376 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
2377 VIXL_ASSERT(instr->Mask(SystemExclusiveMonitorMask) == CLREX);
2378 switch (instr->Mask(SystemExclusiveMonitorMask)) {
2379 case CLREX: {
2380 PrintExclusiveAccessWarning();
2381 ClearLocalMonitor();
2382 break;
2383 }
2384 }
2385 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
2386 switch (instr->Mask(SystemSysRegMask)) {
2387 case MRS: {
2388 switch (instr->ImmSystemRegister()) {
2389 case NZCV: set_xreg(instr->Rt(), nzcv().RawValue()); break;
2390 case FPCR: set_xreg(instr->Rt(), fpcr().RawValue()); break;
2391 default: VIXL_UNIMPLEMENTED();
2392 }
2393 break;
2394 }
2395 case MSR: {
2396 switch (instr->ImmSystemRegister()) {
2397 case NZCV:
2398 nzcv().SetRawValue(xreg(instr->Rt()));
2399 LogSystemRegister(NZCV);
2400 break;
2401 case FPCR:
2402 fpcr().SetRawValue(xreg(instr->Rt()));
2403 LogSystemRegister(FPCR);
2404 break;
2405 default: VIXL_UNIMPLEMENTED();
2406 }
2407 break;
2408 }
2409 }
2410 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
2411 VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
2412 switch (instr->ImmHint()) {
2413 case NOP: break;
2414 default: VIXL_UNIMPLEMENTED();
2415 }
2416 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
2417 __sync_synchronize();
2418 } else if ((instr->Mask(SystemSysFMask) == SystemSysFixed)) {
2419 switch (instr->Mask(SystemSysMask)) {
2420 case SYS: SysOp_W(instr->SysOp(), xreg(instr->Rt())); break;
2421 default: VIXL_UNIMPLEMENTED();
2422 }
2423 } else {
2424 VIXL_UNIMPLEMENTED();
2425 }
2426 }
2427
2428
VisitException(const Instruction * instr)2429 void Simulator::VisitException(const Instruction* instr) {
2430 switch (instr->Mask(ExceptionMask)) {
2431 case HLT:
2432 switch (instr->ImmException()) {
2433 case kUnreachableOpcode:
2434 DoUnreachable(instr);
2435 return;
2436 case kTraceOpcode:
2437 DoTrace(instr);
2438 return;
2439 case kLogOpcode:
2440 DoLog(instr);
2441 return;
2442 case kPrintfOpcode:
2443 DoPrintf(instr);
2444 return;
2445 default:
2446 HostBreakpoint();
2447 return;
2448 }
2449 case BRK:
2450 HostBreakpoint();
2451 return;
2452 default:
2453 VIXL_UNIMPLEMENTED();
2454 }
2455 }
2456
2457
VisitCrypto2RegSHA(const Instruction * instr)2458 void Simulator::VisitCrypto2RegSHA(const Instruction* instr) {
2459 VisitUnimplemented(instr);
2460 }
2461
2462
VisitCrypto3RegSHA(const Instruction * instr)2463 void Simulator::VisitCrypto3RegSHA(const Instruction* instr) {
2464 VisitUnimplemented(instr);
2465 }
2466
2467
VisitCryptoAES(const Instruction * instr)2468 void Simulator::VisitCryptoAES(const Instruction* instr) {
2469 VisitUnimplemented(instr);
2470 }
2471
2472
VisitNEON2RegMisc(const Instruction * instr)2473 void Simulator::VisitNEON2RegMisc(const Instruction* instr) {
2474 NEONFormatDecoder nfd(instr);
2475 VectorFormat vf = nfd.GetVectorFormat();
2476
2477 static const NEONFormatMap map_lp = {
2478 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
2479 };
2480 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);
2481
2482 static const NEONFormatMap map_fcvtl = {
2483 {22}, {NF_4S, NF_2D}
2484 };
2485 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);
2486
2487 static const NEONFormatMap map_fcvtn = {
2488 {22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S}
2489 };
2490 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);
2491
2492 SimVRegister& rd = vreg(instr->Rd());
2493 SimVRegister& rn = vreg(instr->Rn());
2494
2495 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
2496 // These instructions all use a two bit size field, except NOT and RBIT,
2497 // which use the field to encode the operation.
2498 switch (instr->Mask(NEON2RegMiscMask)) {
2499 case NEON_REV64: rev64(vf, rd, rn); break;
2500 case NEON_REV32: rev32(vf, rd, rn); break;
2501 case NEON_REV16: rev16(vf, rd, rn); break;
2502 case NEON_SUQADD: suqadd(vf, rd, rn); break;
2503 case NEON_USQADD: usqadd(vf, rd, rn); break;
2504 case NEON_CLS: cls(vf, rd, rn); break;
2505 case NEON_CLZ: clz(vf, rd, rn); break;
2506 case NEON_CNT: cnt(vf, rd, rn); break;
2507 case NEON_SQABS: abs(vf, rd, rn).SignedSaturate(vf); break;
2508 case NEON_SQNEG: neg(vf, rd, rn).SignedSaturate(vf); break;
2509 case NEON_CMGT_zero: cmp(vf, rd, rn, 0, gt); break;
2510 case NEON_CMGE_zero: cmp(vf, rd, rn, 0, ge); break;
2511 case NEON_CMEQ_zero: cmp(vf, rd, rn, 0, eq); break;
2512 case NEON_CMLE_zero: cmp(vf, rd, rn, 0, le); break;
2513 case NEON_CMLT_zero: cmp(vf, rd, rn, 0, lt); break;
2514 case NEON_ABS: abs(vf, rd, rn); break;
2515 case NEON_NEG: neg(vf, rd, rn); break;
2516 case NEON_SADDLP: saddlp(vf_lp, rd, rn); break;
2517 case NEON_UADDLP: uaddlp(vf_lp, rd, rn); break;
2518 case NEON_SADALP: sadalp(vf_lp, rd, rn); break;
2519 case NEON_UADALP: uadalp(vf_lp, rd, rn); break;
2520 case NEON_RBIT_NOT:
2521 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
2522 switch (instr->FPType()) {
2523 case 0: not_(vf, rd, rn); break;
2524 case 1: rbit(vf, rd, rn);; break;
2525 default:
2526 VIXL_UNIMPLEMENTED();
2527 }
2528 break;
2529 }
2530 } else {
2531 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
2532 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
2533 bool inexact_exception = false;
2534
2535 // These instructions all use a one bit size field, except XTN, SQXTUN,
2536 // SHLL, SQXTN and UQXTN, which use a two bit size field.
2537 switch (instr->Mask(NEON2RegMiscFPMask)) {
2538 case NEON_FABS: fabs_(fpf, rd, rn); return;
2539 case NEON_FNEG: fneg(fpf, rd, rn); return;
2540 case NEON_FSQRT: fsqrt(fpf, rd, rn); return;
2541 case NEON_FCVTL:
2542 if (instr->Mask(NEON_Q)) {
2543 fcvtl2(vf_fcvtl, rd, rn);
2544 } else {
2545 fcvtl(vf_fcvtl, rd, rn);
2546 }
2547 return;
2548 case NEON_FCVTN:
2549 if (instr->Mask(NEON_Q)) {
2550 fcvtn2(vf_fcvtn, rd, rn);
2551 } else {
2552 fcvtn(vf_fcvtn, rd, rn);
2553 }
2554 return;
2555 case NEON_FCVTXN:
2556 if (instr->Mask(NEON_Q)) {
2557 fcvtxn2(vf_fcvtn, rd, rn);
2558 } else {
2559 fcvtxn(vf_fcvtn, rd, rn);
2560 }
2561 return;
2562
2563 // The following instructions break from the switch statement, rather
2564 // than return.
2565 case NEON_FRINTI: break; // Use FPCR rounding mode.
2566 case NEON_FRINTX: inexact_exception = true; break;
2567 case NEON_FRINTA: fpcr_rounding = FPTieAway; break;
2568 case NEON_FRINTM: fpcr_rounding = FPNegativeInfinity; break;
2569 case NEON_FRINTN: fpcr_rounding = FPTieEven; break;
2570 case NEON_FRINTP: fpcr_rounding = FPPositiveInfinity; break;
2571 case NEON_FRINTZ: fpcr_rounding = FPZero; break;
2572
2573 case NEON_FCVTNS: fcvts(fpf, rd, rn, FPTieEven); return;
2574 case NEON_FCVTNU: fcvtu(fpf, rd, rn, FPTieEven); return;
2575 case NEON_FCVTPS: fcvts(fpf, rd, rn, FPPositiveInfinity); return;
2576 case NEON_FCVTPU: fcvtu(fpf, rd, rn, FPPositiveInfinity); return;
2577 case NEON_FCVTMS: fcvts(fpf, rd, rn, FPNegativeInfinity); return;
2578 case NEON_FCVTMU: fcvtu(fpf, rd, rn, FPNegativeInfinity); return;
2579 case NEON_FCVTZS: fcvts(fpf, rd, rn, FPZero); return;
2580 case NEON_FCVTZU: fcvtu(fpf, rd, rn, FPZero); return;
2581 case NEON_FCVTAS: fcvts(fpf, rd, rn, FPTieAway); return;
2582 case NEON_FCVTAU: fcvtu(fpf, rd, rn, FPTieAway); return;
2583 case NEON_SCVTF: scvtf(fpf, rd, rn, 0, fpcr_rounding); return;
2584 case NEON_UCVTF: ucvtf(fpf, rd, rn, 0, fpcr_rounding); return;
2585 case NEON_URSQRTE: ursqrte(fpf, rd, rn); return;
2586 case NEON_URECPE: urecpe(fpf, rd, rn); return;
2587 case NEON_FRSQRTE: frsqrte(fpf, rd, rn); return;
2588 case NEON_FRECPE: frecpe(fpf, rd, rn, fpcr_rounding); return;
2589 case NEON_FCMGT_zero: fcmp_zero(fpf, rd, rn, gt); return;
2590 case NEON_FCMGE_zero: fcmp_zero(fpf, rd, rn, ge); return;
2591 case NEON_FCMEQ_zero: fcmp_zero(fpf, rd, rn, eq); return;
2592 case NEON_FCMLE_zero: fcmp_zero(fpf, rd, rn, le); return;
2593 case NEON_FCMLT_zero: fcmp_zero(fpf, rd, rn, lt); return;
2594 default:
2595 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
2596 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
2597 switch (instr->Mask(NEON2RegMiscMask)) {
2598 case NEON_XTN: xtn(vf, rd, rn); return;
2599 case NEON_SQXTN: sqxtn(vf, rd, rn); return;
2600 case NEON_UQXTN: uqxtn(vf, rd, rn); return;
2601 case NEON_SQXTUN: sqxtun(vf, rd, rn); return;
2602 case NEON_SHLL:
2603 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2604 if (instr->Mask(NEON_Q)) {
2605 shll2(vf, rd, rn);
2606 } else {
2607 shll(vf, rd, rn);
2608 }
2609 return;
2610 default:
2611 VIXL_UNIMPLEMENTED();
2612 }
2613 } else {
2614 VIXL_UNIMPLEMENTED();
2615 }
2616 }
2617
2618 // Only FRINT* instructions fall through the switch above.
2619 frint(fpf, rd, rn, fpcr_rounding, inexact_exception);
2620 }
2621 }
2622
2623
VisitNEON3Same(const Instruction * instr)2624 void Simulator::VisitNEON3Same(const Instruction* instr) {
2625 NEONFormatDecoder nfd(instr);
2626 SimVRegister& rd = vreg(instr->Rd());
2627 SimVRegister& rn = vreg(instr->Rn());
2628 SimVRegister& rm = vreg(instr->Rm());
2629
2630 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
2631 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
2632 switch (instr->Mask(NEON3SameLogicalMask)) {
2633 case NEON_AND: and_(vf, rd, rn, rm); break;
2634 case NEON_ORR: orr(vf, rd, rn, rm); break;
2635 case NEON_ORN: orn(vf, rd, rn, rm); break;
2636 case NEON_EOR: eor(vf, rd, rn, rm); break;
2637 case NEON_BIC: bic(vf, rd, rn, rm); break;
2638 case NEON_BIF: bif(vf, rd, rn, rm); break;
2639 case NEON_BIT: bit(vf, rd, rn, rm); break;
2640 case NEON_BSL: bsl(vf, rd, rn, rm); break;
2641 default:
2642 VIXL_UNIMPLEMENTED();
2643 }
2644 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
2645 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2646 switch (instr->Mask(NEON3SameFPMask)) {
2647 case NEON_FADD: fadd(vf, rd, rn, rm); break;
2648 case NEON_FSUB: fsub(vf, rd, rn, rm); break;
2649 case NEON_FMUL: fmul(vf, rd, rn, rm); break;
2650 case NEON_FDIV: fdiv(vf, rd, rn, rm); break;
2651 case NEON_FMAX: fmax(vf, rd, rn, rm); break;
2652 case NEON_FMIN: fmin(vf, rd, rn, rm); break;
2653 case NEON_FMAXNM: fmaxnm(vf, rd, rn, rm); break;
2654 case NEON_FMINNM: fminnm(vf, rd, rn, rm); break;
2655 case NEON_FMLA: fmla(vf, rd, rn, rm); break;
2656 case NEON_FMLS: fmls(vf, rd, rn, rm); break;
2657 case NEON_FMULX: fmulx(vf, rd, rn, rm); break;
2658 case NEON_FACGE: fabscmp(vf, rd, rn, rm, ge); break;
2659 case NEON_FACGT: fabscmp(vf, rd, rn, rm, gt); break;
2660 case NEON_FCMEQ: fcmp(vf, rd, rn, rm, eq); break;
2661 case NEON_FCMGE: fcmp(vf, rd, rn, rm, ge); break;
2662 case NEON_FCMGT: fcmp(vf, rd, rn, rm, gt); break;
2663 case NEON_FRECPS: frecps(vf, rd, rn, rm); break;
2664 case NEON_FRSQRTS: frsqrts(vf, rd, rn, rm); break;
2665 case NEON_FABD: fabd(vf, rd, rn, rm); break;
2666 case NEON_FADDP: faddp(vf, rd, rn, rm); break;
2667 case NEON_FMAXP: fmaxp(vf, rd, rn, rm); break;
2668 case NEON_FMAXNMP: fmaxnmp(vf, rd, rn, rm); break;
2669 case NEON_FMINP: fminp(vf, rd, rn, rm); break;
2670 case NEON_FMINNMP: fminnmp(vf, rd, rn, rm); break;
2671 default:
2672 VIXL_UNIMPLEMENTED();
2673 }
2674 } else {
2675 VectorFormat vf = nfd.GetVectorFormat();
2676 switch (instr->Mask(NEON3SameMask)) {
2677 case NEON_ADD: add(vf, rd, rn, rm); break;
2678 case NEON_ADDP: addp(vf, rd, rn, rm); break;
2679 case NEON_CMEQ: cmp(vf, rd, rn, rm, eq); break;
2680 case NEON_CMGE: cmp(vf, rd, rn, rm, ge); break;
2681 case NEON_CMGT: cmp(vf, rd, rn, rm, gt); break;
2682 case NEON_CMHI: cmp(vf, rd, rn, rm, hi); break;
2683 case NEON_CMHS: cmp(vf, rd, rn, rm, hs); break;
2684 case NEON_CMTST: cmptst(vf, rd, rn, rm); break;
2685 case NEON_MLS: mls(vf, rd, rn, rm); break;
2686 case NEON_MLA: mla(vf, rd, rn, rm); break;
2687 case NEON_MUL: mul(vf, rd, rn, rm); break;
2688 case NEON_PMUL: pmul(vf, rd, rn, rm); break;
2689 case NEON_SMAX: smax(vf, rd, rn, rm); break;
2690 case NEON_SMAXP: smaxp(vf, rd, rn, rm); break;
2691 case NEON_SMIN: smin(vf, rd, rn, rm); break;
2692 case NEON_SMINP: sminp(vf, rd, rn, rm); break;
2693 case NEON_SUB: sub(vf, rd, rn, rm); break;
2694 case NEON_UMAX: umax(vf, rd, rn, rm); break;
2695 case NEON_UMAXP: umaxp(vf, rd, rn, rm); break;
2696 case NEON_UMIN: umin(vf, rd, rn, rm); break;
2697 case NEON_UMINP: uminp(vf, rd, rn, rm); break;
2698 case NEON_SSHL: sshl(vf, rd, rn, rm); break;
2699 case NEON_USHL: ushl(vf, rd, rn, rm); break;
2700 case NEON_SABD: absdiff(vf, rd, rn, rm, true); break;
2701 case NEON_UABD: absdiff(vf, rd, rn, rm, false); break;
2702 case NEON_SABA: saba(vf, rd, rn, rm); break;
2703 case NEON_UABA: uaba(vf, rd, rn, rm); break;
2704 case NEON_UQADD: add(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2705 case NEON_SQADD: add(vf, rd, rn, rm).SignedSaturate(vf); break;
2706 case NEON_UQSUB: sub(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2707 case NEON_SQSUB: sub(vf, rd, rn, rm).SignedSaturate(vf); break;
2708 case NEON_SQDMULH: sqdmulh(vf, rd, rn, rm); break;
2709 case NEON_SQRDMULH: sqrdmulh(vf, rd, rn, rm); break;
2710 case NEON_UQSHL: ushl(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2711 case NEON_SQSHL: sshl(vf, rd, rn, rm).SignedSaturate(vf); break;
2712 case NEON_URSHL: ushl(vf, rd, rn, rm).Round(vf); break;
2713 case NEON_SRSHL: sshl(vf, rd, rn, rm).Round(vf); break;
2714 case NEON_UQRSHL:
2715 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
2716 break;
2717 case NEON_SQRSHL:
2718 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
2719 break;
2720 case NEON_UHADD:
2721 add(vf, rd, rn, rm).Uhalve(vf);
2722 break;
2723 case NEON_URHADD:
2724 add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
2725 break;
2726 case NEON_SHADD:
2727 add(vf, rd, rn, rm).Halve(vf);
2728 break;
2729 case NEON_SRHADD:
2730 add(vf, rd, rn, rm).Halve(vf).Round(vf);
2731 break;
2732 case NEON_UHSUB:
2733 sub(vf, rd, rn, rm).Uhalve(vf);
2734 break;
2735 case NEON_SHSUB:
2736 sub(vf, rd, rn, rm).Halve(vf);
2737 break;
2738 default:
2739 VIXL_UNIMPLEMENTED();
2740 }
2741 }
2742 }
2743
2744
VisitNEON3Different(const Instruction * instr)2745 void Simulator::VisitNEON3Different(const Instruction* instr) {
2746 NEONFormatDecoder nfd(instr);
2747 VectorFormat vf = nfd.GetVectorFormat();
2748 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2749
2750 SimVRegister& rd = vreg(instr->Rd());
2751 SimVRegister& rn = vreg(instr->Rn());
2752 SimVRegister& rm = vreg(instr->Rm());
2753
2754 switch (instr->Mask(NEON3DifferentMask)) {
2755 case NEON_PMULL: pmull(vf_l, rd, rn, rm); break;
2756 case NEON_PMULL2: pmull2(vf_l, rd, rn, rm); break;
2757 case NEON_UADDL: uaddl(vf_l, rd, rn, rm); break;
2758 case NEON_UADDL2: uaddl2(vf_l, rd, rn, rm); break;
2759 case NEON_SADDL: saddl(vf_l, rd, rn, rm); break;
2760 case NEON_SADDL2: saddl2(vf_l, rd, rn, rm); break;
2761 case NEON_USUBL: usubl(vf_l, rd, rn, rm); break;
2762 case NEON_USUBL2: usubl2(vf_l, rd, rn, rm); break;
2763 case NEON_SSUBL: ssubl(vf_l, rd, rn, rm); break;
2764 case NEON_SSUBL2: ssubl2(vf_l, rd, rn, rm); break;
2765 case NEON_SABAL: sabal(vf_l, rd, rn, rm); break;
2766 case NEON_SABAL2: sabal2(vf_l, rd, rn, rm); break;
2767 case NEON_UABAL: uabal(vf_l, rd, rn, rm); break;
2768 case NEON_UABAL2: uabal2(vf_l, rd, rn, rm); break;
2769 case NEON_SABDL: sabdl(vf_l, rd, rn, rm); break;
2770 case NEON_SABDL2: sabdl2(vf_l, rd, rn, rm); break;
2771 case NEON_UABDL: uabdl(vf_l, rd, rn, rm); break;
2772 case NEON_UABDL2: uabdl2(vf_l, rd, rn, rm); break;
2773 case NEON_SMLAL: smlal(vf_l, rd, rn, rm); break;
2774 case NEON_SMLAL2: smlal2(vf_l, rd, rn, rm); break;
2775 case NEON_UMLAL: umlal(vf_l, rd, rn, rm); break;
2776 case NEON_UMLAL2: umlal2(vf_l, rd, rn, rm); break;
2777 case NEON_SMLSL: smlsl(vf_l, rd, rn, rm); break;
2778 case NEON_SMLSL2: smlsl2(vf_l, rd, rn, rm); break;
2779 case NEON_UMLSL: umlsl(vf_l, rd, rn, rm); break;
2780 case NEON_UMLSL2: umlsl2(vf_l, rd, rn, rm); break;
2781 case NEON_SMULL: smull(vf_l, rd, rn, rm); break;
2782 case NEON_SMULL2: smull2(vf_l, rd, rn, rm); break;
2783 case NEON_UMULL: umull(vf_l, rd, rn, rm); break;
2784 case NEON_UMULL2: umull2(vf_l, rd, rn, rm); break;
2785 case NEON_SQDMLAL: sqdmlal(vf_l, rd, rn, rm); break;
2786 case NEON_SQDMLAL2: sqdmlal2(vf_l, rd, rn, rm); break;
2787 case NEON_SQDMLSL: sqdmlsl(vf_l, rd, rn, rm); break;
2788 case NEON_SQDMLSL2: sqdmlsl2(vf_l, rd, rn, rm); break;
2789 case NEON_SQDMULL: sqdmull(vf_l, rd, rn, rm); break;
2790 case NEON_SQDMULL2: sqdmull2(vf_l, rd, rn, rm); break;
2791 case NEON_UADDW: uaddw(vf_l, rd, rn, rm); break;
2792 case NEON_UADDW2: uaddw2(vf_l, rd, rn, rm); break;
2793 case NEON_SADDW: saddw(vf_l, rd, rn, rm); break;
2794 case NEON_SADDW2: saddw2(vf_l, rd, rn, rm); break;
2795 case NEON_USUBW: usubw(vf_l, rd, rn, rm); break;
2796 case NEON_USUBW2: usubw2(vf_l, rd, rn, rm); break;
2797 case NEON_SSUBW: ssubw(vf_l, rd, rn, rm); break;
2798 case NEON_SSUBW2: ssubw2(vf_l, rd, rn, rm); break;
2799 case NEON_ADDHN: addhn(vf, rd, rn, rm); break;
2800 case NEON_ADDHN2: addhn2(vf, rd, rn, rm); break;
2801 case NEON_RADDHN: raddhn(vf, rd, rn, rm); break;
2802 case NEON_RADDHN2: raddhn2(vf, rd, rn, rm); break;
2803 case NEON_SUBHN: subhn(vf, rd, rn, rm); break;
2804 case NEON_SUBHN2: subhn2(vf, rd, rn, rm); break;
2805 case NEON_RSUBHN: rsubhn(vf, rd, rn, rm); break;
2806 case NEON_RSUBHN2: rsubhn2(vf, rd, rn, rm); break;
2807 default:
2808 VIXL_UNIMPLEMENTED();
2809 }
2810 }
2811
2812
VisitNEONAcrossLanes(const Instruction * instr)2813 void Simulator::VisitNEONAcrossLanes(const Instruction* instr) {
2814 NEONFormatDecoder nfd(instr);
2815
2816 SimVRegister& rd = vreg(instr->Rd());
2817 SimVRegister& rn = vreg(instr->Rn());
2818
2819 // The input operand's VectorFormat is passed for these instructions.
2820 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
2821 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2822
2823 switch (instr->Mask(NEONAcrossLanesFPMask)) {
2824 case NEON_FMAXV: fmaxv(vf, rd, rn); break;
2825 case NEON_FMINV: fminv(vf, rd, rn); break;
2826 case NEON_FMAXNMV: fmaxnmv(vf, rd, rn); break;
2827 case NEON_FMINNMV: fminnmv(vf, rd, rn); break;
2828 default:
2829 VIXL_UNIMPLEMENTED();
2830 }
2831 } else {
2832 VectorFormat vf = nfd.GetVectorFormat();
2833
2834 switch (instr->Mask(NEONAcrossLanesMask)) {
2835 case NEON_ADDV: addv(vf, rd, rn); break;
2836 case NEON_SMAXV: smaxv(vf, rd, rn); break;
2837 case NEON_SMINV: sminv(vf, rd, rn); break;
2838 case NEON_UMAXV: umaxv(vf, rd, rn); break;
2839 case NEON_UMINV: uminv(vf, rd, rn); break;
2840 case NEON_SADDLV: saddlv(vf, rd, rn); break;
2841 case NEON_UADDLV: uaddlv(vf, rd, rn); break;
2842 default:
2843 VIXL_UNIMPLEMENTED();
2844 }
2845 }
2846 }
2847
2848
VisitNEONByIndexedElement(const Instruction * instr)2849 void Simulator::VisitNEONByIndexedElement(const Instruction* instr) {
2850 NEONFormatDecoder nfd(instr);
2851 VectorFormat vf_r = nfd.GetVectorFormat();
2852 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2853
2854 SimVRegister& rd = vreg(instr->Rd());
2855 SimVRegister& rn = vreg(instr->Rn());
2856
2857 ByElementOp Op = NULL;
2858
2859 int rm_reg = instr->Rm();
2860 int index = (instr->NEONH() << 1) | instr->NEONL();
2861 if (instr->NEONSize() == 1) {
2862 rm_reg &= 0xf;
2863 index = (index << 1) | instr->NEONM();
2864 }
2865
2866 switch (instr->Mask(NEONByIndexedElementMask)) {
2867 case NEON_MUL_byelement: Op = &Simulator::mul; vf = vf_r; break;
2868 case NEON_MLA_byelement: Op = &Simulator::mla; vf = vf_r; break;
2869 case NEON_MLS_byelement: Op = &Simulator::mls; vf = vf_r; break;
2870 case NEON_SQDMULH_byelement: Op = &Simulator::sqdmulh; vf = vf_r; break;
2871 case NEON_SQRDMULH_byelement: Op = &Simulator::sqrdmulh; vf = vf_r; break;
2872 case NEON_SMULL_byelement:
2873 if (instr->Mask(NEON_Q)) {
2874 Op = &Simulator::smull2;
2875 } else {
2876 Op = &Simulator::smull;
2877 }
2878 break;
2879 case NEON_UMULL_byelement:
2880 if (instr->Mask(NEON_Q)) {
2881 Op = &Simulator::umull2;
2882 } else {
2883 Op = &Simulator::umull;
2884 }
2885 break;
2886 case NEON_SMLAL_byelement:
2887 if (instr->Mask(NEON_Q)) {
2888 Op = &Simulator::smlal2;
2889 } else {
2890 Op = &Simulator::smlal;
2891 }
2892 break;
2893 case NEON_UMLAL_byelement:
2894 if (instr->Mask(NEON_Q)) {
2895 Op = &Simulator::umlal2;
2896 } else {
2897 Op = &Simulator::umlal;
2898 }
2899 break;
2900 case NEON_SMLSL_byelement:
2901 if (instr->Mask(NEON_Q)) {
2902 Op = &Simulator::smlsl2;
2903 } else {
2904 Op = &Simulator::smlsl;
2905 }
2906 break;
2907 case NEON_UMLSL_byelement:
2908 if (instr->Mask(NEON_Q)) {
2909 Op = &Simulator::umlsl2;
2910 } else {
2911 Op = &Simulator::umlsl;
2912 }
2913 break;
2914 case NEON_SQDMULL_byelement:
2915 if (instr->Mask(NEON_Q)) {
2916 Op = &Simulator::sqdmull2;
2917 } else {
2918 Op = &Simulator::sqdmull;
2919 }
2920 break;
2921 case NEON_SQDMLAL_byelement:
2922 if (instr->Mask(NEON_Q)) {
2923 Op = &Simulator::sqdmlal2;
2924 } else {
2925 Op = &Simulator::sqdmlal;
2926 }
2927 break;
2928 case NEON_SQDMLSL_byelement:
2929 if (instr->Mask(NEON_Q)) {
2930 Op = &Simulator::sqdmlsl2;
2931 } else {
2932 Op = &Simulator::sqdmlsl;
2933 }
2934 break;
2935 default:
2936 index = instr->NEONH();
2937 if ((instr->FPType() & 1) == 0) {
2938 index = (index << 1) | instr->NEONL();
2939 }
2940
2941 vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2942
2943 switch (instr->Mask(NEONByIndexedElementFPMask)) {
2944 case NEON_FMUL_byelement: Op = &Simulator::fmul; break;
2945 case NEON_FMLA_byelement: Op = &Simulator::fmla; break;
2946 case NEON_FMLS_byelement: Op = &Simulator::fmls; break;
2947 case NEON_FMULX_byelement: Op = &Simulator::fmulx; break;
2948 default: VIXL_UNIMPLEMENTED();
2949 }
2950 }
2951
2952 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
2953 }
2954
2955
VisitNEONCopy(const Instruction * instr)2956 void Simulator::VisitNEONCopy(const Instruction* instr) {
2957 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
2958 VectorFormat vf = nfd.GetVectorFormat();
2959
2960 SimVRegister& rd = vreg(instr->Rd());
2961 SimVRegister& rn = vreg(instr->Rn());
2962 int imm5 = instr->ImmNEON5();
2963 int tz = CountTrailingZeros(imm5, 32);
2964 int reg_index = imm5 >> (tz + 1);
2965
2966 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
2967 int imm4 = instr->ImmNEON4();
2968 int rn_index = imm4 >> tz;
2969 ins_element(vf, rd, reg_index, rn, rn_index);
2970 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
2971 ins_immediate(vf, rd, reg_index, xreg(instr->Rn()));
2972 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
2973 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
2974 value &= MaxUintFromFormat(vf);
2975 set_xreg(instr->Rd(), value);
2976 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
2977 int64_t value = LogicVRegister(rn).Int(vf, reg_index);
2978 if (instr->NEONQ()) {
2979 set_xreg(instr->Rd(), value);
2980 } else {
2981 set_wreg(instr->Rd(), (int32_t)value);
2982 }
2983 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
2984 dup_element(vf, rd, rn, reg_index);
2985 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
2986 dup_immediate(vf, rd, xreg(instr->Rn()));
2987 } else {
2988 VIXL_UNIMPLEMENTED();
2989 }
2990 }
2991
2992
VisitNEONExtract(const Instruction * instr)2993 void Simulator::VisitNEONExtract(const Instruction* instr) {
2994 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
2995 VectorFormat vf = nfd.GetVectorFormat();
2996 SimVRegister& rd = vreg(instr->Rd());
2997 SimVRegister& rn = vreg(instr->Rn());
2998 SimVRegister& rm = vreg(instr->Rm());
2999 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
3000 int index = instr->ImmNEONExt();
3001 ext(vf, rd, rn, rm, index);
3002 } else {
3003 VIXL_UNIMPLEMENTED();
3004 }
3005 }
3006
3007
NEONLoadStoreMultiStructHelper(const Instruction * instr,AddrMode addr_mode)3008 void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
3009 AddrMode addr_mode) {
3010 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
3011 VectorFormat vf = nfd.GetVectorFormat();
3012
3013 uint64_t addr_base = xreg(instr->Rn(), Reg31IsStackPointer);
3014 uint64_t reg_size = RegisterSizeInBytesFromFormat(vf);
3015
3016 int reg[4];
3017 uint64_t addr[4];
3018 for (int i = 0; i < 4; i++) {
3019 reg[i] = (instr->Rt() + i) % kNumberOfVRegisters;
3020 addr[i] = addr_base + (i * reg_size);
3021 }
3022 int count = 1;
3023 bool log_read = true;
3024
3025 Instr itype = instr->Mask(NEONLoadStoreMultiStructMask);
3026 if (((itype == NEON_LD1_1v) || (itype == NEON_LD1_2v) ||
3027 (itype == NEON_LD1_3v) || (itype == NEON_LD1_4v) ||
3028 (itype == NEON_ST1_1v) || (itype == NEON_ST1_2v) ||
3029 (itype == NEON_ST1_3v) || (itype == NEON_ST1_4v)) &&
3030 (instr->Bits(20, 16) != 0)) {
3031 VIXL_UNREACHABLE();
3032 }
3033
3034 // We use the PostIndex mask here, as it works in this case for both Offset
3035 // and PostIndex addressing.
3036 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
3037 case NEON_LD1_4v:
3038 case NEON_LD1_4v_post: ld1(vf, vreg(reg[3]), addr[3]); count++;
3039 VIXL_FALLTHROUGH();
3040 case NEON_LD1_3v:
3041 case NEON_LD1_3v_post: ld1(vf, vreg(reg[2]), addr[2]); count++;
3042 VIXL_FALLTHROUGH();
3043 case NEON_LD1_2v:
3044 case NEON_LD1_2v_post: ld1(vf, vreg(reg[1]), addr[1]); count++;
3045 VIXL_FALLTHROUGH();
3046 case NEON_LD1_1v:
3047 case NEON_LD1_1v_post:
3048 ld1(vf, vreg(reg[0]), addr[0]);
3049 log_read = true;
3050 break;
3051 case NEON_ST1_4v:
3052 case NEON_ST1_4v_post: st1(vf, vreg(reg[3]), addr[3]); count++;
3053 VIXL_FALLTHROUGH();
3054 case NEON_ST1_3v:
3055 case NEON_ST1_3v_post: st1(vf, vreg(reg[2]), addr[2]); count++;
3056 VIXL_FALLTHROUGH();
3057 case NEON_ST1_2v:
3058 case NEON_ST1_2v_post: st1(vf, vreg(reg[1]), addr[1]); count++;
3059 VIXL_FALLTHROUGH();
3060 case NEON_ST1_1v:
3061 case NEON_ST1_1v_post:
3062 st1(vf, vreg(reg[0]), addr[0]);
3063 log_read = false;
3064 break;
3065 case NEON_LD2_post:
3066 case NEON_LD2:
3067 ld2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
3068 count = 2;
3069 break;
3070 case NEON_ST2:
3071 case NEON_ST2_post:
3072 st2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
3073 count = 2;
3074 break;
3075 case NEON_LD3_post:
3076 case NEON_LD3:
3077 ld3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
3078 count = 3;
3079 break;
3080 case NEON_ST3:
3081 case NEON_ST3_post:
3082 st3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
3083 count = 3;
3084 break;
3085 case NEON_ST4:
3086 case NEON_ST4_post:
3087 st4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]),
3088 addr[0]);
3089 count = 4;
3090 break;
3091 case NEON_LD4_post:
3092 case NEON_LD4:
3093 ld4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]),
3094 addr[0]);
3095 count = 4;
3096 break;
3097 default: VIXL_UNIMPLEMENTED();
3098 }
3099
3100 // Explicitly log the register update whilst we have type information.
3101 for (int i = 0; i < count; i++) {
3102 // For de-interleaving loads, only print the base address.
3103 int lane_size = LaneSizeInBytesFromFormat(vf);
3104 PrintRegisterFormat format = GetPrintRegisterFormatTryFP(
3105 GetPrintRegisterFormatForSize(reg_size, lane_size));
3106 if (log_read) {
3107 LogVRead(addr_base, reg[i], format);
3108 } else {
3109 LogVWrite(addr_base, reg[i], format);
3110 }
3111 }
3112
3113 if (addr_mode == PostIndex) {
3114 int rm = instr->Rm();
3115 // The immediate post index addressing mode is indicated by rm = 31.
3116 // The immediate is implied by the number of vector registers used.
3117 addr_base += (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count
3118 : xreg(rm);
3119 set_xreg(instr->Rn(), addr_base);
3120 } else {
3121 VIXL_ASSERT(addr_mode == Offset);
3122 }
3123 }
3124
3125
VisitNEONLoadStoreMultiStruct(const Instruction * instr)3126 void Simulator::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
3127 NEONLoadStoreMultiStructHelper(instr, Offset);
3128 }
3129
3130
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)3131 void Simulator::VisitNEONLoadStoreMultiStructPostIndex(
3132 const Instruction* instr) {
3133 NEONLoadStoreMultiStructHelper(instr, PostIndex);
3134 }
3135
3136
NEONLoadStoreSingleStructHelper(const Instruction * instr,AddrMode addr_mode)3137 void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
3138 AddrMode addr_mode) {
3139 uint64_t addr = xreg(instr->Rn(), Reg31IsStackPointer);
3140 int rt = instr->Rt();
3141
3142 Instr itype = instr->Mask(NEONLoadStoreSingleStructMask);
3143 if (((itype == NEON_LD1_b) || (itype == NEON_LD1_h) ||
3144 (itype == NEON_LD1_s) || (itype == NEON_LD1_d)) &&
3145 (instr->Bits(20, 16) != 0)) {
3146 VIXL_UNREACHABLE();
3147 }
3148
3149 // We use the PostIndex mask here, as it works in this case for both Offset
3150 // and PostIndex addressing.
3151 bool do_load = false;
3152
3153 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
3154 VectorFormat vf_t = nfd.GetVectorFormat();
3155
3156 VectorFormat vf = kFormat16B;
3157 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
3158 case NEON_LD1_b:
3159 case NEON_LD1_b_post:
3160 case NEON_LD2_b:
3161 case NEON_LD2_b_post:
3162 case NEON_LD3_b:
3163 case NEON_LD3_b_post:
3164 case NEON_LD4_b:
3165 case NEON_LD4_b_post: do_load = true;
3166 VIXL_FALLTHROUGH();
3167 case NEON_ST1_b:
3168 case NEON_ST1_b_post:
3169 case NEON_ST2_b:
3170 case NEON_ST2_b_post:
3171 case NEON_ST3_b:
3172 case NEON_ST3_b_post:
3173 case NEON_ST4_b:
3174 case NEON_ST4_b_post: break;
3175
3176 case NEON_LD1_h:
3177 case NEON_LD1_h_post:
3178 case NEON_LD2_h:
3179 case NEON_LD2_h_post:
3180 case NEON_LD3_h:
3181 case NEON_LD3_h_post:
3182 case NEON_LD4_h:
3183 case NEON_LD4_h_post: do_load = true;
3184 VIXL_FALLTHROUGH();
3185 case NEON_ST1_h:
3186 case NEON_ST1_h_post:
3187 case NEON_ST2_h:
3188 case NEON_ST2_h_post:
3189 case NEON_ST3_h:
3190 case NEON_ST3_h_post:
3191 case NEON_ST4_h:
3192 case NEON_ST4_h_post: vf = kFormat8H; break;
3193 case NEON_LD1_s:
3194 case NEON_LD1_s_post:
3195 case NEON_LD2_s:
3196 case NEON_LD2_s_post:
3197 case NEON_LD3_s:
3198 case NEON_LD3_s_post:
3199 case NEON_LD4_s:
3200 case NEON_LD4_s_post: do_load = true;
3201 VIXL_FALLTHROUGH();
3202 case NEON_ST1_s:
3203 case NEON_ST1_s_post:
3204 case NEON_ST2_s:
3205 case NEON_ST2_s_post:
3206 case NEON_ST3_s:
3207 case NEON_ST3_s_post:
3208 case NEON_ST4_s:
3209 case NEON_ST4_s_post: {
3210 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
3211 VIXL_STATIC_ASSERT(
3212 (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post);
3213 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
3214 VIXL_STATIC_ASSERT(
3215 (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post);
3216 vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
3217 break;
3218 }
3219
3220 case NEON_LD1R:
3221 case NEON_LD1R_post: {
3222 vf = vf_t;
3223 ld1r(vf, vreg(rt), addr);
3224 do_load = true;
3225 break;
3226 }
3227
3228 case NEON_LD2R:
3229 case NEON_LD2R_post: {
3230 vf = vf_t;
3231 int rt2 = (rt + 1) % kNumberOfVRegisters;
3232 ld2r(vf, vreg(rt), vreg(rt2), addr);
3233 do_load = true;
3234 break;
3235 }
3236
3237 case NEON_LD3R:
3238 case NEON_LD3R_post: {
3239 vf = vf_t;
3240 int rt2 = (rt + 1) % kNumberOfVRegisters;
3241 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
3242 ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr);
3243 do_load = true;
3244 break;
3245 }
3246
3247 case NEON_LD4R:
3248 case NEON_LD4R_post: {
3249 vf = vf_t;
3250 int rt2 = (rt + 1) % kNumberOfVRegisters;
3251 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
3252 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
3253 ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr);
3254 do_load = true;
3255 break;
3256 }
3257 default: VIXL_UNIMPLEMENTED();
3258 }
3259
3260 PrintRegisterFormat print_format =
3261 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
3262 // Make sure that the print_format only includes a single lane.
3263 print_format =
3264 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask);
3265
3266 int esize = LaneSizeInBytesFromFormat(vf);
3267 int index_shift = LaneSizeInBytesLog2FromFormat(vf);
3268 int lane = instr->NEONLSIndex(index_shift);
3269 int scale = 0;
3270 int rt2 = (rt + 1) % kNumberOfVRegisters;
3271 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
3272 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
3273 switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
3274 case NEONLoadStoreSingle1:
3275 scale = 1;
3276 if (do_load) {
3277 ld1(vf, vreg(rt), lane, addr);
3278 LogVRead(addr, rt, print_format, lane);
3279 } else {
3280 st1(vf, vreg(rt), lane, addr);
3281 LogVWrite(addr, rt, print_format, lane);
3282 }
3283 break;
3284 case NEONLoadStoreSingle2:
3285 scale = 2;
3286 if (do_load) {
3287 ld2(vf, vreg(rt), vreg(rt2), lane, addr);
3288 LogVRead(addr, rt, print_format, lane);
3289 LogVRead(addr + esize, rt2, print_format, lane);
3290 } else {
3291 st2(vf, vreg(rt), vreg(rt2), lane, addr);
3292 LogVWrite(addr, rt, print_format, lane);
3293 LogVWrite(addr + esize, rt2, print_format, lane);
3294 }
3295 break;
3296 case NEONLoadStoreSingle3:
3297 scale = 3;
3298 if (do_load) {
3299 ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
3300 LogVRead(addr, rt, print_format, lane);
3301 LogVRead(addr + esize, rt2, print_format, lane);
3302 LogVRead(addr + (2 * esize), rt3, print_format, lane);
3303 } else {
3304 st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
3305 LogVWrite(addr, rt, print_format, lane);
3306 LogVWrite(addr + esize, rt2, print_format, lane);
3307 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
3308 }
3309 break;
3310 case NEONLoadStoreSingle4:
3311 scale = 4;
3312 if (do_load) {
3313 ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
3314 LogVRead(addr, rt, print_format, lane);
3315 LogVRead(addr + esize, rt2, print_format, lane);
3316 LogVRead(addr + (2 * esize), rt3, print_format, lane);
3317 LogVRead(addr + (3 * esize), rt4, print_format, lane);
3318 } else {
3319 st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
3320 LogVWrite(addr, rt, print_format, lane);
3321 LogVWrite(addr + esize, rt2, print_format, lane);
3322 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
3323 LogVWrite(addr + (3 * esize), rt4, print_format, lane);
3324 }
3325 break;
3326 default: VIXL_UNIMPLEMENTED();
3327 }
3328
3329 if (addr_mode == PostIndex) {
3330 int rm = instr->Rm();
3331 int lane_size = LaneSizeInBytesFromFormat(vf);
3332 set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm)));
3333 }
3334 }
3335
3336
VisitNEONLoadStoreSingleStruct(const Instruction * instr)3337 void Simulator::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
3338 NEONLoadStoreSingleStructHelper(instr, Offset);
3339 }
3340
3341
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)3342 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(
3343 const Instruction* instr) {
3344 NEONLoadStoreSingleStructHelper(instr, PostIndex);
3345 }
3346
3347
VisitNEONModifiedImmediate(const Instruction * instr)3348 void Simulator::VisitNEONModifiedImmediate(const Instruction* instr) {
3349 SimVRegister& rd = vreg(instr->Rd());
3350 int cmode = instr->NEONCmode();
3351 int cmode_3_1 = (cmode >> 1) & 7;
3352 int cmode_3 = (cmode >> 3) & 1;
3353 int cmode_2 = (cmode >> 2) & 1;
3354 int cmode_1 = (cmode >> 1) & 1;
3355 int cmode_0 = cmode & 1;
3356 int q = instr->NEONQ();
3357 int op_bit = instr->NEONModImmOp();
3358 uint64_t imm8 = instr->ImmNEONabcdefgh();
3359
3360 // Find the format and immediate value
3361 uint64_t imm = 0;
3362 VectorFormat vform = kFormatUndefined;
3363 switch (cmode_3_1) {
3364 case 0x0:
3365 case 0x1:
3366 case 0x2:
3367 case 0x3:
3368 vform = (q == 1) ? kFormat4S : kFormat2S;
3369 imm = imm8 << (8 * cmode_3_1);
3370 break;
3371 case 0x4:
3372 case 0x5:
3373 vform = (q == 1) ? kFormat8H : kFormat4H;
3374 imm = imm8 << (8 * cmode_1);
3375 break;
3376 case 0x6:
3377 vform = (q == 1) ? kFormat4S : kFormat2S;
3378 if (cmode_0 == 0) {
3379 imm = imm8 << 8 | 0x000000ff;
3380 } else {
3381 imm = imm8 << 16 | 0x0000ffff;
3382 }
3383 break;
3384 case 0x7:
3385 if (cmode_0 == 0 && op_bit == 0) {
3386 vform = q ? kFormat16B : kFormat8B;
3387 imm = imm8;
3388 } else if (cmode_0 == 0 && op_bit == 1) {
3389 vform = q ? kFormat2D : kFormat1D;
3390 imm = 0;
3391 for (int i = 0; i < 8; ++i) {
3392 if (imm8 & (1 << i)) {
3393 imm |= (UINT64_C(0xff) << (8 * i));
3394 }
3395 }
3396 } else { // cmode_0 == 1, cmode == 0xf.
3397 if (op_bit == 0) {
3398 vform = q ? kFormat4S : kFormat2S;
3399 imm = float_to_rawbits(instr->ImmNEONFP32());
3400 } else if (q == 1) {
3401 vform = kFormat2D;
3402 imm = double_to_rawbits(instr->ImmNEONFP64());
3403 } else {
3404 VIXL_ASSERT((q == 0) && (op_bit == 1) && (cmode == 0xf));
3405 VisitUnallocated(instr);
3406 }
3407 }
3408 break;
3409 default: VIXL_UNREACHABLE(); break;
3410 }
3411
3412 // Find the operation
3413 NEONModifiedImmediateOp op;
3414 if (cmode_3 == 0) {
3415 if (cmode_0 == 0) {
3416 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3417 } else { // cmode<0> == '1'
3418 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
3419 }
3420 } else { // cmode<3> == '1'
3421 if (cmode_2 == 0) {
3422 if (cmode_0 == 0) {
3423 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3424 } else { // cmode<0> == '1'
3425 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
3426 }
3427 } else { // cmode<2> == '1'
3428 if (cmode_1 == 0) {
3429 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3430 } else { // cmode<1> == '1'
3431 if (cmode_0 == 0) {
3432 op = NEONModifiedImmediate_MOVI;
3433 } else { // cmode<0> == '1'
3434 op = NEONModifiedImmediate_MOVI;
3435 }
3436 }
3437 }
3438 }
3439
3440 // Call the logic function
3441 if (op == NEONModifiedImmediate_ORR) {
3442 orr(vform, rd, rd, imm);
3443 } else if (op == NEONModifiedImmediate_BIC) {
3444 bic(vform, rd, rd, imm);
3445 } else if (op == NEONModifiedImmediate_MOVI) {
3446 movi(vform, rd, imm);
3447 } else if (op == NEONModifiedImmediate_MVNI) {
3448 mvni(vform, rd, imm);
3449 } else {
3450 VisitUnimplemented(instr);
3451 }
3452 }
3453
3454
VisitNEONScalar2RegMisc(const Instruction * instr)3455 void Simulator::VisitNEONScalar2RegMisc(const Instruction* instr) {
3456 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3457 VectorFormat vf = nfd.GetVectorFormat();
3458
3459 SimVRegister& rd = vreg(instr->Rd());
3460 SimVRegister& rn = vreg(instr->Rn());
3461
3462 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
3463 // These instructions all use a two bit size field, except NOT and RBIT,
3464 // which use the field to encode the operation.
3465 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3466 case NEON_CMEQ_zero_scalar: cmp(vf, rd, rn, 0, eq); break;
3467 case NEON_CMGE_zero_scalar: cmp(vf, rd, rn, 0, ge); break;
3468 case NEON_CMGT_zero_scalar: cmp(vf, rd, rn, 0, gt); break;
3469 case NEON_CMLT_zero_scalar: cmp(vf, rd, rn, 0, lt); break;
3470 case NEON_CMLE_zero_scalar: cmp(vf, rd, rn, 0, le); break;
3471 case NEON_ABS_scalar: abs(vf, rd, rn); break;
3472 case NEON_SQABS_scalar: abs(vf, rd, rn).SignedSaturate(vf); break;
3473 case NEON_NEG_scalar: neg(vf, rd, rn); break;
3474 case NEON_SQNEG_scalar: neg(vf, rd, rn).SignedSaturate(vf); break;
3475 case NEON_SUQADD_scalar: suqadd(vf, rd, rn); break;
3476 case NEON_USQADD_scalar: usqadd(vf, rd, rn); break;
3477 default: VIXL_UNIMPLEMENTED(); break;
3478 }
3479 } else {
3480 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3481 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3482
3483 // These instructions all use a one bit size field, except SQXTUN, SQXTN
3484 // and UQXTN, which use a two bit size field.
3485 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
3486 case NEON_FRECPE_scalar: frecpe(fpf, rd, rn, fpcr_rounding); break;
3487 case NEON_FRECPX_scalar: frecpx(fpf, rd, rn); break;
3488 case NEON_FRSQRTE_scalar: frsqrte(fpf, rd, rn); break;
3489 case NEON_FCMGT_zero_scalar: fcmp_zero(fpf, rd, rn, gt); break;
3490 case NEON_FCMGE_zero_scalar: fcmp_zero(fpf, rd, rn, ge); break;
3491 case NEON_FCMEQ_zero_scalar: fcmp_zero(fpf, rd, rn, eq); break;
3492 case NEON_FCMLE_zero_scalar: fcmp_zero(fpf, rd, rn, le); break;
3493 case NEON_FCMLT_zero_scalar: fcmp_zero(fpf, rd, rn, lt); break;
3494 case NEON_SCVTF_scalar: scvtf(fpf, rd, rn, 0, fpcr_rounding); break;
3495 case NEON_UCVTF_scalar: ucvtf(fpf, rd, rn, 0, fpcr_rounding); break;
3496 case NEON_FCVTNS_scalar: fcvts(fpf, rd, rn, FPTieEven); break;
3497 case NEON_FCVTNU_scalar: fcvtu(fpf, rd, rn, FPTieEven); break;
3498 case NEON_FCVTPS_scalar: fcvts(fpf, rd, rn, FPPositiveInfinity); break;
3499 case NEON_FCVTPU_scalar: fcvtu(fpf, rd, rn, FPPositiveInfinity); break;
3500 case NEON_FCVTMS_scalar: fcvts(fpf, rd, rn, FPNegativeInfinity); break;
3501 case NEON_FCVTMU_scalar: fcvtu(fpf, rd, rn, FPNegativeInfinity); break;
3502 case NEON_FCVTZS_scalar: fcvts(fpf, rd, rn, FPZero); break;
3503 case NEON_FCVTZU_scalar: fcvtu(fpf, rd, rn, FPZero); break;
3504 case NEON_FCVTAS_scalar: fcvts(fpf, rd, rn, FPTieAway); break;
3505 case NEON_FCVTAU_scalar: fcvtu(fpf, rd, rn, FPTieAway); break;
3506 case NEON_FCVTXN_scalar:
3507 // Unlike all of the other FP instructions above, fcvtxn encodes dest
3508 // size S as size<0>=1. There's only one case, so we ignore the form.
3509 VIXL_ASSERT(instr->Bit(22) == 1);
3510 fcvtxn(kFormatS, rd, rn);
3511 break;
3512 default:
3513 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3514 case NEON_SQXTN_scalar: sqxtn(vf, rd, rn); break;
3515 case NEON_UQXTN_scalar: uqxtn(vf, rd, rn); break;
3516 case NEON_SQXTUN_scalar: sqxtun(vf, rd, rn); break;
3517 default:
3518 VIXL_UNIMPLEMENTED();
3519 }
3520 }
3521 }
3522 }
3523
3524
VisitNEONScalar3Diff(const Instruction * instr)3525 void Simulator::VisitNEONScalar3Diff(const Instruction* instr) {
3526 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
3527 VectorFormat vf = nfd.GetVectorFormat();
3528
3529 SimVRegister& rd = vreg(instr->Rd());
3530 SimVRegister& rn = vreg(instr->Rn());
3531 SimVRegister& rm = vreg(instr->Rm());
3532 switch (instr->Mask(NEONScalar3DiffMask)) {
3533 case NEON_SQDMLAL_scalar: sqdmlal(vf, rd, rn, rm); break;
3534 case NEON_SQDMLSL_scalar: sqdmlsl(vf, rd, rn, rm); break;
3535 case NEON_SQDMULL_scalar: sqdmull(vf, rd, rn, rm); break;
3536 default:
3537 VIXL_UNIMPLEMENTED();
3538 }
3539 }
3540
3541
VisitNEONScalar3Same(const Instruction * instr)3542 void Simulator::VisitNEONScalar3Same(const Instruction* instr) {
3543 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3544 VectorFormat vf = nfd.GetVectorFormat();
3545
3546 SimVRegister& rd = vreg(instr->Rd());
3547 SimVRegister& rn = vreg(instr->Rn());
3548 SimVRegister& rm = vreg(instr->Rm());
3549
3550 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
3551 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3552 switch (instr->Mask(NEONScalar3SameFPMask)) {
3553 case NEON_FMULX_scalar: fmulx(vf, rd, rn, rm); break;
3554 case NEON_FACGE_scalar: fabscmp(vf, rd, rn, rm, ge); break;
3555 case NEON_FACGT_scalar: fabscmp(vf, rd, rn, rm, gt); break;
3556 case NEON_FCMEQ_scalar: fcmp(vf, rd, rn, rm, eq); break;
3557 case NEON_FCMGE_scalar: fcmp(vf, rd, rn, rm, ge); break;
3558 case NEON_FCMGT_scalar: fcmp(vf, rd, rn, rm, gt); break;
3559 case NEON_FRECPS_scalar: frecps(vf, rd, rn, rm); break;
3560 case NEON_FRSQRTS_scalar: frsqrts(vf, rd, rn, rm); break;
3561 case NEON_FABD_scalar: fabd(vf, rd, rn, rm); break;
3562 default:
3563 VIXL_UNIMPLEMENTED();
3564 }
3565 } else {
3566 switch (instr->Mask(NEONScalar3SameMask)) {
3567 case NEON_ADD_scalar: add(vf, rd, rn, rm); break;
3568 case NEON_SUB_scalar: sub(vf, rd, rn, rm); break;
3569 case NEON_CMEQ_scalar: cmp(vf, rd, rn, rm, eq); break;
3570 case NEON_CMGE_scalar: cmp(vf, rd, rn, rm, ge); break;
3571 case NEON_CMGT_scalar: cmp(vf, rd, rn, rm, gt); break;
3572 case NEON_CMHI_scalar: cmp(vf, rd, rn, rm, hi); break;
3573 case NEON_CMHS_scalar: cmp(vf, rd, rn, rm, hs); break;
3574 case NEON_CMTST_scalar: cmptst(vf, rd, rn, rm); break;
3575 case NEON_USHL_scalar: ushl(vf, rd, rn, rm); break;
3576 case NEON_SSHL_scalar: sshl(vf, rd, rn, rm); break;
3577 case NEON_SQDMULH_scalar: sqdmulh(vf, rd, rn, rm); break;
3578 case NEON_SQRDMULH_scalar: sqrdmulh(vf, rd, rn, rm); break;
3579 case NEON_UQADD_scalar:
3580 add(vf, rd, rn, rm).UnsignedSaturate(vf);
3581 break;
3582 case NEON_SQADD_scalar:
3583 add(vf, rd, rn, rm).SignedSaturate(vf);
3584 break;
3585 case NEON_UQSUB_scalar:
3586 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
3587 break;
3588 case NEON_SQSUB_scalar:
3589 sub(vf, rd, rn, rm).SignedSaturate(vf);
3590 break;
3591 case NEON_UQSHL_scalar:
3592 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
3593 break;
3594 case NEON_SQSHL_scalar:
3595 sshl(vf, rd, rn, rm).SignedSaturate(vf);
3596 break;
3597 case NEON_URSHL_scalar:
3598 ushl(vf, rd, rn, rm).Round(vf);
3599 break;
3600 case NEON_SRSHL_scalar:
3601 sshl(vf, rd, rn, rm).Round(vf);
3602 break;
3603 case NEON_UQRSHL_scalar:
3604 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
3605 break;
3606 case NEON_SQRSHL_scalar:
3607 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
3608 break;
3609 default:
3610 VIXL_UNIMPLEMENTED();
3611 }
3612 }
3613 }
3614
3615
VisitNEONScalarByIndexedElement(const Instruction * instr)3616 void Simulator::VisitNEONScalarByIndexedElement(const Instruction* instr) {
3617 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
3618 VectorFormat vf = nfd.GetVectorFormat();
3619 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());
3620
3621 SimVRegister& rd = vreg(instr->Rd());
3622 SimVRegister& rn = vreg(instr->Rn());
3623 ByElementOp Op = NULL;
3624
3625 int rm_reg = instr->Rm();
3626 int index = (instr->NEONH() << 1) | instr->NEONL();
3627 if (instr->NEONSize() == 1) {
3628 rm_reg &= 0xf;
3629 index = (index << 1) | instr->NEONM();
3630 }
3631
3632 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
3633 case NEON_SQDMULL_byelement_scalar: Op = &Simulator::sqdmull; break;
3634 case NEON_SQDMLAL_byelement_scalar: Op = &Simulator::sqdmlal; break;
3635 case NEON_SQDMLSL_byelement_scalar: Op = &Simulator::sqdmlsl; break;
3636 case NEON_SQDMULH_byelement_scalar:
3637 Op = &Simulator::sqdmulh;
3638 vf = vf_r;
3639 break;
3640 case NEON_SQRDMULH_byelement_scalar:
3641 Op = &Simulator::sqrdmulh;
3642 vf = vf_r;
3643 break;
3644 default:
3645 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3646 index = instr->NEONH();
3647 if ((instr->FPType() & 1) == 0) {
3648 index = (index << 1) | instr->NEONL();
3649 }
3650 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
3651 case NEON_FMUL_byelement_scalar: Op = &Simulator::fmul; break;
3652 case NEON_FMLA_byelement_scalar: Op = &Simulator::fmla; break;
3653 case NEON_FMLS_byelement_scalar: Op = &Simulator::fmls; break;
3654 case NEON_FMULX_byelement_scalar: Op = &Simulator::fmulx; break;
3655 default: VIXL_UNIMPLEMENTED();
3656 }
3657 }
3658
3659 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
3660 }
3661
3662
VisitNEONScalarCopy(const Instruction * instr)3663 void Simulator::VisitNEONScalarCopy(const Instruction* instr) {
3664 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
3665 VectorFormat vf = nfd.GetVectorFormat();
3666
3667 SimVRegister& rd = vreg(instr->Rd());
3668 SimVRegister& rn = vreg(instr->Rn());
3669
3670 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
3671 int imm5 = instr->ImmNEON5();
3672 int tz = CountTrailingZeros(imm5, 32);
3673 int rn_index = imm5 >> (tz + 1);
3674 dup_element(vf, rd, rn, rn_index);
3675 } else {
3676 VIXL_UNIMPLEMENTED();
3677 }
3678 }
3679
3680
VisitNEONScalarPairwise(const Instruction * instr)3681 void Simulator::VisitNEONScalarPairwise(const Instruction* instr) {
3682 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());
3683 VectorFormat vf = nfd.GetVectorFormat();
3684
3685 SimVRegister& rd = vreg(instr->Rd());
3686 SimVRegister& rn = vreg(instr->Rn());
3687 switch (instr->Mask(NEONScalarPairwiseMask)) {
3688 case NEON_ADDP_scalar: addp(vf, rd, rn); break;
3689 case NEON_FADDP_scalar: faddp(vf, rd, rn); break;
3690 case NEON_FMAXP_scalar: fmaxp(vf, rd, rn); break;
3691 case NEON_FMAXNMP_scalar: fmaxnmp(vf, rd, rn); break;
3692 case NEON_FMINP_scalar: fminp(vf, rd, rn); break;
3693 case NEON_FMINNMP_scalar: fminnmp(vf, rd, rn); break;
3694 default:
3695 VIXL_UNIMPLEMENTED();
3696 }
3697 }
3698
3699
VisitNEONScalarShiftImmediate(const Instruction * instr)3700 void Simulator::VisitNEONScalarShiftImmediate(const Instruction* instr) {
3701 SimVRegister& rd = vreg(instr->Rd());
3702 SimVRegister& rn = vreg(instr->Rn());
3703 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3704
3705 static const NEONFormatMap map = {
3706 {22, 21, 20, 19},
3707 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S,
3708 NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D}
3709 };
3710 NEONFormatDecoder nfd(instr, &map);
3711 VectorFormat vf = nfd.GetVectorFormat();
3712
3713 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
3714 int immhimmb = instr->ImmNEONImmhImmb();
3715 int right_shift = (16 << highestSetBit) - immhimmb;
3716 int left_shift = immhimmb - (8 << highestSetBit);
3717 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
3718 case NEON_SHL_scalar: shl(vf, rd, rn, left_shift); break;
3719 case NEON_SLI_scalar: sli(vf, rd, rn, left_shift); break;
3720 case NEON_SQSHL_imm_scalar: sqshl(vf, rd, rn, left_shift); break;
3721 case NEON_UQSHL_imm_scalar: uqshl(vf, rd, rn, left_shift); break;
3722 case NEON_SQSHLU_scalar: sqshlu(vf, rd, rn, left_shift); break;
3723 case NEON_SRI_scalar: sri(vf, rd, rn, right_shift); break;
3724 case NEON_SSHR_scalar: sshr(vf, rd, rn, right_shift); break;
3725 case NEON_USHR_scalar: ushr(vf, rd, rn, right_shift); break;
3726 case NEON_SRSHR_scalar: sshr(vf, rd, rn, right_shift).Round(vf); break;
3727 case NEON_URSHR_scalar: ushr(vf, rd, rn, right_shift).Round(vf); break;
3728 case NEON_SSRA_scalar: ssra(vf, rd, rn, right_shift); break;
3729 case NEON_USRA_scalar: usra(vf, rd, rn, right_shift); break;
3730 case NEON_SRSRA_scalar: srsra(vf, rd, rn, right_shift); break;
3731 case NEON_URSRA_scalar: ursra(vf, rd, rn, right_shift); break;
3732 case NEON_UQSHRN_scalar: uqshrn(vf, rd, rn, right_shift); break;
3733 case NEON_UQRSHRN_scalar: uqrshrn(vf, rd, rn, right_shift); break;
3734 case NEON_SQSHRN_scalar: sqshrn(vf, rd, rn, right_shift); break;
3735 case NEON_SQRSHRN_scalar: sqrshrn(vf, rd, rn, right_shift); break;
3736 case NEON_SQSHRUN_scalar: sqshrun(vf, rd, rn, right_shift); break;
3737 case NEON_SQRSHRUN_scalar: sqrshrun(vf, rd, rn, right_shift); break;
3738 case NEON_FCVTZS_imm_scalar: fcvts(vf, rd, rn, FPZero, right_shift); break;
3739 case NEON_FCVTZU_imm_scalar: fcvtu(vf, rd, rn, FPZero, right_shift); break;
3740 case NEON_SCVTF_imm_scalar:
3741 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
3742 break;
3743 case NEON_UCVTF_imm_scalar:
3744 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
3745 break;
3746 default:
3747 VIXL_UNIMPLEMENTED();
3748 }
3749 }
3750
3751
VisitNEONShiftImmediate(const Instruction * instr)3752 void Simulator::VisitNEONShiftImmediate(const Instruction* instr) {
3753 SimVRegister& rd = vreg(instr->Rd());
3754 SimVRegister& rn = vreg(instr->Rn());
3755 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3756
3757 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
3758 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
3759 static const NEONFormatMap map = {
3760 {22, 21, 20, 19, 30},
3761 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H,
3762 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S,
3763 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
3764 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}
3765 };
3766 NEONFormatDecoder nfd(instr, &map);
3767 VectorFormat vf = nfd.GetVectorFormat();
3768
3769 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
3770 static const NEONFormatMap map_l = {
3771 {22, 21, 20, 19},
3772 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}
3773 };
3774 VectorFormat vf_l = nfd.GetVectorFormat(&map_l);
3775
3776 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
3777 int immhimmb = instr->ImmNEONImmhImmb();
3778 int right_shift = (16 << highestSetBit) - immhimmb;
3779 int left_shift = immhimmb - (8 << highestSetBit);
3780
3781 switch (instr->Mask(NEONShiftImmediateMask)) {
3782 case NEON_SHL: shl(vf, rd, rn, left_shift); break;
3783 case NEON_SLI: sli(vf, rd, rn, left_shift); break;
3784 case NEON_SQSHLU: sqshlu(vf, rd, rn, left_shift); break;
3785 case NEON_SRI: sri(vf, rd, rn, right_shift); break;
3786 case NEON_SSHR: sshr(vf, rd, rn, right_shift); break;
3787 case NEON_USHR: ushr(vf, rd, rn, right_shift); break;
3788 case NEON_SRSHR: sshr(vf, rd, rn, right_shift).Round(vf); break;
3789 case NEON_URSHR: ushr(vf, rd, rn, right_shift).Round(vf); break;
3790 case NEON_SSRA: ssra(vf, rd, rn, right_shift); break;
3791 case NEON_USRA: usra(vf, rd, rn, right_shift); break;
3792 case NEON_SRSRA: srsra(vf, rd, rn, right_shift); break;
3793 case NEON_URSRA: ursra(vf, rd, rn, right_shift); break;
3794 case NEON_SQSHL_imm: sqshl(vf, rd, rn, left_shift); break;
3795 case NEON_UQSHL_imm: uqshl(vf, rd, rn, left_shift); break;
3796 case NEON_SCVTF_imm: scvtf(vf, rd, rn, right_shift, fpcr_rounding); break;
3797 case NEON_UCVTF_imm: ucvtf(vf, rd, rn, right_shift, fpcr_rounding); break;
3798 case NEON_FCVTZS_imm: fcvts(vf, rd, rn, FPZero, right_shift); break;
3799 case NEON_FCVTZU_imm: fcvtu(vf, rd, rn, FPZero, right_shift); break;
3800 case NEON_SSHLL:
3801 vf = vf_l;
3802 if (instr->Mask(NEON_Q)) {
3803 sshll2(vf, rd, rn, left_shift);
3804 } else {
3805 sshll(vf, rd, rn, left_shift);
3806 }
3807 break;
3808 case NEON_USHLL:
3809 vf = vf_l;
3810 if (instr->Mask(NEON_Q)) {
3811 ushll2(vf, rd, rn, left_shift);
3812 } else {
3813 ushll(vf, rd, rn, left_shift);
3814 }
3815 break;
3816 case NEON_SHRN:
3817 if (instr->Mask(NEON_Q)) {
3818 shrn2(vf, rd, rn, right_shift);
3819 } else {
3820 shrn(vf, rd, rn, right_shift);
3821 }
3822 break;
3823 case NEON_RSHRN:
3824 if (instr->Mask(NEON_Q)) {
3825 rshrn2(vf, rd, rn, right_shift);
3826 } else {
3827 rshrn(vf, rd, rn, right_shift);
3828 }
3829 break;
3830 case NEON_UQSHRN:
3831 if (instr->Mask(NEON_Q)) {
3832 uqshrn2(vf, rd, rn, right_shift);
3833 } else {
3834 uqshrn(vf, rd, rn, right_shift);
3835 }
3836 break;
3837 case NEON_UQRSHRN:
3838 if (instr->Mask(NEON_Q)) {
3839 uqrshrn2(vf, rd, rn, right_shift);
3840 } else {
3841 uqrshrn(vf, rd, rn, right_shift);
3842 }
3843 break;
3844 case NEON_SQSHRN:
3845 if (instr->Mask(NEON_Q)) {
3846 sqshrn2(vf, rd, rn, right_shift);
3847 } else {
3848 sqshrn(vf, rd, rn, right_shift);
3849 }
3850 break;
3851 case NEON_SQRSHRN:
3852 if (instr->Mask(NEON_Q)) {
3853 sqrshrn2(vf, rd, rn, right_shift);
3854 } else {
3855 sqrshrn(vf, rd, rn, right_shift);
3856 }
3857 break;
3858 case NEON_SQSHRUN:
3859 if (instr->Mask(NEON_Q)) {
3860 sqshrun2(vf, rd, rn, right_shift);
3861 } else {
3862 sqshrun(vf, rd, rn, right_shift);
3863 }
3864 break;
3865 case NEON_SQRSHRUN:
3866 if (instr->Mask(NEON_Q)) {
3867 sqrshrun2(vf, rd, rn, right_shift);
3868 } else {
3869 sqrshrun(vf, rd, rn, right_shift);
3870 }
3871 break;
3872 default:
3873 VIXL_UNIMPLEMENTED();
3874 }
3875 }
3876
3877
VisitNEONTable(const Instruction * instr)3878 void Simulator::VisitNEONTable(const Instruction* instr) {
3879 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
3880 VectorFormat vf = nfd.GetVectorFormat();
3881
3882 SimVRegister& rd = vreg(instr->Rd());
3883 SimVRegister& rn = vreg(instr->Rn());
3884 SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters);
3885 SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters);
3886 SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters);
3887 SimVRegister& rm = vreg(instr->Rm());
3888
3889 switch (instr->Mask(NEONTableMask)) {
3890 case NEON_TBL_1v: tbl(vf, rd, rn, rm); break;
3891 case NEON_TBL_2v: tbl(vf, rd, rn, rn2, rm); break;
3892 case NEON_TBL_3v: tbl(vf, rd, rn, rn2, rn3, rm); break;
3893 case NEON_TBL_4v: tbl(vf, rd, rn, rn2, rn3, rn4, rm); break;
3894 case NEON_TBX_1v: tbx(vf, rd, rn, rm); break;
3895 case NEON_TBX_2v: tbx(vf, rd, rn, rn2, rm); break;
3896 case NEON_TBX_3v: tbx(vf, rd, rn, rn2, rn3, rm); break;
3897 case NEON_TBX_4v: tbx(vf, rd, rn, rn2, rn3, rn4, rm); break;
3898 default:
3899 VIXL_UNIMPLEMENTED();
3900 }
3901 }
3902
3903
VisitNEONPerm(const Instruction * instr)3904 void Simulator::VisitNEONPerm(const Instruction* instr) {
3905 NEONFormatDecoder nfd(instr);
3906 VectorFormat vf = nfd.GetVectorFormat();
3907
3908 SimVRegister& rd = vreg(instr->Rd());
3909 SimVRegister& rn = vreg(instr->Rn());
3910 SimVRegister& rm = vreg(instr->Rm());
3911
3912 switch (instr->Mask(NEONPermMask)) {
3913 case NEON_TRN1: trn1(vf, rd, rn, rm); break;
3914 case NEON_TRN2: trn2(vf, rd, rn, rm); break;
3915 case NEON_UZP1: uzp1(vf, rd, rn, rm); break;
3916 case NEON_UZP2: uzp2(vf, rd, rn, rm); break;
3917 case NEON_ZIP1: zip1(vf, rd, rn, rm); break;
3918 case NEON_ZIP2: zip2(vf, rd, rn, rm); break;
3919 default:
3920 VIXL_UNIMPLEMENTED();
3921 }
3922 }
3923
3924
DoUnreachable(const Instruction * instr)3925 void Simulator::DoUnreachable(const Instruction* instr) {
3926 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3927 (instr->ImmException() == kUnreachableOpcode));
3928
3929 fprintf(stream_, "Hit UNREACHABLE marker at pc=%p.\n",
3930 reinterpret_cast<const void*>(instr));
3931 abort();
3932 }
3933
3934
DoTrace(const Instruction * instr)3935 void Simulator::DoTrace(const Instruction* instr) {
3936 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3937 (instr->ImmException() == kTraceOpcode));
3938
3939 // Read the arguments encoded inline in the instruction stream.
3940 uint32_t parameters;
3941 uint32_t command;
3942
3943 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3944 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
3945 memcpy(&command, instr + kTraceCommandOffset, sizeof(command));
3946
3947 switch (command) {
3948 case TRACE_ENABLE:
3949 set_trace_parameters(trace_parameters() | parameters);
3950 break;
3951 case TRACE_DISABLE:
3952 set_trace_parameters(trace_parameters() & ~parameters);
3953 break;
3954 default:
3955 VIXL_UNREACHABLE();
3956 }
3957
3958 set_pc(instr->InstructionAtOffset(kTraceLength));
3959 }
3960
3961
DoLog(const Instruction * instr)3962 void Simulator::DoLog(const Instruction* instr) {
3963 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3964 (instr->ImmException() == kLogOpcode));
3965
3966 // Read the arguments encoded inline in the instruction stream.
3967 uint32_t parameters;
3968
3969 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3970 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
3971
3972 // We don't support a one-shot LOG_DISASM.
3973 VIXL_ASSERT((parameters & LOG_DISASM) == 0);
3974 // Print the requested information.
3975 if (parameters & LOG_SYSREGS) PrintSystemRegisters();
3976 if (parameters & LOG_REGS) PrintRegisters();
3977 if (parameters & LOG_VREGS) PrintVRegisters();
3978
3979 set_pc(instr->InstructionAtOffset(kLogLength));
3980 }
3981
3982
DoPrintf(const Instruction * instr)3983 void Simulator::DoPrintf(const Instruction* instr) {
3984 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3985 (instr->ImmException() == kPrintfOpcode));
3986
3987 // Read the arguments encoded inline in the instruction stream.
3988 uint32_t arg_count;
3989 uint32_t arg_pattern_list;
3990 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3991 memcpy(&arg_count,
3992 instr + kPrintfArgCountOffset,
3993 sizeof(arg_count));
3994 memcpy(&arg_pattern_list,
3995 instr + kPrintfArgPatternListOffset,
3996 sizeof(arg_pattern_list));
3997
3998 VIXL_ASSERT(arg_count <= kPrintfMaxArgCount);
3999 VIXL_ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
4000
4001 // We need to call the host printf function with a set of arguments defined by
4002 // arg_pattern_list. Because we don't know the types and sizes of the
4003 // arguments, this is very difficult to do in a robust and portable way. To
4004 // work around the problem, we pick apart the format string, and print one
4005 // format placeholder at a time.
4006
4007 // Allocate space for the format string. We take a copy, so we can modify it.
4008 // Leave enough space for one extra character per expected argument (plus the
4009 // '\0' termination).
4010 const char * format_base = reg<const char *>(0);
4011 VIXL_ASSERT(format_base != NULL);
4012 size_t length = strlen(format_base) + 1;
4013 char * const format = new char[length + arg_count];
4014
4015 // A list of chunks, each with exactly one format placeholder.
4016 const char * chunks[kPrintfMaxArgCount];
4017
4018 // Copy the format string and search for format placeholders.
4019 uint32_t placeholder_count = 0;
4020 char * format_scratch = format;
4021 for (size_t i = 0; i < length; i++) {
4022 if (format_base[i] != '%') {
4023 *format_scratch++ = format_base[i];
4024 } else {
4025 if (format_base[i + 1] == '%') {
4026 // Ignore explicit "%%" sequences.
4027 *format_scratch++ = format_base[i];
4028 i++;
4029 // Chunks after the first are passed as format strings to printf, so we
4030 // need to escape '%' characters in those chunks.
4031 if (placeholder_count > 0) *format_scratch++ = format_base[i];
4032 } else {
4033 VIXL_CHECK(placeholder_count < arg_count);
4034 // Insert '\0' before placeholders, and store their locations.
4035 *format_scratch++ = '\0';
4036 chunks[placeholder_count++] = format_scratch;
4037 *format_scratch++ = format_base[i];
4038 }
4039 }
4040 }
4041 VIXL_CHECK(placeholder_count == arg_count);
4042
4043 // Finally, call printf with each chunk, passing the appropriate register
4044 // argument. Normally, printf returns the number of bytes transmitted, so we
4045 // can emulate a single printf call by adding the result from each chunk. If
4046 // any call returns a negative (error) value, though, just return that value.
4047
4048 printf("%s", clr_printf);
4049
4050 // Because '\0' is inserted before each placeholder, the first string in
4051 // 'format' contains no format placeholders and should be printed literally.
4052 int result = printf("%s", format);
4053 int pcs_r = 1; // Start at x1. x0 holds the format string.
4054 int pcs_f = 0; // Start at d0.
4055 if (result >= 0) {
4056 for (uint32_t i = 0; i < placeholder_count; i++) {
4057 int part_result = -1;
4058
4059 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
4060 arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
4061 switch (arg_pattern) {
4062 case kPrintfArgW: part_result = printf(chunks[i], wreg(pcs_r++)); break;
4063 case kPrintfArgX: part_result = printf(chunks[i], xreg(pcs_r++)); break;
4064 case kPrintfArgD: part_result = printf(chunks[i], dreg(pcs_f++)); break;
4065 default: VIXL_UNREACHABLE();
4066 }
4067
4068 if (part_result < 0) {
4069 // Handle error values.
4070 result = part_result;
4071 break;
4072 }
4073
4074 result += part_result;
4075 }
4076 }
4077
4078 printf("%s", clr_normal);
4079
4080 // Printf returns its result in x0 (just like the C library's printf).
4081 set_xreg(0, result);
4082
4083 // The printf parameters are inlined in the code, so skip them.
4084 set_pc(instr->InstructionAtOffset(kPrintfLength));
4085
4086 // Set LR as if we'd just called a native printf function.
4087 set_lr(pc());
4088
4089 delete[] format;
4090 }
4091
4092 } // namespace vixl
4093
4094 #endif // USE_SIMULATOR
4095