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