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