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