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