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