Five fixes, for fcsel, fcvtz, fminnm, mls, and non-widening mul.
[deliverable/binutils-gdb.git] / sim / aarch64 / simulator.c
CommitLineData
2e8cf49e
NC
1/* simulator.c -- Interface for the AArch64 simulator.
2
61baf725 3 Copyright (C) 2015-2017 Free Software Foundation, Inc.
2e8cf49e
NC
4
5 Contributed by Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <sys/types.h>
2e8cf49e
NC
27#include <math.h>
28#include <time.h>
29#include <limits.h>
30
2e8cf49e
NC
31#include "simulator.h"
32#include "cpustate.h"
33#include "memory.h"
34
35#define NO_SP 0
36#define SP_OK 1
37
2e8cf49e 38#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
e101a78b
NC
39#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
40#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
2e8cf49e 41
ef0d8ffc
NC
42/* Space saver macro. */
43#define INSTR(HIGH, LOW) uimm (aarch64_get_instr (cpu), (HIGH), (LOW))
44
2e8cf49e
NC
45#define HALT_UNALLOC \
46 do \
47 { \
1a846c62
MF
48 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
49 TRACE_INSN (cpu, \
50 "Unallocated instruction detected at sim line %d," \
51 " exe addr %" PRIx64, \
52 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
53 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
54 sim_stopped, SIM_SIGILL); \
55 } \
56 while (0)
57
58#define HALT_NYI \
59 do \
60 { \
1a846c62
MF
61 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
62 TRACE_INSN (cpu, \
63 "Unimplemented instruction detected at sim line %d," \
64 " exe addr %" PRIx64, \
65 __LINE__, aarch64_get_PC (cpu)); \
5ab6d79e 66 if (! TRACE_ANY_P (cpu)) \
6a277579
NC
67 sim_io_eprintf (CPU_STATE (cpu), "SIM Error: Unimplemented instruction: %#08x\n", \
68 aarch64_get_instr (cpu)); \
2e8cf49e
NC
69 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
70 sim_stopped, SIM_SIGABRT); \
71 } \
72 while (0)
73
74#define NYI_assert(HI, LO, EXPECTED) \
75 do \
76 { \
ef0d8ffc 77 if (INSTR ((HI), (LO)) != (EXPECTED)) \
2e8cf49e
NC
78 HALT_NYI; \
79 } \
80 while (0)
81
2e8cf49e
NC
82/* Helper functions used by expandLogicalImmediate. */
83
84/* for i = 1, ... N result<i-1> = 1 other bits are zero */
85static inline uint64_t
86ones (int N)
87{
88 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
89}
90
91/* result<0> to val<N> */
92static inline uint64_t
93pickbit (uint64_t val, int N)
94{
95 return pickbits64 (val, N, N);
96}
97
98static uint64_t
99expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
100{
101 uint64_t mask;
102 uint64_t imm;
103 unsigned simd_size;
104
105 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
106 (in other words, right rotated by R), then replicated. */
107 if (N != 0)
108 {
109 simd_size = 64;
110 mask = 0xffffffffffffffffull;
111 }
112 else
113 {
114 switch (S)
115 {
116 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
117 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
118 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
119 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
120 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
121 default: return 0;
122 }
123 mask = (1ull << simd_size) - 1;
124 /* Top bits are IGNORED. */
125 R &= simd_size - 1;
126 }
127
128 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
129 if (S == simd_size - 1)
130 return 0;
131
132 /* S+1 consecutive bits to 1. */
133 /* NOTE: S can't be 63 due to detection above. */
134 imm = (1ull << (S + 1)) - 1;
135
136 /* Rotate to the left by simd_size - R. */
137 if (R != 0)
138 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
139
140 /* Replicate the value according to SIMD size. */
141 switch (simd_size)
142 {
143 case 2: imm = (imm << 2) | imm;
144 case 4: imm = (imm << 4) | imm;
145 case 8: imm = (imm << 8) | imm;
146 case 16: imm = (imm << 16) | imm;
147 case 32: imm = (imm << 32) | imm;
148 case 64: break;
149 default: return 0;
150 }
151
152 return imm;
153}
154
155/* Instr[22,10] encodes N immr and imms. we want a lookup table
156 for each possible combination i.e. 13 bits worth of int entries. */
157#define LI_TABLE_SIZE (1 << 13)
158static uint64_t LITable[LI_TABLE_SIZE];
159
160void
161aarch64_init_LIT_table (void)
162{
163 unsigned index;
164
165 for (index = 0; index < LI_TABLE_SIZE; index++)
166 {
167 uint32_t N = uimm (index, 12, 12);
168 uint32_t immr = uimm (index, 11, 6);
169 uint32_t imms = uimm (index, 5, 0);
170
171 LITable [index] = expand_logical_immediate (imms, immr, N);
172 }
173}
174
175static void
176dexNotify (sim_cpu *cpu)
177{
178 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
179 2 ==> exit Java, 3 ==> start next bytecode. */
ef0d8ffc 180 uint32_t type = INSTR (14, 0);
2e8cf49e
NC
181
182 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
183
184 switch (type)
185 {
186 case 0:
187 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
188 aarch64_get_reg_u64 (cpu, R22, 0)); */
189 break;
190 case 1:
191 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
192 aarch64_get_reg_u64 (cpu, R22, 0)); */
193 break;
194 case 2:
195 /* aarch64_notifyMethodExit (); */
196 break;
197 case 3:
198 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
199 aarch64_get_reg_u64 (cpu, R22, 0)); */
200 break;
201 }
202}
203
204/* secondary decode within top level groups */
205
206static void
207dexPseudo (sim_cpu *cpu)
208{
209 /* assert instr[28,27] = 00
210
211 We provide 2 pseudo instructions:
212
213 HALT stops execution of the simulator causing an immediate
214 return to the x86 code which entered it.
215
216 CALLOUT initiates recursive entry into x86 code. A register
217 argument holds the address of the x86 routine. Immediate
218 values in the instruction identify the number of general
219 purpose and floating point register arguments to be passed
220 and the type of any value to be returned. */
221
222 uint32_t PSEUDO_HALT = 0xE0000000U;
223 uint32_t PSEUDO_CALLOUT = 0x00018000U;
224 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
225 uint32_t PSEUDO_NOTIFY = 0x00014000U;
226 uint32_t dispatch;
227
228 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
229 {
230 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
231 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
232 sim_stopped, SIM_SIGTRAP);
233 }
234
ef0d8ffc 235 dispatch = INSTR (31, 15);
2e8cf49e
NC
236
237 /* We do not handle callouts at the moment. */
238 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
239 {
240 TRACE_EVENTS (cpu, " Callout");
241 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
242 sim_stopped, SIM_SIGABRT);
243 }
244
245 else if (dispatch == PSEUDO_NOTIFY)
246 dexNotify (cpu);
247
248 else
249 HALT_UNALLOC;
250}
251
252/* Load-store single register (unscaled offset)
253 These instructions employ a base register plus an unscaled signed
254 9 bit offset.
255
256 N.B. the base register (source) can be Xn or SP. all other
257 registers may not be SP. */
258
259/* 32 bit load 32 bit unscaled signed 9 bit. */
260static void
261ldur32 (sim_cpu *cpu, int32_t offset)
262{
ef0d8ffc
NC
263 unsigned rn = INSTR (9, 5);
264 unsigned rt = INSTR (4, 0);
2e8cf49e 265
2cdad34c 266 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
267 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
268 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
269 + offset));
270}
271
272/* 64 bit load 64 bit unscaled signed 9 bit. */
273static void
274ldur64 (sim_cpu *cpu, int32_t offset)
275{
ef0d8ffc
NC
276 unsigned rn = INSTR (9, 5);
277 unsigned rt = INSTR (4, 0);
2e8cf49e 278
2cdad34c 279 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
280 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
281 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
282 + offset));
283}
284
285/* 32 bit load zero-extended byte unscaled signed 9 bit. */
286static void
287ldurb32 (sim_cpu *cpu, int32_t offset)
288{
ef0d8ffc
NC
289 unsigned rn = INSTR (9, 5);
290 unsigned rt = INSTR (4, 0);
2e8cf49e 291
2cdad34c 292 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
293 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
294 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
295 + offset));
296}
297
298/* 32 bit load sign-extended byte unscaled signed 9 bit. */
299static void
300ldursb32 (sim_cpu *cpu, int32_t offset)
301{
ef0d8ffc
NC
302 unsigned rn = INSTR (9, 5);
303 unsigned rt = INSTR (4, 0);
2e8cf49e 304
2cdad34c 305 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
306 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
307 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
308 + offset));
309}
310
311/* 64 bit load sign-extended byte unscaled signed 9 bit. */
312static void
313ldursb64 (sim_cpu *cpu, int32_t offset)
314{
ef0d8ffc
NC
315 unsigned rn = INSTR (9, 5);
316 unsigned rt = INSTR (4, 0);
2e8cf49e 317
2cdad34c 318 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
319 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
320 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
321 + offset));
322}
323
324/* 32 bit load zero-extended short unscaled signed 9 bit */
325static void
326ldurh32 (sim_cpu *cpu, int32_t offset)
327{
ef0d8ffc
NC
328 unsigned rn = INSTR (9, 5);
329 unsigned rd = INSTR (4, 0);
2e8cf49e 330
2cdad34c 331 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
332 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
333 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
334 + offset));
335}
336
337/* 32 bit load sign-extended short unscaled signed 9 bit */
338static void
339ldursh32 (sim_cpu *cpu, int32_t offset)
340{
ef0d8ffc
NC
341 unsigned rn = INSTR (9, 5);
342 unsigned rd = INSTR (4, 0);
2e8cf49e 343
2cdad34c 344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
345 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
346 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
347 + offset));
348}
349
350/* 64 bit load sign-extended short unscaled signed 9 bit */
351static void
352ldursh64 (sim_cpu *cpu, int32_t offset)
353{
ef0d8ffc
NC
354 unsigned rn = INSTR (9, 5);
355 unsigned rt = INSTR (4, 0);
2e8cf49e 356
2cdad34c 357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
358 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
359 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
360 + offset));
361}
362
363/* 64 bit load sign-extended word unscaled signed 9 bit */
364static void
365ldursw (sim_cpu *cpu, int32_t offset)
366{
ef0d8ffc
NC
367 unsigned rn = INSTR (9, 5);
368 unsigned rd = INSTR (4, 0);
2e8cf49e 369
2cdad34c 370 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
371 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
372 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
373 + offset));
374}
375
376/* N.B. with stores the value in source is written to the address
377 identified by source2 modified by offset. */
378
379/* 32 bit store 32 bit unscaled signed 9 bit. */
380static void
381stur32 (sim_cpu *cpu, int32_t offset)
382{
ef0d8ffc
NC
383 unsigned rn = INSTR (9, 5);
384 unsigned rd = INSTR (4, 0);
2e8cf49e 385
2cdad34c 386 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
387 aarch64_set_mem_u32 (cpu,
388 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
389 aarch64_get_reg_u32 (cpu, rd, NO_SP));
390}
391
392/* 64 bit store 64 bit unscaled signed 9 bit */
393static void
394stur64 (sim_cpu *cpu, int32_t offset)
395{
ef0d8ffc
NC
396 unsigned rn = INSTR (9, 5);
397 unsigned rd = INSTR (4, 0);
2e8cf49e 398
2cdad34c 399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
400 aarch64_set_mem_u64 (cpu,
401 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
402 aarch64_get_reg_u64 (cpu, rd, NO_SP));
403}
404
405/* 32 bit store byte unscaled signed 9 bit */
406static void
407sturb (sim_cpu *cpu, int32_t offset)
408{
ef0d8ffc
NC
409 unsigned rn = INSTR (9, 5);
410 unsigned rd = INSTR (4, 0);
2e8cf49e 411
2cdad34c 412 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
413 aarch64_set_mem_u8 (cpu,
414 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
415 aarch64_get_reg_u8 (cpu, rd, NO_SP));
416}
417
418/* 32 bit store short unscaled signed 9 bit */
419static void
420sturh (sim_cpu *cpu, int32_t offset)
421{
ef0d8ffc
NC
422 unsigned rn = INSTR (9, 5);
423 unsigned rd = INSTR (4, 0);
2e8cf49e 424
2cdad34c 425 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
426 aarch64_set_mem_u16 (cpu,
427 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
428 aarch64_get_reg_u16 (cpu, rd, NO_SP));
429}
430
431/* Load single register pc-relative label
432 Offset is a signed 19 bit immediate count in words
433 rt may not be SP. */
434
435/* 32 bit pc-relative load */
436static void
437ldr32_pcrel (sim_cpu *cpu, int32_t offset)
438{
ef0d8ffc 439 unsigned rd = INSTR (4, 0);
2e8cf49e 440
2cdad34c 441 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
442 aarch64_set_reg_u64 (cpu, rd, NO_SP,
443 aarch64_get_mem_u32
444 (cpu, aarch64_get_PC (cpu) + offset * 4));
445}
446
447/* 64 bit pc-relative load */
448static void
449ldr_pcrel (sim_cpu *cpu, int32_t offset)
450{
ef0d8ffc 451 unsigned rd = INSTR (4, 0);
2e8cf49e 452
2cdad34c 453 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
454 aarch64_set_reg_u64 (cpu, rd, NO_SP,
455 aarch64_get_mem_u64
456 (cpu, aarch64_get_PC (cpu) + offset * 4));
457}
458
459/* sign extended 32 bit pc-relative load */
460static void
461ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
462{
ef0d8ffc 463 unsigned rd = INSTR (4, 0);
2e8cf49e 464
2cdad34c 465 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
466 aarch64_set_reg_u64 (cpu, rd, NO_SP,
467 aarch64_get_mem_s32
468 (cpu, aarch64_get_PC (cpu) + offset * 4));
469}
470
471/* float pc-relative load */
472static void
473fldrs_pcrel (sim_cpu *cpu, int32_t offset)
474{
ef0d8ffc 475 unsigned int rd = INSTR (4, 0);
2e8cf49e 476
2cdad34c 477 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
478 aarch64_set_vec_u32 (cpu, rd, 0,
479 aarch64_get_mem_u32
480 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
481}
482
483/* double pc-relative load */
484static void
485fldrd_pcrel (sim_cpu *cpu, int32_t offset)
486{
ef0d8ffc 487 unsigned int st = INSTR (4, 0);
2e8cf49e 488
2cdad34c 489 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
490 aarch64_set_vec_u64 (cpu, st, 0,
491 aarch64_get_mem_u64
492 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
493}
494
495/* long double pc-relative load. */
496static void
497fldrq_pcrel (sim_cpu *cpu, int32_t offset)
498{
ef0d8ffc 499 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
500 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
501 FRegister a;
502
2cdad34c 503 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
504 aarch64_get_mem_long_double (cpu, addr, & a);
505 aarch64_set_FP_long_double (cpu, st, a);
506}
507
508/* This can be used to scale an offset by applying
509 the requisite shift. the second argument is either
510 16, 32 or 64. */
511
512#define SCALE(_offset, _elementSize) \
513 ((_offset) << ScaleShift ## _elementSize)
514
515/* This can be used to optionally scale a register derived offset
516 by applying the requisite shift as indicated by the Scaling
7517e550 517 argument. The second argument is either Byte, Short, Word
2e8cf49e
NC
518 or Long. The third argument is either Scaled or Unscaled.
519 N.B. when _Scaling is Scaled the shift gets ANDed with
520 all 1s while when it is Unscaled it gets ANDed with 0. */
521
522#define OPT_SCALE(_offset, _elementType, _Scaling) \
523 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
524
525/* This can be used to zero or sign extend a 32 bit register derived
526 value to a 64 bit value. the first argument must be the value as
527 a uint32_t and the second must be either UXTW or SXTW. The result
528 is returned as an int64_t. */
529
530static inline int64_t
531extend (uint32_t value, Extension extension)
532{
533 union
534 {
535 uint32_t u;
536 int32_t n;
537 } x;
538
539 /* A branchless variant of this ought to be possible. */
540 if (extension == UXTW || extension == NoExtension)
541 return value;
542
543 x.u = value;
544 return x.n;
545}
546
547/* Scalar Floating Point
548
549 FP load/store single register (4 addressing modes)
550
551 N.B. the base register (source) can be the stack pointer.
552 The secondary source register (source2) can only be an Xn register. */
553
554/* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
555static void
556fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
557{
ef0d8ffc
NC
558 unsigned rn = INSTR (9, 5);
559 unsigned st = INSTR (4, 0);
2e8cf49e
NC
560 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
561
562 if (wb != Post)
563 address += offset;
564
2cdad34c 565 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 566 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
2e8cf49e
NC
567 if (wb == Post)
568 address += offset;
569
570 if (wb != NoWriteBack)
571 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
572}
573
5ab6d79e
NC
574/* Load 8 bit with unsigned 12 bit offset. */
575static void
576fldrb_abs (sim_cpu *cpu, uint32_t offset)
577{
ef0d8ffc
NC
578 unsigned rd = INSTR (4, 0);
579 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
580 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
581
2cdad34c 582 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
583 aarch64_set_vec_u8 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
584}
585
586/* Load 16 bit scaled unsigned 12 bit. */
587static void
588fldrh_abs (sim_cpu *cpu, uint32_t offset)
589{
ef0d8ffc
NC
590 unsigned rd = INSTR (4, 0);
591 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
592 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16);
593
2cdad34c 594 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
595 aarch64_set_vec_u16 (cpu, rd, 0, aarch64_get_mem_u16 (cpu, addr));
596}
597
2e8cf49e
NC
598/* Load 32 bit scaled unsigned 12 bit. */
599static void
600fldrs_abs (sim_cpu *cpu, uint32_t offset)
601{
ef0d8ffc
NC
602 unsigned rd = INSTR (4, 0);
603 unsigned rn = INSTR (9, 5);
5ab6d79e 604 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32);
2e8cf49e 605
2cdad34c 606 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
607 aarch64_set_vec_u32 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
608}
609
610/* Load 64 bit scaled unsigned 12 bit. */
611static void
612fldrd_abs (sim_cpu *cpu, uint32_t offset)
613{
ef0d8ffc
NC
614 unsigned rd = INSTR (4, 0);
615 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
616 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
617
2cdad34c 618 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
619 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
620}
621
622/* Load 128 bit scaled unsigned 12 bit. */
623static void
624fldrq_abs (sim_cpu *cpu, uint32_t offset)
625{
ef0d8ffc
NC
626 unsigned rd = INSTR (4, 0);
627 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
628 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
629
2cdad34c 630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
631 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
632 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_mem_u64 (cpu, addr + 8));
2e8cf49e
NC
633}
634
635/* Load 32 bit scaled or unscaled zero- or sign-extended
636 32-bit register offset. */
637static void
638fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
639{
ef0d8ffc
NC
640 unsigned rm = INSTR (20, 16);
641 unsigned rn = INSTR (9, 5);
642 unsigned st = INSTR (4, 0);
2e8cf49e
NC
643 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
644 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
645 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
646
2cdad34c 647 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
648 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
649 (cpu, address + displacement));
2e8cf49e
NC
650}
651
652/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
653static void
654fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
655{
ef0d8ffc
NC
656 unsigned rn = INSTR (9, 5);
657 unsigned st = INSTR (4, 0);
2e8cf49e
NC
658 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
659
660 if (wb != Post)
661 address += offset;
662
2cdad34c 663 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 664 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
665
666 if (wb == Post)
667 address += offset;
668
669 if (wb != NoWriteBack)
670 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
671}
672
2e8cf49e
NC
673/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
674static void
675fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
676{
ef0d8ffc 677 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
678 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
679 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
680
681 fldrd_wb (cpu, displacement, NoWriteBack);
682}
683
684/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
685static void
686fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
687{
688 FRegister a;
ef0d8ffc
NC
689 unsigned rn = INSTR (9, 5);
690 unsigned st = INSTR (4, 0);
2e8cf49e
NC
691 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
692
693 if (wb != Post)
694 address += offset;
695
2cdad34c 696 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
697 aarch64_get_mem_long_double (cpu, address, & a);
698 aarch64_set_FP_long_double (cpu, st, a);
699
700 if (wb == Post)
701 address += offset;
702
703 if (wb != NoWriteBack)
704 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
705}
706
2e8cf49e
NC
707/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
708static void
709fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
710{
ef0d8ffc 711 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
712 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
713 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
714
715 fldrq_wb (cpu, displacement, NoWriteBack);
716}
717
718/* Memory Access
719
720 load-store single register
721 There are four addressing modes available here which all employ a
722 64 bit source (base) register.
723
724 N.B. the base register (source) can be the stack pointer.
725 The secondary source register (source2)can only be an Xn register.
726
727 Scaled, 12-bit, unsigned immediate offset, without pre- and
728 post-index options.
729 Unscaled, 9-bit, signed immediate offset with pre- or post-index
730 writeback.
731 scaled or unscaled 64-bit register offset.
732 scaled or unscaled 32-bit extended register offset.
733
734 All offsets are assumed to be raw from the decode i.e. the
735 simulator is expected to adjust scaled offsets based on the
736 accessed data size with register or extended register offset
737 versions the same applies except that in the latter case the
738 operation may also require a sign extend.
739
740 A separate method is provided for each possible addressing mode. */
741
742/* 32 bit load 32 bit scaled unsigned 12 bit */
743static void
744ldr32_abs (sim_cpu *cpu, uint32_t offset)
745{
ef0d8ffc
NC
746 unsigned rn = INSTR (9, 5);
747 unsigned rt = INSTR (4, 0);
2e8cf49e 748
2cdad34c 749 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
750 /* The target register may not be SP but the source may be. */
751 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
752 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
753 + SCALE (offset, 32)));
754}
755
756/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
757static void
758ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
759{
ef0d8ffc
NC
760 unsigned rn = INSTR (9, 5);
761 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
762 uint64_t address;
763
764 if (rn == rt && wb != NoWriteBack)
765 HALT_UNALLOC;
766
767 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
768
769 if (wb != Post)
770 address += offset;
771
2cdad34c 772 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
773 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
774
775 if (wb == Post)
776 address += offset;
777
778 if (wb != NoWriteBack)
779 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
780}
781
782/* 32 bit load 32 bit scaled or unscaled
783 zero- or sign-extended 32-bit register offset */
784static void
785ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
786{
ef0d8ffc
NC
787 unsigned rm = INSTR (20, 16);
788 unsigned rn = INSTR (9, 5);
789 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
790 /* rn may reference SP, rm and rt must reference ZR */
791
792 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
793 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
794 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
795
2cdad34c 796 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
797 aarch64_set_reg_u64 (cpu, rt, NO_SP,
798 aarch64_get_mem_u32 (cpu, address + displacement));
799}
800
801/* 64 bit load 64 bit scaled unsigned 12 bit */
802static void
803ldr_abs (sim_cpu *cpu, uint32_t offset)
804{
ef0d8ffc
NC
805 unsigned rn = INSTR (9, 5);
806 unsigned rt = INSTR (4, 0);
2e8cf49e 807
2cdad34c 808 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
809 /* The target register may not be SP but the source may be. */
810 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
811 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
812 + SCALE (offset, 64)));
813}
814
815/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
816static void
817ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
818{
ef0d8ffc
NC
819 unsigned rn = INSTR (9, 5);
820 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
821 uint64_t address;
822
823 if (rn == rt && wb != NoWriteBack)
824 HALT_UNALLOC;
825
826 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
827
828 if (wb != Post)
829 address += offset;
830
2cdad34c 831 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
832 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
833
834 if (wb == Post)
835 address += offset;
836
837 if (wb != NoWriteBack)
838 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
839}
840
841/* 64 bit load 64 bit scaled or unscaled zero-
842 or sign-extended 32-bit register offset. */
843static void
844ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
845{
ef0d8ffc
NC
846 unsigned rm = INSTR (20, 16);
847 unsigned rn = INSTR (9, 5);
848 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
849 /* rn may reference SP, rm and rt must reference ZR */
850
851 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
852 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
853 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
854
2cdad34c 855 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
856 aarch64_set_reg_u64 (cpu, rt, NO_SP,
857 aarch64_get_mem_u64 (cpu, address + displacement));
858}
859
860/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
861static void
862ldrb32_abs (sim_cpu *cpu, uint32_t offset)
863{
ef0d8ffc
NC
864 unsigned rn = INSTR (9, 5);
865 unsigned rt = INSTR (4, 0);
2e8cf49e 866
2cdad34c 867 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
868 /* The target register may not be SP but the source may be
869 there is no scaling required for a byte load. */
870 aarch64_set_reg_u64 (cpu, rt, NO_SP,
871 aarch64_get_mem_u8
872 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
873}
874
875/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
876static void
877ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
878{
ef0d8ffc
NC
879 unsigned rn = INSTR (9, 5);
880 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
881 uint64_t address;
882
883 if (rn == rt && wb != NoWriteBack)
884 HALT_UNALLOC;
885
886 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
887
888 if (wb != Post)
889 address += offset;
890
2cdad34c 891 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
892 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
893
894 if (wb == Post)
895 address += offset;
896
897 if (wb != NoWriteBack)
898 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
899}
900
901/* 32 bit load zero-extended byte scaled or unscaled zero-
902 or sign-extended 32-bit register offset. */
903static void
904ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
905{
ef0d8ffc
NC
906 unsigned rm = INSTR (20, 16);
907 unsigned rn = INSTR (9, 5);
908 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
909 /* rn may reference SP, rm and rt must reference ZR */
910
911 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
912 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
913 extension);
914
2cdad34c 915 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
916 /* There is no scaling required for a byte load. */
917 aarch64_set_reg_u64 (cpu, rt, NO_SP,
918 aarch64_get_mem_u8 (cpu, address + displacement));
919}
920
921/* 64 bit load sign-extended byte unscaled signed 9 bit
922 with pre- or post-writeback. */
923static void
924ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
925{
ef0d8ffc
NC
926 unsigned rn = INSTR (9, 5);
927 unsigned rt = INSTR (4, 0);
2e8cf49e 928 uint64_t address;
7517e550 929 int64_t val;
2e8cf49e
NC
930
931 if (rn == rt && wb != NoWriteBack)
932 HALT_UNALLOC;
933
934 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
935
936 if (wb != Post)
937 address += offset;
938
2cdad34c 939 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
940 val = aarch64_get_mem_s8 (cpu, address);
941 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
942
943 if (wb == Post)
944 address += offset;
945
946 if (wb != NoWriteBack)
947 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
948}
949
950/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
951static void
952ldrsb_abs (sim_cpu *cpu, uint32_t offset)
953{
954 ldrsb_wb (cpu, offset, NoWriteBack);
955}
956
957/* 64 bit load sign-extended byte scaled or unscaled zero-
958 or sign-extended 32-bit register offset. */
959static void
960ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
961{
ef0d8ffc
NC
962 unsigned rm = INSTR (20, 16);
963 unsigned rn = INSTR (9, 5);
964 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
965 /* rn may reference SP, rm and rt must reference ZR */
966
967 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
968 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
969 extension);
2cdad34c 970 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 971 /* There is no scaling required for a byte load. */
7517e550 972 aarch64_set_reg_s64 (cpu, rt, NO_SP,
2e8cf49e
NC
973 aarch64_get_mem_s8 (cpu, address + displacement));
974}
975
976/* 32 bit load zero-extended short scaled unsigned 12 bit. */
977static void
978ldrh32_abs (sim_cpu *cpu, uint32_t offset)
979{
ef0d8ffc
NC
980 unsigned rn = INSTR (9, 5);
981 unsigned rt = INSTR (4, 0);
7517e550 982 uint32_t val;
2e8cf49e 983
2cdad34c 984 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 985 /* The target register may not be SP but the source may be. */
7517e550
NC
986 val = aarch64_get_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
987 + SCALE (offset, 16));
988 aarch64_set_reg_u32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
989}
990
991/* 32 bit load zero-extended short unscaled signed 9 bit
992 with pre- or post-writeback. */
993static void
994ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
995{
ef0d8ffc
NC
996 unsigned rn = INSTR (9, 5);
997 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
998 uint64_t address;
999
1000 if (rn == rt && wb != NoWriteBack)
1001 HALT_UNALLOC;
1002
1003 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1004
1005 if (wb != Post)
1006 address += offset;
1007
2cdad34c 1008 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1009 aarch64_set_reg_u32 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
2e8cf49e
NC
1010
1011 if (wb == Post)
1012 address += offset;
1013
1014 if (wb != NoWriteBack)
1015 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1016}
1017
1018/* 32 bit load zero-extended short scaled or unscaled zero-
1019 or sign-extended 32-bit register offset. */
1020static void
1021ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1022{
ef0d8ffc
NC
1023 unsigned rm = INSTR (20, 16);
1024 unsigned rn = INSTR (9, 5);
1025 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1026 /* rn may reference SP, rm and rt must reference ZR */
1027
1028 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1029 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1030 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1031
2cdad34c 1032 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1033 aarch64_set_reg_u32 (cpu, rt, NO_SP,
2e8cf49e
NC
1034 aarch64_get_mem_u16 (cpu, address + displacement));
1035}
1036
1037/* 32 bit load sign-extended short scaled unsigned 12 bit. */
1038static void
1039ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
1040{
ef0d8ffc
NC
1041 unsigned rn = INSTR (9, 5);
1042 unsigned rt = INSTR (4, 0);
7517e550 1043 int32_t val;
2e8cf49e 1044
2cdad34c 1045 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1046 /* The target register may not be SP but the source may be. */
7517e550
NC
1047 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1048 + SCALE (offset, 16));
1049 aarch64_set_reg_s32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1050}
1051
1052/* 32 bit load sign-extended short unscaled signed 9 bit
1053 with pre- or post-writeback. */
1054static void
1055ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1056{
ef0d8ffc
NC
1057 unsigned rn = INSTR (9, 5);
1058 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1059 uint64_t address;
1060
1061 if (rn == rt && wb != NoWriteBack)
1062 HALT_UNALLOC;
1063
1064 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1065
1066 if (wb != Post)
1067 address += offset;
1068
2cdad34c 1069 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1070 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1071 (int32_t) aarch64_get_mem_s16 (cpu, address));
2e8cf49e
NC
1072
1073 if (wb == Post)
1074 address += offset;
1075
1076 if (wb != NoWriteBack)
1077 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1078}
1079
1080/* 32 bit load sign-extended short scaled or unscaled zero-
1081 or sign-extended 32-bit register offset. */
1082static void
1083ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1084{
ef0d8ffc
NC
1085 unsigned rm = INSTR (20, 16);
1086 unsigned rn = INSTR (9, 5);
1087 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1088 /* rn may reference SP, rm and rt must reference ZR */
1089
1090 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1091 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1092 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1093
2cdad34c 1094 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1095 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1096 (int32_t) aarch64_get_mem_s16
2e8cf49e
NC
1097 (cpu, address + displacement));
1098}
1099
1100/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1101static void
1102ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1103{
ef0d8ffc
NC
1104 unsigned rn = INSTR (9, 5);
1105 unsigned rt = INSTR (4, 0);
7517e550 1106 int64_t val;
2e8cf49e 1107
2cdad34c 1108 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1109 /* The target register may not be SP but the source may be. */
7517e550
NC
1110 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1111 + SCALE (offset, 16));
1112 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1113}
1114
1115/* 64 bit load sign-extended short unscaled signed 9 bit
1116 with pre- or post-writeback. */
1117static void
1118ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1119{
ef0d8ffc
NC
1120 unsigned rn = INSTR (9, 5);
1121 unsigned rt = INSTR (4, 0);
2e8cf49e 1122 uint64_t address;
7517e550 1123 int64_t val;
2e8cf49e
NC
1124
1125 if (rn == rt && wb != NoWriteBack)
1126 HALT_UNALLOC;
1127
2cdad34c 1128 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1129 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1130
1131 if (wb != Post)
1132 address += offset;
1133
7517e550
NC
1134 val = aarch64_get_mem_s16 (cpu, address);
1135 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1136
1137 if (wb == Post)
1138 address += offset;
1139
1140 if (wb != NoWriteBack)
1141 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1142}
1143
1144/* 64 bit load sign-extended short scaled or unscaled zero-
1145 or sign-extended 32-bit register offset. */
1146static void
1147ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1148{
ef0d8ffc
NC
1149 unsigned rm = INSTR (20, 16);
1150 unsigned rn = INSTR (9, 5);
1151 unsigned rt = INSTR (4, 0);
7517e550 1152
2e8cf49e
NC
1153 /* rn may reference SP, rm and rt must reference ZR */
1154
1155 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1156 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1157 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
7517e550 1158 int64_t val;
2e8cf49e 1159
2cdad34c 1160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1161 val = aarch64_get_mem_s16 (cpu, address + displacement);
1162 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1163}
1164
1165/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1166static void
1167ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1168{
ef0d8ffc
NC
1169 unsigned rn = INSTR (9, 5);
1170 unsigned rt = INSTR (4, 0);
7517e550 1171 int64_t val;
2e8cf49e 1172
2cdad34c 1173 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1174 val = aarch64_get_mem_s32 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1175 + SCALE (offset, 32));
2e8cf49e 1176 /* The target register may not be SP but the source may be. */
7517e550 1177 return aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1178}
1179
1180/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1181 with pre- or post-writeback. */
1182static void
1183ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1184{
ef0d8ffc
NC
1185 unsigned rn = INSTR (9, 5);
1186 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1187 uint64_t address;
1188
1189 if (rn == rt && wb != NoWriteBack)
1190 HALT_UNALLOC;
1191
1192 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1193
1194 if (wb != Post)
1195 address += offset;
1196
2cdad34c 1197 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1198 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1199
1200 if (wb == Post)
1201 address += offset;
1202
1203 if (wb != NoWriteBack)
1204 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1205}
1206
1207/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1208 or sign-extended 32-bit register offset. */
1209static void
1210ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1211{
ef0d8ffc
NC
1212 unsigned rm = INSTR (20, 16);
1213 unsigned rn = INSTR (9, 5);
1214 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1215 /* rn may reference SP, rm and rt must reference ZR */
1216
1217 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1218 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1219 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1220
2cdad34c 1221 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1222 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1223 aarch64_get_mem_s32 (cpu, address + displacement));
1224}
1225
1226/* N.B. with stores the value in source is written to the
1227 address identified by source2 modified by source3/offset. */
1228
1229/* 32 bit store scaled unsigned 12 bit. */
1230static void
1231str32_abs (sim_cpu *cpu, uint32_t offset)
1232{
ef0d8ffc
NC
1233 unsigned rn = INSTR (9, 5);
1234 unsigned rt = INSTR (4, 0);
2e8cf49e 1235
2cdad34c 1236 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1237 /* The target register may not be SP but the source may be. */
1238 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1239 + SCALE (offset, 32)),
1240 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1241}
1242
1243/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1244static void
1245str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1246{
ef0d8ffc
NC
1247 unsigned rn = INSTR (9, 5);
1248 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1249 uint64_t address;
1250
1251 if (rn == rt && wb != NoWriteBack)
1252 HALT_UNALLOC;
1253
1254 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1255 if (wb != Post)
1256 address += offset;
1257
2cdad34c 1258 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1259 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1260
1261 if (wb == Post)
1262 address += offset;
1263
1264 if (wb != NoWriteBack)
1265 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1266}
1267
1268/* 32 bit store scaled or unscaled zero- or
1269 sign-extended 32-bit register offset. */
1270static void
1271str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1272{
ef0d8ffc
NC
1273 unsigned rm = INSTR (20, 16);
1274 unsigned rn = INSTR (9, 5);
1275 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1276
1277 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1278 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1279 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1280
2cdad34c 1281 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1282 aarch64_set_mem_u32 (cpu, address + displacement,
1283 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1284}
1285
1286/* 64 bit store scaled unsigned 12 bit. */
1287static void
1288str_abs (sim_cpu *cpu, uint32_t offset)
1289{
ef0d8ffc
NC
1290 unsigned rn = INSTR (9, 5);
1291 unsigned rt = INSTR (4, 0);
2e8cf49e 1292
2cdad34c 1293 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1294 aarch64_set_mem_u64 (cpu,
1295 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1296 + SCALE (offset, 64),
1297 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1298}
1299
1300/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1301static void
1302str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1303{
ef0d8ffc
NC
1304 unsigned rn = INSTR (9, 5);
1305 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1306 uint64_t address;
1307
1308 if (rn == rt && wb != NoWriteBack)
1309 HALT_UNALLOC;
1310
1311 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1312
1313 if (wb != Post)
1314 address += offset;
1315
2cdad34c 1316 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1317 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1318
1319 if (wb == Post)
1320 address += offset;
1321
1322 if (wb != NoWriteBack)
1323 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1324}
1325
1326/* 64 bit store scaled or unscaled zero-
1327 or sign-extended 32-bit register offset. */
1328static void
1329str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1330{
ef0d8ffc
NC
1331 unsigned rm = INSTR (20, 16);
1332 unsigned rn = INSTR (9, 5);
1333 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1334 /* rn may reference SP, rm and rt must reference ZR */
1335
1336 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1337 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1338 extension);
1339 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1340
2cdad34c 1341 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1342 aarch64_set_mem_u64 (cpu, address + displacement,
1343 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1344}
1345
1346/* 32 bit store byte scaled unsigned 12 bit. */
1347static void
1348strb_abs (sim_cpu *cpu, uint32_t offset)
1349{
ef0d8ffc
NC
1350 unsigned rn = INSTR (9, 5);
1351 unsigned rt = INSTR (4, 0);
2e8cf49e 1352
2cdad34c 1353 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1354 /* The target register may not be SP but the source may be.
1355 There is no scaling required for a byte load. */
1356 aarch64_set_mem_u8 (cpu,
1357 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1358 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1359}
1360
1361/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1362static void
1363strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1364{
ef0d8ffc
NC
1365 unsigned rn = INSTR (9, 5);
1366 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1367 uint64_t address;
1368
1369 if (rn == rt && wb != NoWriteBack)
1370 HALT_UNALLOC;
1371
1372 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1373
1374 if (wb != Post)
1375 address += offset;
1376
2cdad34c 1377 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1378 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1379
1380 if (wb == Post)
1381 address += offset;
1382
1383 if (wb != NoWriteBack)
1384 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1385}
1386
1387/* 32 bit store byte scaled or unscaled zero-
1388 or sign-extended 32-bit register offset. */
1389static void
1390strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1391{
ef0d8ffc
NC
1392 unsigned rm = INSTR (20, 16);
1393 unsigned rn = INSTR (9, 5);
1394 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1395 /* rn may reference SP, rm and rt must reference ZR */
1396
1397 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1398 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1399 extension);
1400
2cdad34c 1401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1402 /* There is no scaling required for a byte load. */
1403 aarch64_set_mem_u8 (cpu, address + displacement,
1404 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1405}
1406
1407/* 32 bit store short scaled unsigned 12 bit. */
1408static void
1409strh_abs (sim_cpu *cpu, uint32_t offset)
1410{
ef0d8ffc
NC
1411 unsigned rn = INSTR (9, 5);
1412 unsigned rt = INSTR (4, 0);
2e8cf49e 1413
2cdad34c 1414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1415 /* The target register may not be SP but the source may be. */
1416 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1417 + SCALE (offset, 16),
1418 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1419}
1420
1421/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1422static void
1423strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1424{
ef0d8ffc
NC
1425 unsigned rn = INSTR (9, 5);
1426 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1427 uint64_t address;
1428
1429 if (rn == rt && wb != NoWriteBack)
1430 HALT_UNALLOC;
1431
1432 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1433
1434 if (wb != Post)
1435 address += offset;
1436
2cdad34c 1437 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1438 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1439
1440 if (wb == Post)
1441 address += offset;
1442
1443 if (wb != NoWriteBack)
1444 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1445}
1446
1447/* 32 bit store short scaled or unscaled zero-
1448 or sign-extended 32-bit register offset. */
1449static void
1450strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1451{
ef0d8ffc
NC
1452 unsigned rm = INSTR (20, 16);
1453 unsigned rn = INSTR (9, 5);
1454 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1455 /* rn may reference SP, rm and rt must reference ZR */
1456
1457 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1458 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1459 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1460
2cdad34c 1461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1462 aarch64_set_mem_u16 (cpu, address + displacement,
1463 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1464}
1465
1466/* Prefetch unsigned 12 bit. */
1467static void
1468prfm_abs (sim_cpu *cpu, uint32_t offset)
1469{
1470 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1471 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1472 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1473 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1474 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1475 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1476 ow ==> UNALLOC
ef0d8ffc 1477 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1478 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1479 + SCALE (offset, 64). */
1480
1481 /* TODO : implement prefetch of address. */
1482}
1483
1484/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1485static void
1486prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1487{
1488 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1489 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1490 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1491 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1492 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1493 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1494 ow ==> UNALLOC
1495 rn may reference SP, rm may only reference ZR
ef0d8ffc 1496 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1497 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1498 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1499 extension);
1500 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1501 uint64_t address = base + displacement. */
1502
1503 /* TODO : implement prefetch of address */
1504}
1505
1506/* 64 bit pc-relative prefetch. */
1507static void
1508prfm_pcrel (sim_cpu *cpu, int32_t offset)
1509{
1510 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1511 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1512 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1513 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1514 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1515 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1516 ow ==> UNALLOC
ef0d8ffc 1517 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1518 uint64_t address = aarch64_get_PC (cpu) + offset. */
1519
1520 /* TODO : implement this */
1521}
1522
1523/* Load-store exclusive. */
1524
1525static void
1526ldxr (sim_cpu *cpu)
1527{
ef0d8ffc
NC
1528 unsigned rn = INSTR (9, 5);
1529 unsigned rt = INSTR (4, 0);
2e8cf49e 1530 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc
NC
1531 int size = INSTR (31, 30);
1532 /* int ordered = INSTR (15, 15); */
1533 /* int exclusive = ! INSTR (23, 23); */
2e8cf49e 1534
2cdad34c 1535 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1536 switch (size)
1537 {
1538 case 0:
1539 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1540 break;
1541 case 1:
1542 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1543 break;
1544 case 2:
1545 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1546 break;
1547 case 3:
1548 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1549 break;
2e8cf49e
NC
1550 }
1551}
1552
1553static void
1554stxr (sim_cpu *cpu)
1555{
ef0d8ffc
NC
1556 unsigned rn = INSTR (9, 5);
1557 unsigned rt = INSTR (4, 0);
1558 unsigned rs = INSTR (20, 16);
2e8cf49e 1559 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc 1560 int size = INSTR (31, 30);
2e8cf49e
NC
1561 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1562
1563 switch (size)
1564 {
1565 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1566 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1567 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1568 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
2e8cf49e
NC
1569 }
1570
2cdad34c 1571 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1572 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1573}
1574
1575static void
1576dexLoadLiteral (sim_cpu *cpu)
1577{
1578 /* instr[29,27] == 011
1579 instr[25,24] == 00
1580 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1581 010 ==> LDRX, 011 ==> FLDRD
1582 100 ==> LDRSW, 101 ==> FLDRQ
1583 110 ==> PRFM, 111 ==> UNALLOC
1584 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1585 instr[23, 5] == simm19 */
1586
ef0d8ffc 1587 /* unsigned rt = INSTR (4, 0); */
7517e550 1588 uint32_t dispatch = (INSTR (31, 30) << 1) | INSTR (26, 26);
2e8cf49e
NC
1589 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1590
1591 switch (dispatch)
1592 {
1593 case 0: ldr32_pcrel (cpu, imm); break;
1594 case 1: fldrs_pcrel (cpu, imm); break;
1595 case 2: ldr_pcrel (cpu, imm); break;
1596 case 3: fldrd_pcrel (cpu, imm); break;
1597 case 4: ldrsw_pcrel (cpu, imm); break;
1598 case 5: fldrq_pcrel (cpu, imm); break;
1599 case 6: prfm_pcrel (cpu, imm); break;
1600 case 7:
1601 default:
1602 HALT_UNALLOC;
1603 }
1604}
1605
1606/* Immediate arithmetic
1607 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1608 value left shifted by 12 bits (done at decode).
1609
1610 N.B. the register args (dest, source) can normally be Xn or SP.
1611 the exception occurs for flag setting instructions which may
1612 only use Xn for the output (dest). */
1613
1614/* 32 bit add immediate. */
1615static void
1616add32 (sim_cpu *cpu, uint32_t aimm)
1617{
ef0d8ffc
NC
1618 unsigned rn = INSTR (9, 5);
1619 unsigned rd = INSTR (4, 0);
2e8cf49e 1620
2cdad34c 1621 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1622 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1623 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1624}
1625
1626/* 64 bit add immediate. */
1627static void
1628add64 (sim_cpu *cpu, uint32_t aimm)
1629{
ef0d8ffc
NC
1630 unsigned rn = INSTR (9, 5);
1631 unsigned rd = INSTR (4, 0);
2e8cf49e 1632
2cdad34c 1633 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1634 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1635 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1636}
1637
1638static void
1639set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1640{
1641 int32_t result = value1 + value2;
1642 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1643 uint64_t uresult = (uint64_t)(uint32_t) value1
1644 + (uint64_t)(uint32_t) value2;
1645 uint32_t flags = 0;
1646
1647 if (result == 0)
1648 flags |= Z;
1649
1650 if (result & (1 << 31))
1651 flags |= N;
1652
1653 if (uresult != result)
1654 flags |= C;
1655
1656 if (sresult != result)
1657 flags |= V;
1658
1659 aarch64_set_CPSR (cpu, flags);
1660}
1661
963201cf
JW
1662#define NEG(a) (((a) & signbit) == signbit)
1663#define POS(a) (((a) & signbit) == 0)
1664
2e8cf49e
NC
1665static void
1666set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1667{
963201cf
JW
1668 uint64_t result = value1 + value2;
1669 uint32_t flags = 0;
1670 uint64_t signbit = 1ULL << 63;
2e8cf49e
NC
1671
1672 if (result == 0)
1673 flags |= Z;
1674
963201cf 1675 if (NEG (result))
2e8cf49e
NC
1676 flags |= N;
1677
963201cf
JW
1678 if ( (NEG (value1) && NEG (value2))
1679 || (NEG (value1) && POS (result))
1680 || (NEG (value2) && POS (result)))
1681 flags |= C;
1682
1683 if ( (NEG (value1) && NEG (value2) && POS (result))
1684 || (POS (value1) && POS (value2) && NEG (result)))
1685 flags |= V;
2e8cf49e
NC
1686
1687 aarch64_set_CPSR (cpu, flags);
1688}
1689
2e8cf49e
NC
1690static void
1691set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1692{
1693 uint32_t result = value1 - value2;
1694 uint32_t flags = 0;
57aa1742 1695 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1696
1697 if (result == 0)
1698 flags |= Z;
1699
1700 if (NEG (result))
1701 flags |= N;
1702
1703 if ( (NEG (value1) && POS (value2))
1704 || (NEG (value1) && POS (result))
1705 || (POS (value2) && POS (result)))
1706 flags |= C;
1707
1708 if ( (NEG (value1) && POS (value2) && POS (result))
1709 || (POS (value1) && NEG (value2) && NEG (result)))
1710 flags |= V;
1711
1712 aarch64_set_CPSR (cpu, flags);
1713}
1714
1715static void
1716set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1717{
1718 uint64_t result = value1 - value2;
1719 uint32_t flags = 0;
1720 uint64_t signbit = 1ULL << 63;
1721
1722 if (result == 0)
1723 flags |= Z;
1724
1725 if (NEG (result))
1726 flags |= N;
1727
1728 if ( (NEG (value1) && POS (value2))
1729 || (NEG (value1) && POS (result))
1730 || (POS (value2) && POS (result)))
1731 flags |= C;
1732
1733 if ( (NEG (value1) && POS (value2) && POS (result))
1734 || (POS (value1) && NEG (value2) && NEG (result)))
1735 flags |= V;
1736
1737 aarch64_set_CPSR (cpu, flags);
1738}
1739
1740static void
1741set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1742{
1743 uint32_t flags = 0;
1744
1745 if (result == 0)
1746 flags |= Z;
1747 else
1748 flags &= ~ Z;
1749
1750 if (result & (1 << 31))
1751 flags |= N;
1752 else
1753 flags &= ~ N;
1754
1755 aarch64_set_CPSR (cpu, flags);
1756}
1757
1758static void
1759set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1760{
1761 uint32_t flags = 0;
1762
1763 if (result == 0)
1764 flags |= Z;
1765 else
1766 flags &= ~ Z;
1767
1768 if (result & (1ULL << 63))
1769 flags |= N;
1770 else
1771 flags &= ~ N;
1772
1773 aarch64_set_CPSR (cpu, flags);
1774}
1775
1776/* 32 bit add immediate set flags. */
1777static void
1778adds32 (sim_cpu *cpu, uint32_t aimm)
1779{
ef0d8ffc
NC
1780 unsigned rn = INSTR (9, 5);
1781 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1782 /* TODO : do we need to worry about signs here? */
1783 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1784
2cdad34c 1785 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1786 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1787 set_flags_for_add32 (cpu, value1, aimm);
1788}
1789
1790/* 64 bit add immediate set flags. */
1791static void
1792adds64 (sim_cpu *cpu, uint32_t aimm)
1793{
ef0d8ffc
NC
1794 unsigned rn = INSTR (9, 5);
1795 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1796 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1797 uint64_t value2 = aimm;
1798
2cdad34c 1799 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1800 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1801 set_flags_for_add64 (cpu, value1, value2);
1802}
1803
1804/* 32 bit sub immediate. */
1805static void
1806sub32 (sim_cpu *cpu, uint32_t aimm)
1807{
ef0d8ffc
NC
1808 unsigned rn = INSTR (9, 5);
1809 unsigned rd = INSTR (4, 0);
2e8cf49e 1810
2cdad34c 1811 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1812 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1813 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1814}
1815
1816/* 64 bit sub immediate. */
1817static void
1818sub64 (sim_cpu *cpu, uint32_t aimm)
1819{
ef0d8ffc
NC
1820 unsigned rn = INSTR (9, 5);
1821 unsigned rd = INSTR (4, 0);
2e8cf49e 1822
2cdad34c 1823 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1824 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1825 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1826}
1827
1828/* 32 bit sub immediate set flags. */
1829static void
1830subs32 (sim_cpu *cpu, uint32_t aimm)
1831{
ef0d8ffc
NC
1832 unsigned rn = INSTR (9, 5);
1833 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1834 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1835 uint32_t value2 = aimm;
1836
2cdad34c 1837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1838 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1839 set_flags_for_sub32 (cpu, value1, value2);
1840}
1841
1842/* 64 bit sub immediate set flags. */
1843static void
1844subs64 (sim_cpu *cpu, uint32_t aimm)
1845{
ef0d8ffc
NC
1846 unsigned rn = INSTR (9, 5);
1847 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1848 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1849 uint32_t value2 = aimm;
1850
2cdad34c 1851 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1852 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1853 set_flags_for_sub64 (cpu, value1, value2);
1854}
1855
1856/* Data Processing Register. */
1857
1858/* First two helpers to perform the shift operations. */
1859
1860static inline uint32_t
1861shifted32 (uint32_t value, Shift shift, uint32_t count)
1862{
1863 switch (shift)
1864 {
1865 default:
1866 case LSL:
1867 return (value << count);
1868 case LSR:
1869 return (value >> count);
1870 case ASR:
1871 {
1872 int32_t svalue = value;
1873 return (svalue >> count);
1874 }
1875 case ROR:
1876 {
1877 uint32_t top = value >> count;
1878 uint32_t bottom = value << (32 - count);
1879 return (bottom | top);
1880 }
1881 }
1882}
1883
1884static inline uint64_t
1885shifted64 (uint64_t value, Shift shift, uint32_t count)
1886{
1887 switch (shift)
1888 {
1889 default:
1890 case LSL:
1891 return (value << count);
1892 case LSR:
1893 return (value >> count);
1894 case ASR:
1895 {
1896 int64_t svalue = value;
1897 return (svalue >> count);
1898 }
1899 case ROR:
1900 {
1901 uint64_t top = value >> count;
1902 uint64_t bottom = value << (64 - count);
1903 return (bottom | top);
1904 }
1905 }
1906}
1907
1908/* Arithmetic shifted register.
1909 These allow an optional LSL, ASR or LSR to the second source
1910 register with a count up to the register bit count.
1911
1912 N.B register args may not be SP. */
1913
1914/* 32 bit ADD shifted register. */
1915static void
1916add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1917{
ef0d8ffc
NC
1918 unsigned rm = INSTR (20, 16);
1919 unsigned rn = INSTR (9, 5);
1920 unsigned rd = INSTR (4, 0);
2e8cf49e 1921
2cdad34c 1922 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1923 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1924 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1925 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1926 shift, count));
1927}
1928
1929/* 64 bit ADD shifted register. */
1930static void
1931add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1932{
ef0d8ffc
NC
1933 unsigned rm = INSTR (20, 16);
1934 unsigned rn = INSTR (9, 5);
1935 unsigned rd = INSTR (4, 0);
2e8cf49e 1936
2cdad34c 1937 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1938 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1939 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1940 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1941 shift, count));
1942}
1943
1944/* 32 bit ADD shifted register setting flags. */
1945static void
1946adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1947{
ef0d8ffc
NC
1948 unsigned rm = INSTR (20, 16);
1949 unsigned rn = INSTR (9, 5);
1950 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1951
1952 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1953 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1954 shift, count);
1955
2cdad34c 1956 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1957 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1958 set_flags_for_add32 (cpu, value1, value2);
1959}
1960
1961/* 64 bit ADD shifted register setting flags. */
1962static void
1963adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1964{
ef0d8ffc
NC
1965 unsigned rm = INSTR (20, 16);
1966 unsigned rn = INSTR (9, 5);
1967 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1968
1969 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1970 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1971 shift, count);
1972
2cdad34c 1973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1974 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1975 set_flags_for_add64 (cpu, value1, value2);
1976}
1977
1978/* 32 bit SUB shifted register. */
1979static void
1980sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1981{
ef0d8ffc
NC
1982 unsigned rm = INSTR (20, 16);
1983 unsigned rn = INSTR (9, 5);
1984 unsigned rd = INSTR (4, 0);
2e8cf49e 1985
2cdad34c 1986 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1987 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1988 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1989 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1990 shift, count));
1991}
1992
1993/* 64 bit SUB shifted register. */
1994static void
1995sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1996{
ef0d8ffc
NC
1997 unsigned rm = INSTR (20, 16);
1998 unsigned rn = INSTR (9, 5);
1999 unsigned rd = INSTR (4, 0);
2e8cf49e 2000
2cdad34c 2001 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2002 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2003 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2004 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2005 shift, count));
2006}
2007
2008/* 32 bit SUB shifted register setting flags. */
2009static void
2010subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2011{
ef0d8ffc
NC
2012 unsigned rm = INSTR (20, 16);
2013 unsigned rn = INSTR (9, 5);
2014 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2015
2016 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2017 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
2018 shift, count);
2019
2cdad34c 2020 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2021 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2022 set_flags_for_sub32 (cpu, value1, value2);
2023}
2024
2025/* 64 bit SUB shifted register setting flags. */
2026static void
2027subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2028{
ef0d8ffc
NC
2029 unsigned rm = INSTR (20, 16);
2030 unsigned rn = INSTR (9, 5);
2031 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2032
2033 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2034 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2035 shift, count);
2036
2cdad34c 2037 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2038 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2039 set_flags_for_sub64 (cpu, value1, value2);
2040}
2041
2042/* First a couple more helpers to fetch the
2043 relevant source register element either
2044 sign or zero extended as required by the
2045 extension value. */
2046
2047static uint32_t
2048extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
2049{
2050 switch (extension)
2051 {
2052 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2053 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2054 case UXTW: /* Fall through. */
2055 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2056 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2057 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2058 case SXTW: /* Fall through. */
2059 case SXTX: /* Fall through. */
2060 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2061 }
2062}
2063
2064static uint64_t
2065extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
2066{
2067 switch (extension)
2068 {
2069 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2070 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2071 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2072 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2073 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2074 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2075 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2076 case SXTX:
2077 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2078 }
2079}
2080
2081/* Arithmetic extending register
2082 These allow an optional sign extension of some portion of the
2083 second source register followed by an optional left shift of
2084 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2085
2086 N.B output (dest) and first input arg (source) may normally be Xn
2087 or SP. However, for flag setting operations dest can only be
2088 Xn. Second input registers are always Xn. */
2089
2090/* 32 bit ADD extending register. */
2091static void
2092add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2093{
ef0d8ffc
NC
2094 unsigned rm = INSTR (20, 16);
2095 unsigned rn = INSTR (9, 5);
2096 unsigned rd = INSTR (4, 0);
2e8cf49e 2097
2cdad34c 2098 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2099 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2100 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2101 + (extreg32 (cpu, rm, extension) << shift));
2102}
2103
2104/* 64 bit ADD extending register.
2105 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2106static void
2107add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2108{
ef0d8ffc
NC
2109 unsigned rm = INSTR (20, 16);
2110 unsigned rn = INSTR (9, 5);
2111 unsigned rd = INSTR (4, 0);
2e8cf49e 2112
2cdad34c 2113 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2114 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2115 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2116 + (extreg64 (cpu, rm, extension) << shift));
2117}
2118
2119/* 32 bit ADD extending register setting flags. */
2120static void
2121adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2122{
ef0d8ffc
NC
2123 unsigned rm = INSTR (20, 16);
2124 unsigned rn = INSTR (9, 5);
2125 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2126
2127 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2128 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2129
2cdad34c 2130 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2131 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2132 set_flags_for_add32 (cpu, value1, value2);
2133}
2134
2135/* 64 bit ADD extending register setting flags */
2136/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2137static void
2138adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2139{
ef0d8ffc
NC
2140 unsigned rm = INSTR (20, 16);
2141 unsigned rn = INSTR (9, 5);
2142 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2143
2144 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2145 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2146
2cdad34c 2147 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2148 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2149 set_flags_for_add64 (cpu, value1, value2);
2150}
2151
2152/* 32 bit SUB extending register. */
2153static void
2154sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2155{
ef0d8ffc
NC
2156 unsigned rm = INSTR (20, 16);
2157 unsigned rn = INSTR (9, 5);
2158 unsigned rd = INSTR (4, 0);
2e8cf49e 2159
2cdad34c 2160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2161 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2162 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2163 - (extreg32 (cpu, rm, extension) << shift));
2164}
2165
2166/* 64 bit SUB extending register. */
2167/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2168static void
2169sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2170{
ef0d8ffc
NC
2171 unsigned rm = INSTR (20, 16);
2172 unsigned rn = INSTR (9, 5);
2173 unsigned rd = INSTR (4, 0);
2e8cf49e 2174
2cdad34c 2175 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2176 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2177 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2178 - (extreg64 (cpu, rm, extension) << shift));
2179}
2180
2181/* 32 bit SUB extending register setting flags. */
2182static void
2183subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2184{
ef0d8ffc
NC
2185 unsigned rm = INSTR (20, 16);
2186 unsigned rn = INSTR (9, 5);
2187 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2188
2189 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2190 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2191
2cdad34c 2192 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2193 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2194 set_flags_for_sub32 (cpu, value1, value2);
2195}
2196
2197/* 64 bit SUB extending register setting flags */
2198/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2199static void
2200subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2201{
ef0d8ffc
NC
2202 unsigned rm = INSTR (20, 16);
2203 unsigned rn = INSTR (9, 5);
2204 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2205
2206 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2207 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2208
2cdad34c 2209 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2210 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2211 set_flags_for_sub64 (cpu, value1, value2);
2212}
2213
2214static void
2215dexAddSubtractImmediate (sim_cpu *cpu)
2216{
2217 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2218 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2219 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2220 instr[28,24] = 10001
2221 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2222 instr[21,10] = uimm12
2223 instr[9,5] = Rn
2224 instr[4,0] = Rd */
2225
2226 /* N.B. the shift is applied at decode before calling the add/sub routine. */
ef0d8ffc
NC
2227 uint32_t shift = INSTR (23, 22);
2228 uint32_t imm = INSTR (21, 10);
2229 uint32_t dispatch = INSTR (31, 29);
2e8cf49e
NC
2230
2231 NYI_assert (28, 24, 0x11);
2232
2233 if (shift > 1)
2234 HALT_UNALLOC;
2235
2236 if (shift)
2237 imm <<= 12;
2238
2239 switch (dispatch)
2240 {
2241 case 0: add32 (cpu, imm); break;
2242 case 1: adds32 (cpu, imm); break;
2243 case 2: sub32 (cpu, imm); break;
2244 case 3: subs32 (cpu, imm); break;
2245 case 4: add64 (cpu, imm); break;
2246 case 5: adds64 (cpu, imm); break;
2247 case 6: sub64 (cpu, imm); break;
2248 case 7: subs64 (cpu, imm); break;
2e8cf49e
NC
2249 }
2250}
2251
2252static void
2253dexAddSubtractShiftedRegister (sim_cpu *cpu)
2254{
2255 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2256 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2257 instr[28,24] = 01011
2258 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2259 instr[21] = 0
2260 instr[20,16] = Rm
2261 instr[15,10] = count : must be 0xxxxx for 32 bit
2262 instr[9,5] = Rn
2263 instr[4,0] = Rd */
2264
ef0d8ffc
NC
2265 uint32_t size = INSTR (31, 31);
2266 uint32_t count = INSTR (15, 10);
2267 Shift shiftType = INSTR (23, 22);
2e8cf49e
NC
2268
2269 NYI_assert (28, 24, 0x0B);
2270 NYI_assert (21, 21, 0);
2271
ef0d8ffc 2272 /* Shift encoded as ROR is unallocated. */
2e8cf49e
NC
2273 if (shiftType == ROR)
2274 HALT_UNALLOC;
2275
ef0d8ffc
NC
2276 /* 32 bit operations must have count[5] = 0
2277 or else we have an UNALLOC. */
2278 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
2279 HALT_UNALLOC;
2280
ef0d8ffc
NC
2281 /* Dispatch on size:op i.e instr [31,29]. */
2282 switch (INSTR (31, 29))
2e8cf49e
NC
2283 {
2284 case 0: add32_shift (cpu, shiftType, count); break;
2285 case 1: adds32_shift (cpu, shiftType, count); break;
2286 case 2: sub32_shift (cpu, shiftType, count); break;
2287 case 3: subs32_shift (cpu, shiftType, count); break;
2288 case 4: add64_shift (cpu, shiftType, count); break;
2289 case 5: adds64_shift (cpu, shiftType, count); break;
2290 case 6: sub64_shift (cpu, shiftType, count); break;
2291 case 7: subs64_shift (cpu, shiftType, count); break;
2e8cf49e
NC
2292 }
2293}
2294
2295static void
2296dexAddSubtractExtendedRegister (sim_cpu *cpu)
2297{
2298 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2299 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2300 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2301 instr[28,24] = 01011
2302 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2303 instr[21] = 1
2304 instr[20,16] = Rm
2305 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2306 000 ==> LSL|UXTW, 001 ==> UXTZ,
2307 000 ==> SXTB, 001 ==> SXTH,
2308 000 ==> SXTW, 001 ==> SXTX,
2309 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2310 instr[9,5] = Rn
2311 instr[4,0] = Rd */
2312
ef0d8ffc
NC
2313 Extension extensionType = INSTR (15, 13);
2314 uint32_t shift = INSTR (12, 10);
2e8cf49e
NC
2315
2316 NYI_assert (28, 24, 0x0B);
2317 NYI_assert (21, 21, 1);
2318
2319 /* Shift may not exceed 4. */
2320 if (shift > 4)
2321 HALT_UNALLOC;
2322
ef0d8ffc
NC
2323 /* Dispatch on size:op:set?. */
2324 switch (INSTR (31, 29))
2e8cf49e
NC
2325 {
2326 case 0: add32_ext (cpu, extensionType, shift); break;
2327 case 1: adds32_ext (cpu, extensionType, shift); break;
2328 case 2: sub32_ext (cpu, extensionType, shift); break;
2329 case 3: subs32_ext (cpu, extensionType, shift); break;
2330 case 4: add64_ext (cpu, extensionType, shift); break;
2331 case 5: adds64_ext (cpu, extensionType, shift); break;
2332 case 6: sub64_ext (cpu, extensionType, shift); break;
2333 case 7: subs64_ext (cpu, extensionType, shift); break;
2e8cf49e
NC
2334 }
2335}
2336
2337/* Conditional data processing
2338 Condition register is implicit 3rd source. */
2339
2340/* 32 bit add with carry. */
2341/* N.B register args may not be SP. */
2342
2343static void
2344adc32 (sim_cpu *cpu)
2345{
ef0d8ffc
NC
2346 unsigned rm = INSTR (20, 16);
2347 unsigned rn = INSTR (9, 5);
2348 unsigned rd = INSTR (4, 0);
2e8cf49e 2349
2cdad34c 2350 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2351 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2352 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2353 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2354 + IS_SET (C));
2355}
2356
2357/* 64 bit add with carry */
2358static void
2359adc64 (sim_cpu *cpu)
2360{
ef0d8ffc
NC
2361 unsigned rm = INSTR (20, 16);
2362 unsigned rn = INSTR (9, 5);
2363 unsigned rd = INSTR (4, 0);
2e8cf49e 2364
2cdad34c 2365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2366 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2367 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2368 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2369 + IS_SET (C));
2370}
2371
2372/* 32 bit add with carry setting flags. */
2373static void
2374adcs32 (sim_cpu *cpu)
2375{
ef0d8ffc
NC
2376 unsigned rm = INSTR (20, 16);
2377 unsigned rn = INSTR (9, 5);
2378 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2379
2380 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2381 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2382 uint32_t carry = IS_SET (C);
2383
2cdad34c 2384 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2385 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2386 set_flags_for_add32 (cpu, value1, value2 + carry);
2387}
2388
2389/* 64 bit add with carry setting flags. */
2390static void
2391adcs64 (sim_cpu *cpu)
2392{
ef0d8ffc
NC
2393 unsigned rm = INSTR (20, 16);
2394 unsigned rn = INSTR (9, 5);
2395 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2396
2397 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2398 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2399 uint64_t carry = IS_SET (C);
2400
2cdad34c 2401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2402 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2403 set_flags_for_add64 (cpu, value1, value2 + carry);
2404}
2405
2406/* 32 bit sub with carry. */
2407static void
2408sbc32 (sim_cpu *cpu)
2409{
ef0d8ffc
NC
2410 unsigned rm = INSTR (20, 16);
2411 unsigned rn = INSTR (9, 5); /* ngc iff rn == 31. */
2412 unsigned rd = INSTR (4, 0);
2e8cf49e 2413
2cdad34c 2414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2415 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2416 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2417 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2418 - 1 + IS_SET (C));
2419}
2420
2421/* 64 bit sub with carry */
2422static void
2423sbc64 (sim_cpu *cpu)
2424{
ef0d8ffc
NC
2425 unsigned rm = INSTR (20, 16);
2426 unsigned rn = INSTR (9, 5);
2427 unsigned rd = INSTR (4, 0);
2e8cf49e 2428
2cdad34c 2429 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2430 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2431 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2432 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2433 - 1 + IS_SET (C));
2434}
2435
2436/* 32 bit sub with carry setting flags */
2437static void
2438sbcs32 (sim_cpu *cpu)
2439{
ef0d8ffc
NC
2440 unsigned rm = INSTR (20, 16);
2441 unsigned rn = INSTR (9, 5);
2442 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2443
2444 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2445 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2446 uint32_t carry = IS_SET (C);
2447 uint32_t result = value1 - value2 + 1 - carry;
2448
2cdad34c 2449 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2450 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2451 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2452}
2453
2454/* 64 bit sub with carry setting flags */
2455static void
2456sbcs64 (sim_cpu *cpu)
2457{
ef0d8ffc
NC
2458 unsigned rm = INSTR (20, 16);
2459 unsigned rn = INSTR (9, 5);
2460 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2461
2462 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2463 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2464 uint64_t carry = IS_SET (C);
2465 uint64_t result = value1 - value2 + 1 - carry;
2466
2cdad34c 2467 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2468 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2469 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2470}
2471
2472static void
2473dexAddSubtractWithCarry (sim_cpu *cpu)
2474{
2475 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2476 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2477 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2478 instr[28,21] = 1 1010 000
2479 instr[20,16] = Rm
2480 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2481 instr[9,5] = Rn
2482 instr[4,0] = Rd */
2483
ef0d8ffc 2484 uint32_t op2 = INSTR (15, 10);
2e8cf49e
NC
2485
2486 NYI_assert (28, 21, 0xD0);
2487
2488 if (op2 != 0)
2489 HALT_UNALLOC;
2490
ef0d8ffc
NC
2491 /* Dispatch on size:op:set?. */
2492 switch (INSTR (31, 29))
2e8cf49e
NC
2493 {
2494 case 0: adc32 (cpu); break;
2495 case 1: adcs32 (cpu); break;
2496 case 2: sbc32 (cpu); break;
2497 case 3: sbcs32 (cpu); break;
2498 case 4: adc64 (cpu); break;
2499 case 5: adcs64 (cpu); break;
2500 case 6: sbc64 (cpu); break;
2501 case 7: sbcs64 (cpu); break;
2e8cf49e
NC
2502 }
2503}
2504
2505static uint32_t
2506testConditionCode (sim_cpu *cpu, CondCode cc)
2507{
2508 /* This should be reduceable to branchless logic
2509 by some careful testing of bits in CC followed
2510 by the requisite masking and combining of bits
2511 from the flag register.
2512
2513 For now we do it with a switch. */
2514 int res;
2515
2516 switch (cc)
2517 {
2518 case EQ: res = IS_SET (Z); break;
2519 case NE: res = IS_CLEAR (Z); break;
2520 case CS: res = IS_SET (C); break;
2521 case CC: res = IS_CLEAR (C); break;
2522 case MI: res = IS_SET (N); break;
2523 case PL: res = IS_CLEAR (N); break;
2524 case VS: res = IS_SET (V); break;
2525 case VC: res = IS_CLEAR (V); break;
2526 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2527 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2528 case GE: res = IS_SET (N) == IS_SET (V); break;
2529 case LT: res = IS_SET (N) != IS_SET (V); break;
2530 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2531 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2532 case AL:
2533 case NV:
2534 default:
2535 res = 1;
2536 break;
2537 }
2538 return res;
2539}
2540
2541static void
2542CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2543{
2544 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2545 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2546 instr[29,21] = 1 1101 0010
2547 instr[20,16] = Rm or const
2548 instr[15,12] = cond
2549 instr[11] = compare reg (0) or const (1)
2550 instr[10] = 0
2551 instr[9,5] = Rn
2552 instr[4] = 0
2553 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2554 signed int negate;
2555 unsigned rm;
2556 unsigned rn;
2557
2558 NYI_assert (29, 21, 0x1d2);
2559 NYI_assert (10, 10, 0);
2560 NYI_assert (4, 4, 0);
2561
2cdad34c 2562 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2563 if (! testConditionCode (cpu, INSTR (15, 12)))
2e8cf49e 2564 {
ef0d8ffc 2565 aarch64_set_CPSR (cpu, INSTR (3, 0));
2e8cf49e
NC
2566 return;
2567 }
2568
ef0d8ffc
NC
2569 negate = INSTR (30, 30) ? 1 : -1;
2570 rm = INSTR (20, 16);
2571 rn = INSTR ( 9, 5);
2e8cf49e 2572
ef0d8ffc 2573 if (INSTR (31, 31))
2e8cf49e 2574 {
ef0d8ffc 2575 if (INSTR (11, 11))
2e8cf49e
NC
2576 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2577 negate * (uint64_t) rm);
2578 else
2579 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2580 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2581 }
2582 else
2583 {
ef0d8ffc 2584 if (INSTR (11, 11))
2e8cf49e
NC
2585 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2586 negate * rm);
2587 else
2588 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2589 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2590 }
2591}
2592
2593static void
2594do_vec_MOV_whole_vector (sim_cpu *cpu)
2595{
2596 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2597
2598 instr[31] = 0
2599 instr[30] = half(0)/full(1)
2600 instr[29,21] = 001110101
2601 instr[20,16] = Vs
2602 instr[15,10] = 000111
2603 instr[9,5] = Vs
2604 instr[4,0] = Vd */
2605
ef0d8ffc
NC
2606 unsigned vs = INSTR (9, 5);
2607 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2608
2609 NYI_assert (29, 21, 0x075);
2610 NYI_assert (15, 10, 0x07);
2611
ef0d8ffc 2612 if (INSTR (20, 16) != vs)
2e8cf49e
NC
2613 HALT_NYI;
2614
2cdad34c 2615 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2616 if (INSTR (30, 30))
2e8cf49e
NC
2617 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2618
2619 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2620}
2621
2622static void
2623do_vec_MOV_into_scalar (sim_cpu *cpu)
2624{
2625 /* instr[31] = 0
2626 instr[30] = word(0)/long(1)
2627 instr[29,21] = 00 1110 000
2628 instr[20,18] = element size and index
2629 instr[17,10] = 00 0011 11
2630 instr[9,5] = V source
2631 instr[4,0] = R dest */
2632
ef0d8ffc
NC
2633 unsigned vs = INSTR (9, 5);
2634 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2635
2636 NYI_assert (29, 21, 0x070);
2637 NYI_assert (17, 10, 0x0F);
2638
2cdad34c 2639 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2640 switch (INSTR (20, 18))
2e8cf49e
NC
2641 {
2642 case 0x2:
2643 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2644 break;
2645
2646 case 0x6:
2647 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2648 break;
2649
2650 case 0x1:
2651 case 0x3:
2652 case 0x5:
2653 case 0x7:
2654 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
ef0d8ffc 2655 (cpu, vs, INSTR (20, 19)));
2e8cf49e
NC
2656 break;
2657
2658 default:
2659 HALT_NYI;
2660 }
2661}
2662
2663static void
2664do_vec_INS (sim_cpu *cpu)
2665{
2666 /* instr[31,21] = 01001110000
2667 instr[20,16] = element size and index
2668 instr[15,10] = 000111
2669 instr[9,5] = W source
2670 instr[4,0] = V dest */
2671
2672 int index;
ef0d8ffc
NC
2673 unsigned rs = INSTR (9, 5);
2674 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2675
2676 NYI_assert (31, 21, 0x270);
2677 NYI_assert (15, 10, 0x07);
2678
2cdad34c 2679 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2680 if (INSTR (16, 16))
2e8cf49e 2681 {
ef0d8ffc 2682 index = INSTR (20, 17);
2e8cf49e
NC
2683 aarch64_set_vec_u8 (cpu, vd, index,
2684 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2685 }
ef0d8ffc 2686 else if (INSTR (17, 17))
2e8cf49e 2687 {
ef0d8ffc 2688 index = INSTR (20, 18);
2e8cf49e
NC
2689 aarch64_set_vec_u16 (cpu, vd, index,
2690 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2691 }
ef0d8ffc 2692 else if (INSTR (18, 18))
2e8cf49e 2693 {
ef0d8ffc 2694 index = INSTR (20, 19);
2e8cf49e
NC
2695 aarch64_set_vec_u32 (cpu, vd, index,
2696 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2697 }
ef0d8ffc 2698 else if (INSTR (19, 19))
2e8cf49e 2699 {
ef0d8ffc 2700 index = INSTR (20, 20);
2e8cf49e
NC
2701 aarch64_set_vec_u64 (cpu, vd, index,
2702 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2703 }
2704 else
2705 HALT_NYI;
2706}
2707
2708static void
2709do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2710{
2711 /* instr[31] = 0
2712 instr[30] = half(0)/full(1)
2713 instr[29,21] = 00 1110 000
2714 instr[20,16] = element size and index
2715 instr[15,10] = 0000 01
2716 instr[9,5] = V source
2717 instr[4,0] = V dest. */
2718
ef0d8ffc
NC
2719 unsigned full = INSTR (30, 30);
2720 unsigned vs = INSTR (9, 5);
2721 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2722 int i, index;
2723
2724 NYI_assert (29, 21, 0x070);
2725 NYI_assert (15, 10, 0x01);
2726
2cdad34c 2727 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2728 if (INSTR (16, 16))
2e8cf49e 2729 {
ef0d8ffc 2730 index = INSTR (20, 17);
2e8cf49e
NC
2731
2732 for (i = 0; i < (full ? 16 : 8); i++)
2733 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2734 }
ef0d8ffc 2735 else if (INSTR (17, 17))
2e8cf49e 2736 {
ef0d8ffc 2737 index = INSTR (20, 18);
2e8cf49e
NC
2738
2739 for (i = 0; i < (full ? 8 : 4); i++)
2740 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2741 }
ef0d8ffc 2742 else if (INSTR (18, 18))
2e8cf49e 2743 {
ef0d8ffc 2744 index = INSTR (20, 19);
2e8cf49e
NC
2745
2746 for (i = 0; i < (full ? 4 : 2); i++)
2747 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2748 }
2749 else
2750 {
ef0d8ffc 2751 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2752 HALT_UNALLOC;
2753
2754 if (! full)
2755 HALT_UNALLOC;
2756
ef0d8ffc 2757 index = INSTR (20, 20);
2e8cf49e
NC
2758
2759 for (i = 0; i < 2; i++)
2760 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2761 }
2762}
2763
2764static void
2765do_vec_TBL (sim_cpu *cpu)
2766{
2767 /* instr[31] = 0
2768 instr[30] = half(0)/full(1)
2769 instr[29,21] = 00 1110 000
2770 instr[20,16] = Vm
2771 instr[15] = 0
2772 instr[14,13] = vec length
2773 instr[12,10] = 000
2774 instr[9,5] = V start
2775 instr[4,0] = V dest */
2776
ef0d8ffc
NC
2777 int full = INSTR (30, 30);
2778 int len = INSTR (14, 13) + 1;
2779 unsigned vm = INSTR (20, 16);
2780 unsigned vn = INSTR (9, 5);
2781 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2782 unsigned i;
2783
2784 NYI_assert (29, 21, 0x070);
2785 NYI_assert (12, 10, 0);
2786
2cdad34c 2787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2788 for (i = 0; i < (full ? 16 : 8); i++)
2789 {
2790 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2791 uint8_t val;
2792
2793 if (selector < 16)
2794 val = aarch64_get_vec_u8 (cpu, vn, selector);
2795 else if (selector < 32)
2796 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2797 else if (selector < 48)
2798 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2799 else if (selector < 64)
2800 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2801 else
2802 val = 0;
2803
2804 aarch64_set_vec_u8 (cpu, vd, i, val);
2805 }
2806}
2807
2808static void
2809do_vec_TRN (sim_cpu *cpu)
2810{
2811 /* instr[31] = 0
2812 instr[30] = half(0)/full(1)
2813 instr[29,24] = 00 1110
2814 instr[23,22] = size
2815 instr[21] = 0
2816 instr[20,16] = Vm
2817 instr[15] = 0
2818 instr[14] = TRN1 (0) / TRN2 (1)
2819 instr[13,10] = 1010
2820 instr[9,5] = V source
2821 instr[4,0] = V dest. */
2822
ef0d8ffc
NC
2823 int full = INSTR (30, 30);
2824 int second = INSTR (14, 14);
2825 unsigned vm = INSTR (20, 16);
2826 unsigned vn = INSTR (9, 5);
2827 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2828 unsigned i;
2829
2830 NYI_assert (29, 24, 0x0E);
2831 NYI_assert (13, 10, 0xA);
2832
2cdad34c 2833 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2834 switch (INSTR (23, 22))
2e8cf49e
NC
2835 {
2836 case 0:
2837 for (i = 0; i < (full ? 8 : 4); i++)
2838 {
2839 aarch64_set_vec_u8
2840 (cpu, vd, i * 2,
2841 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2842 aarch64_set_vec_u8
2843 (cpu, vd, 1 * 2 + 1,
2844 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2845 }
2846 break;
2847
2848 case 1:
2849 for (i = 0; i < (full ? 4 : 2); i++)
2850 {
2851 aarch64_set_vec_u16
2852 (cpu, vd, i * 2,
2853 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2854 aarch64_set_vec_u16
2855 (cpu, vd, 1 * 2 + 1,
2856 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2857 }
2858 break;
2859
2860 case 2:
2861 aarch64_set_vec_u32
2862 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2863 aarch64_set_vec_u32
2864 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2865 aarch64_set_vec_u32
2866 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2867 aarch64_set_vec_u32
2868 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2869 break;
2870
2871 case 3:
2872 if (! full)
2873 HALT_UNALLOC;
2874
2875 aarch64_set_vec_u64 (cpu, vd, 0,
2876 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2877 aarch64_set_vec_u64 (cpu, vd, 1,
2878 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2879 break;
2e8cf49e
NC
2880 }
2881}
2882
2883static void
2884do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2885{
2886 /* instr[31] = 0
2887 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2888 [must be 1 for 64-bit xfer]
2889 instr[29,20] = 00 1110 0000
2890 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2891 0100=> 32-bits. 1000=>64-bits
2892 instr[15,10] = 0000 11
2893 instr[9,5] = W source
2894 instr[4,0] = V dest. */
2895
2896 unsigned i;
ef0d8ffc
NC
2897 unsigned Vd = INSTR (4, 0);
2898 unsigned Rs = INSTR (9, 5);
2899 int both = INSTR (30, 30);
2e8cf49e
NC
2900
2901 NYI_assert (29, 20, 0x0E0);
2902 NYI_assert (15, 10, 0x03);
2903
2cdad34c 2904 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2905 switch (INSTR (19, 16))
2e8cf49e
NC
2906 {
2907 case 1:
2908 for (i = 0; i < (both ? 16 : 8); i++)
2909 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2910 break;
2911
2912 case 2:
2913 for (i = 0; i < (both ? 8 : 4); i++)
2914 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2915 break;
2916
2917 case 4:
2918 for (i = 0; i < (both ? 4 : 2); i++)
2919 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2920 break;
2921
2922 case 8:
2923 if (!both)
2924 HALT_NYI;
2925 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2926 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2927 break;
2928
2929 default:
2930 HALT_NYI;
2931 }
2932}
2933
2934static void
2935do_vec_UZP (sim_cpu *cpu)
2936{
2937 /* instr[31] = 0
2938 instr[30] = half(0)/full(1)
2939 instr[29,24] = 00 1110
2940 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2941 instr[21] = 0
2942 instr[20,16] = Vm
2943 instr[15] = 0
2944 instr[14] = lower (0) / upper (1)
2945 instr[13,10] = 0110
2946 instr[9,5] = Vn
2947 instr[4,0] = Vd. */
2948
ef0d8ffc
NC
2949 int full = INSTR (30, 30);
2950 int upper = INSTR (14, 14);
2e8cf49e 2951
ef0d8ffc
NC
2952 unsigned vm = INSTR (20, 16);
2953 unsigned vn = INSTR (9, 5);
2954 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2955
2956 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2957 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2958 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2959 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2960
2961 uint64_t val1 = 0;
2962 uint64_t val2 = 0;
2963
2964 uint64_t input1 = upper ? val_n1 : val_m1;
2965 uint64_t input2 = upper ? val_n2 : val_m2;
2966 unsigned i;
2967
2968 NYI_assert (29, 24, 0x0E);
2969 NYI_assert (21, 21, 0);
2970 NYI_assert (15, 15, 0);
2971 NYI_assert (13, 10, 6);
2972
2cdad34c 2973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2974 switch (INSTR (23, 23))
2e8cf49e
NC
2975 {
2976 case 0:
2977 for (i = 0; i < 8; i++)
2978 {
2979 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2980 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2981 }
2982 break;
2983
2984 case 1:
2985 for (i = 0; i < 4; i++)
2986 {
2987 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2988 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2989 }
2990 break;
2991
2992 case 2:
2993 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2994 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2995
2996 case 3:
2997 val1 = input1;
2998 val2 = input2;
2999 break;
3000 }
3001
3002 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3003 if (full)
3004 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3005}
3006
3007static void
3008do_vec_ZIP (sim_cpu *cpu)
3009{
3010 /* instr[31] = 0
3011 instr[30] = half(0)/full(1)
3012 instr[29,24] = 00 1110
3013 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
3014 instr[21] = 0
3015 instr[20,16] = Vm
3016 instr[15] = 0
3017 instr[14] = lower (0) / upper (1)
3018 instr[13,10] = 1110
3019 instr[9,5] = Vn
3020 instr[4,0] = Vd. */
3021
ef0d8ffc
NC
3022 int full = INSTR (30, 30);
3023 int upper = INSTR (14, 14);
2e8cf49e 3024
ef0d8ffc
NC
3025 unsigned vm = INSTR (20, 16);
3026 unsigned vn = INSTR (9, 5);
3027 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3028
3029 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3030 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3031 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3032 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3033
3034 uint64_t val1 = 0;
3035 uint64_t val2 = 0;
3036
3037 uint64_t input1 = upper ? val_n1 : val_m1;
3038 uint64_t input2 = upper ? val_n2 : val_m2;
3039
3040 NYI_assert (29, 24, 0x0E);
3041 NYI_assert (21, 21, 0);
3042 NYI_assert (15, 15, 0);
3043 NYI_assert (13, 10, 0xE);
3044
2cdad34c 3045 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3046 switch (INSTR (23, 23))
2e8cf49e
NC
3047 {
3048 case 0:
3049 val1 =
3050 ((input1 << 0) & (0xFF << 0))
3051 | ((input2 << 8) & (0xFF << 8))
3052 | ((input1 << 8) & (0xFF << 16))
3053 | ((input2 << 16) & (0xFF << 24))
3054 | ((input1 << 16) & (0xFFULL << 32))
3055 | ((input2 << 24) & (0xFFULL << 40))
3056 | ((input1 << 24) & (0xFFULL << 48))
3057 | ((input2 << 32) & (0xFFULL << 56));
3058
3059 val2 =
3060 ((input1 >> 32) & (0xFF << 0))
3061 | ((input2 >> 24) & (0xFF << 8))
3062 | ((input1 >> 24) & (0xFF << 16))
3063 | ((input2 >> 16) & (0xFF << 24))
3064 | ((input1 >> 16) & (0xFFULL << 32))
3065 | ((input2 >> 8) & (0xFFULL << 40))
3066 | ((input1 >> 8) & (0xFFULL << 48))
3067 | ((input2 >> 0) & (0xFFULL << 56));
3068 break;
3069
3070 case 1:
3071 val1 =
3072 ((input1 << 0) & (0xFFFF << 0))
3073 | ((input2 << 16) & (0xFFFF << 16))
3074 | ((input1 << 16) & (0xFFFFULL << 32))
3075 | ((input2 << 32) & (0xFFFFULL << 48));
3076
3077 val2 =
3078 ((input1 >> 32) & (0xFFFF << 0))
3079 | ((input2 >> 16) & (0xFFFF << 16))
3080 | ((input1 >> 16) & (0xFFFFULL << 32))
3081 | ((input2 >> 0) & (0xFFFFULL << 48));
3082 break;
3083
3084 case 2:
3085 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3086 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3087 break;
3088
3089 case 3:
3090 val1 = input1;
3091 val2 = input2;
3092 break;
3093 }
3094
3095 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3096 if (full)
3097 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3098}
3099
3100/* Floating point immediates are encoded in 8 bits.
3101 fpimm[7] = sign bit.
3102 fpimm[6:4] = signed exponent.
3103 fpimm[3:0] = fraction (assuming leading 1).
3104 i.e. F = s * 1.f * 2^(e - b). */
3105
3106static float
3107fp_immediate_for_encoding_32 (uint32_t imm8)
3108{
3109 float u;
3110 uint32_t s, e, f, i;
3111
3112 s = (imm8 >> 7) & 0x1;
3113 e = (imm8 >> 4) & 0x7;
3114 f = imm8 & 0xf;
3115
3116 /* The fp value is s * n/16 * 2r where n is 16+e. */
3117 u = (16.0 + f) / 16.0;
3118
3119 /* N.B. exponent is signed. */
3120 if (e < 4)
3121 {
3122 int epos = e;
3123
3124 for (i = 0; i <= epos; i++)
3125 u *= 2.0;
3126 }
3127 else
3128 {
3129 int eneg = 7 - e;
3130
3131 for (i = 0; i < eneg; i++)
3132 u /= 2.0;
3133 }
3134
3135 if (s)
3136 u = - u;
3137
3138 return u;
3139}
3140
3141static double
3142fp_immediate_for_encoding_64 (uint32_t imm8)
3143{
3144 double u;
3145 uint32_t s, e, f, i;
3146
3147 s = (imm8 >> 7) & 0x1;
3148 e = (imm8 >> 4) & 0x7;
3149 f = imm8 & 0xf;
3150
3151 /* The fp value is s * n/16 * 2r where n is 16+e. */
3152 u = (16.0 + f) / 16.0;
3153
3154 /* N.B. exponent is signed. */
3155 if (e < 4)
3156 {
3157 int epos = e;
3158
3159 for (i = 0; i <= epos; i++)
3160 u *= 2.0;
3161 }
3162 else
3163 {
3164 int eneg = 7 - e;
3165
3166 for (i = 0; i < eneg; i++)
3167 u /= 2.0;
3168 }
3169
3170 if (s)
3171 u = - u;
3172
3173 return u;
3174}
3175
3176static void
3177do_vec_MOV_immediate (sim_cpu *cpu)
3178{
3179 /* instr[31] = 0
3180 instr[30] = full/half selector
3181 instr[29,19] = 00111100000
3182 instr[18,16] = high 3 bits of uimm8
3183 instr[15,12] = size & shift:
3184 0000 => 32-bit
3185 0010 => 32-bit + LSL#8
3186 0100 => 32-bit + LSL#16
3187 0110 => 32-bit + LSL#24
3188 1010 => 16-bit + LSL#8
3189 1000 => 16-bit
3190 1101 => 32-bit + MSL#16
3191 1100 => 32-bit + MSL#8
3192 1110 => 8-bit
3193 1111 => double
3194 instr[11,10] = 01
3195 instr[9,5] = low 5-bits of uimm8
3196 instr[4,0] = Vd. */
3197
ef0d8ffc
NC
3198 int full = INSTR (30, 30);
3199 unsigned vd = INSTR (4, 0);
7517e550 3200 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3201 unsigned i;
3202
3203 NYI_assert (29, 19, 0x1E0);
3204 NYI_assert (11, 10, 1);
3205
2cdad34c 3206 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3207 switch (INSTR (15, 12))
2e8cf49e
NC
3208 {
3209 case 0x0: /* 32-bit, no shift. */
3210 case 0x2: /* 32-bit, shift by 8. */
3211 case 0x4: /* 32-bit, shift by 16. */
3212 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3213 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3214 for (i = 0; i < (full ? 4 : 2); i++)
3215 aarch64_set_vec_u32 (cpu, vd, i, val);
3216 break;
3217
3218 case 0xa: /* 16-bit, shift by 8. */
3219 val <<= 8;
3220 /* Fall through. */
3221 case 0x8: /* 16-bit, no shift. */
3222 for (i = 0; i < (full ? 8 : 4); i++)
3223 aarch64_set_vec_u16 (cpu, vd, i, val);
c0386d4d
JW
3224 break;
3225
2e8cf49e
NC
3226 case 0xd: /* 32-bit, mask shift by 16. */
3227 val <<= 8;
3228 val |= 0xFF;
3229 /* Fall through. */
3230 case 0xc: /* 32-bit, mask shift by 8. */
3231 val <<= 8;
3232 val |= 0xFF;
3233 for (i = 0; i < (full ? 4 : 2); i++)
3234 aarch64_set_vec_u32 (cpu, vd, i, val);
3235 break;
3236
3237 case 0xe: /* 8-bit, no shift. */
3238 for (i = 0; i < (full ? 16 : 8); i++)
3239 aarch64_set_vec_u8 (cpu, vd, i, val);
3240 break;
3241
3242 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3243 {
3244 float u = fp_immediate_for_encoding_32 (val);
3245 for (i = 0; i < (full ? 4 : 2); i++)
3246 aarch64_set_vec_float (cpu, vd, i, u);
3247 break;
3248 }
3249
3250 default:
3251 HALT_NYI;
3252 }
3253}
3254
3255static void
3256do_vec_MVNI (sim_cpu *cpu)
3257{
3258 /* instr[31] = 0
3259 instr[30] = full/half selector
3260 instr[29,19] = 10111100000
3261 instr[18,16] = high 3 bits of uimm8
3262 instr[15,12] = selector
3263 instr[11,10] = 01
3264 instr[9,5] = low 5-bits of uimm8
3265 instr[4,0] = Vd. */
3266
ef0d8ffc
NC
3267 int full = INSTR (30, 30);
3268 unsigned vd = INSTR (4, 0);
7517e550 3269 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3270 unsigned i;
3271
3272 NYI_assert (29, 19, 0x5E0);
3273 NYI_assert (11, 10, 1);
3274
2cdad34c 3275 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3276 switch (INSTR (15, 12))
2e8cf49e
NC
3277 {
3278 case 0x0: /* 32-bit, no shift. */
3279 case 0x2: /* 32-bit, shift by 8. */
3280 case 0x4: /* 32-bit, shift by 16. */
3281 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3282 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3283 val = ~ val;
3284 for (i = 0; i < (full ? 4 : 2); i++)
3285 aarch64_set_vec_u32 (cpu, vd, i, val);
3286 return;
3287
3288 case 0xa: /* 16-bit, 8 bit shift. */
3289 val <<= 8;
3290 case 0x8: /* 16-bit, no shift. */
3291 val = ~ val;
3292 for (i = 0; i < (full ? 8 : 4); i++)
3293 aarch64_set_vec_u16 (cpu, vd, i, val);
3294 return;
3295
3296 case 0xd: /* 32-bit, mask shift by 16. */
3297 val <<= 8;
3298 val |= 0xFF;
3299 case 0xc: /* 32-bit, mask shift by 8. */
3300 val <<= 8;
3301 val |= 0xFF;
3302 val = ~ val;
3303 for (i = 0; i < (full ? 4 : 2); i++)
3304 aarch64_set_vec_u32 (cpu, vd, i, val);
3305 return;
3306
3307 case 0xE: /* MOVI Dn, #mask64 */
3308 {
3309 uint64_t mask = 0;
3310
3311 for (i = 0; i < 8; i++)
3312 if (val & (1 << i))
7517e550 3313 mask |= (0xFFUL << (i * 8));
2e8cf49e 3314 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3315 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3316 return;
3317 }
3318
3319 case 0xf: /* FMOV Vd.2D, #fpimm. */
3320 {
3321 double u = fp_immediate_for_encoding_64 (val);
3322
3323 if (! full)
3324 HALT_UNALLOC;
3325
3326 aarch64_set_vec_double (cpu, vd, 0, u);
3327 aarch64_set_vec_double (cpu, vd, 1, u);
3328 return;
3329 }
3330
3331 default:
3332 HALT_NYI;
3333 }
3334}
3335
3336#define ABS(A) ((A) < 0 ? - (A) : (A))
3337
3338static void
3339do_vec_ABS (sim_cpu *cpu)
3340{
3341 /* instr[31] = 0
3342 instr[30] = half(0)/full(1)
3343 instr[29,24] = 00 1110
3344 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3345 instr[21,10] = 10 0000 1011 10
3346 instr[9,5] = Vn
3347 instr[4.0] = Vd. */
3348
ef0d8ffc
NC
3349 unsigned vn = INSTR (9, 5);
3350 unsigned vd = INSTR (4, 0);
3351 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3352 unsigned i;
3353
3354 NYI_assert (29, 24, 0x0E);
3355 NYI_assert (21, 10, 0x82E);
3356
2cdad34c 3357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3358 switch (INSTR (23, 22))
2e8cf49e
NC
3359 {
3360 case 0:
3361 for (i = 0; i < (full ? 16 : 8); i++)
3362 aarch64_set_vec_s8 (cpu, vd, i,
3363 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3364 break;
3365
3366 case 1:
3367 for (i = 0; i < (full ? 8 : 4); i++)
3368 aarch64_set_vec_s16 (cpu, vd, i,
3369 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3370 break;
3371
3372 case 2:
3373 for (i = 0; i < (full ? 4 : 2); i++)
3374 aarch64_set_vec_s32 (cpu, vd, i,
3375 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3376 break;
3377
3378 case 3:
3379 if (! full)
3380 HALT_NYI;
3381 for (i = 0; i < 2; i++)
3382 aarch64_set_vec_s64 (cpu, vd, i,
3383 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3384 break;
3385 }
3386}
3387
3388static void
3389do_vec_ADDV (sim_cpu *cpu)
3390{
3391 /* instr[31] = 0
3392 instr[30] = full/half selector
3393 instr[29,24] = 00 1110
3394 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3395 instr[21,10] = 11 0001 1011 10
3396 instr[9,5] = Vm
3397 instr[4.0] = Rd. */
3398
ef0d8ffc
NC
3399 unsigned vm = INSTR (9, 5);
3400 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
3401 unsigned i;
3402 uint64_t val = 0;
ef0d8ffc 3403 int full = INSTR (30, 30);
2e8cf49e
NC
3404
3405 NYI_assert (29, 24, 0x0E);
3406 NYI_assert (21, 10, 0xC6E);
3407
2cdad34c 3408 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3409 switch (INSTR (23, 22))
2e8cf49e
NC
3410 {
3411 case 0:
3412 for (i = 0; i < (full ? 16 : 8); i++)
3413 val += aarch64_get_vec_u8 (cpu, vm, i);
3414 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3415 return;
3416
3417 case 1:
3418 for (i = 0; i < (full ? 8 : 4); i++)
3419 val += aarch64_get_vec_u16 (cpu, vm, i);
3420 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3421 return;
3422
3423 case 2:
3424 for (i = 0; i < (full ? 4 : 2); i++)
3425 val += aarch64_get_vec_u32 (cpu, vm, i);
3426 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3427 return;
3428
3429 case 3:
3430 if (! full)
3431 HALT_UNALLOC;
3432 val = aarch64_get_vec_u64 (cpu, vm, 0);
3433 val += aarch64_get_vec_u64 (cpu, vm, 1);
3434 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3435 return;
2e8cf49e
NC
3436 }
3437}
3438
3439static void
3440do_vec_ins_2 (sim_cpu *cpu)
3441{
3442 /* instr[31,21] = 01001110000
3443 instr[20,18] = size & element selector
3444 instr[17,14] = 0000
3445 instr[13] = direction: to vec(0), from vec (1)
3446 instr[12,10] = 111
3447 instr[9,5] = Vm
3448 instr[4,0] = Vd. */
3449
3450 unsigned elem;
ef0d8ffc
NC
3451 unsigned vm = INSTR (9, 5);
3452 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3453
3454 NYI_assert (31, 21, 0x270);
3455 NYI_assert (17, 14, 0);
3456 NYI_assert (12, 10, 7);
3457
2cdad34c 3458 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3459 if (INSTR (13, 13) == 1)
2e8cf49e 3460 {
ef0d8ffc 3461 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3462 {
3463 /* 32-bit moves. */
ef0d8ffc 3464 elem = INSTR (20, 19);
2e8cf49e
NC
3465 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3466 aarch64_get_vec_u32 (cpu, vm, elem));
3467 }
3468 else
3469 {
3470 /* 64-bit moves. */
ef0d8ffc 3471 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3472 HALT_NYI;
3473
ef0d8ffc 3474 elem = INSTR (20, 20);
2e8cf49e
NC
3475 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3476 aarch64_get_vec_u64 (cpu, vm, elem));
3477 }
3478 }
3479 else
3480 {
ef0d8ffc 3481 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3482 {
3483 /* 32-bit moves. */
ef0d8ffc 3484 elem = INSTR (20, 19);
2e8cf49e
NC
3485 aarch64_set_vec_u32 (cpu, vd, elem,
3486 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3487 }
3488 else
3489 {
3490 /* 64-bit moves. */
ef0d8ffc 3491 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3492 HALT_NYI;
3493
ef0d8ffc 3494 elem = INSTR (20, 20);
2e8cf49e
NC
3495 aarch64_set_vec_u64 (cpu, vd, elem,
3496 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3497 }
3498 }
3499}
3500
7517e550
NC
3501#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3502 do \
3503 { \
3504 DST_TYPE a[N], b[N]; \
3505 \
3506 for (i = 0; i < (N); i++) \
3507 { \
3508 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3509 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3510 } \
3511 for (i = 0; i < (N); i++) \
3512 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3513 } \
3514 while (0)
3515
2e8cf49e
NC
3516static void
3517do_vec_mull (sim_cpu *cpu)
3518{
3519 /* instr[31] = 0
3520 instr[30] = lower(0)/upper(1) selector
3521 instr[29] = signed(0)/unsigned(1)
3522 instr[28,24] = 0 1110
3523 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3524 instr[21] = 1
3525 instr[20,16] = Vm
3526 instr[15,10] = 11 0000
3527 instr[9,5] = Vn
3528 instr[4.0] = Vd. */
3529
ef0d8ffc
NC
3530 int unsign = INSTR (29, 29);
3531 int bias = INSTR (30, 30);
3532 unsigned vm = INSTR (20, 16);
3533 unsigned vn = INSTR ( 9, 5);
3534 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3535 unsigned i;
3536
3537 NYI_assert (28, 24, 0x0E);
3538 NYI_assert (15, 10, 0x30);
3539
2cdad34c 3540 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
3541 /* NB: Read source values before writing results, in case
3542 the source and destination vectors are the same. */
ef0d8ffc 3543 switch (INSTR (23, 22))
2e8cf49e
NC
3544 {
3545 case 0:
3546 if (bias)
3547 bias = 8;
3548 if (unsign)
7517e550 3549 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3550 else
7517e550 3551 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3552 return;
3553
3554 case 1:
3555 if (bias)
3556 bias = 4;
3557 if (unsign)
7517e550 3558 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3559 else
7517e550 3560 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3561 return;
3562
3563 case 2:
3564 if (bias)
3565 bias = 2;
3566 if (unsign)
7517e550 3567 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3568 else
7517e550 3569 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3570 return;
3571
3572 case 3:
2e8cf49e
NC
3573 HALT_NYI;
3574 }
3575}
3576
3577static void
3578do_vec_fadd (sim_cpu *cpu)
3579{
3580 /* instr[31] = 0
3581 instr[30] = half(0)/full(1)
3582 instr[29,24] = 001110
3583 instr[23] = FADD(0)/FSUB(1)
3584 instr[22] = float (0)/double(1)
3585 instr[21] = 1
3586 instr[20,16] = Vm
3587 instr[15,10] = 110101
3588 instr[9,5] = Vn
3589 instr[4.0] = Vd. */
3590
ef0d8ffc
NC
3591 unsigned vm = INSTR (20, 16);
3592 unsigned vn = INSTR (9, 5);
3593 unsigned vd = INSTR (4, 0);
2e8cf49e 3594 unsigned i;
ef0d8ffc 3595 int full = INSTR (30, 30);
2e8cf49e
NC
3596
3597 NYI_assert (29, 24, 0x0E);
3598 NYI_assert (21, 21, 1);
3599 NYI_assert (15, 10, 0x35);
3600
2cdad34c 3601 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3602 if (INSTR (23, 23))
2e8cf49e 3603 {
ef0d8ffc 3604 if (INSTR (22, 22))
2e8cf49e
NC
3605 {
3606 if (! full)
3607 HALT_NYI;
3608
3609 for (i = 0; i < 2; i++)
3610 aarch64_set_vec_double (cpu, vd, i,
3611 aarch64_get_vec_double (cpu, vn, i)
3612 - aarch64_get_vec_double (cpu, vm, i));
3613 }
3614 else
3615 {
3616 for (i = 0; i < (full ? 4 : 2); i++)
3617 aarch64_set_vec_float (cpu, vd, i,
3618 aarch64_get_vec_float (cpu, vn, i)
3619 - aarch64_get_vec_float (cpu, vm, i));
3620 }
3621 }
3622 else
3623 {
ef0d8ffc 3624 if (INSTR (22, 22))
2e8cf49e
NC
3625 {
3626 if (! full)
3627 HALT_NYI;
3628
3629 for (i = 0; i < 2; i++)
3630 aarch64_set_vec_double (cpu, vd, i,
3631 aarch64_get_vec_double (cpu, vm, i)
3632 + aarch64_get_vec_double (cpu, vn, i));
3633 }
3634 else
3635 {
3636 for (i = 0; i < (full ? 4 : 2); i++)
3637 aarch64_set_vec_float (cpu, vd, i,
3638 aarch64_get_vec_float (cpu, vm, i)
3639 + aarch64_get_vec_float (cpu, vn, i));
3640 }
3641 }
3642}
3643
3644static void
3645do_vec_add (sim_cpu *cpu)
3646{
3647 /* instr[31] = 0
3648 instr[30] = full/half selector
3649 instr[29,24] = 001110
3650 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3651 instr[21] = 1
3652 instr[20,16] = Vn
3653 instr[15,10] = 100001
3654 instr[9,5] = Vm
3655 instr[4.0] = Vd. */
3656
ef0d8ffc
NC
3657 unsigned vm = INSTR (20, 16);
3658 unsigned vn = INSTR (9, 5);
3659 unsigned vd = INSTR (4, 0);
2e8cf49e 3660 unsigned i;
ef0d8ffc 3661 int full = INSTR (30, 30);
2e8cf49e
NC
3662
3663 NYI_assert (29, 24, 0x0E);
3664 NYI_assert (21, 21, 1);
3665 NYI_assert (15, 10, 0x21);
3666
2cdad34c 3667 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3668 switch (INSTR (23, 22))
2e8cf49e
NC
3669 {
3670 case 0:
3671 for (i = 0; i < (full ? 16 : 8); i++)
3672 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3673 + aarch64_get_vec_u8 (cpu, vm, i));
3674 return;
3675
3676 case 1:
3677 for (i = 0; i < (full ? 8 : 4); i++)
3678 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3679 + aarch64_get_vec_u16 (cpu, vm, i));
3680 return;
3681
3682 case 2:
3683 for (i = 0; i < (full ? 4 : 2); i++)
3684 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3685 + aarch64_get_vec_u32 (cpu, vm, i));
3686 return;
3687
3688 case 3:
3689 if (! full)
3690 HALT_UNALLOC;
3691 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3692 + aarch64_get_vec_u64 (cpu, vm, 0));
3693 aarch64_set_vec_u64 (cpu, vd, 1,
3694 aarch64_get_vec_u64 (cpu, vn, 1)
3695 + aarch64_get_vec_u64 (cpu, vm, 1));
3696 return;
2e8cf49e
NC
3697 }
3698}
3699
3700static void
3701do_vec_mul (sim_cpu *cpu)
3702{
3703 /* instr[31] = 0
3704 instr[30] = full/half selector
3705 instr[29,24] = 00 1110
3706 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3707 instr[21] = 1
3708 instr[20,16] = Vn
3709 instr[15,10] = 10 0111
3710 instr[9,5] = Vm
3711 instr[4.0] = Vd. */
3712
ef0d8ffc
NC
3713 unsigned vm = INSTR (20, 16);
3714 unsigned vn = INSTR (9, 5);
3715 unsigned vd = INSTR (4, 0);
2e8cf49e 3716 unsigned i;
ef0d8ffc 3717 int full = INSTR (30, 30);
7517e550 3718 int bias = 0;
2e8cf49e
NC
3719
3720 NYI_assert (29, 24, 0x0E);
3721 NYI_assert (21, 21, 1);
3722 NYI_assert (15, 10, 0x27);
3723
2cdad34c 3724 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3725 switch (INSTR (23, 22))
2e8cf49e
NC
3726 {
3727 case 0:
c0386d4d 3728 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint8_t, u8, u8);
2e8cf49e
NC
3729 return;
3730
3731 case 1:
c0386d4d 3732 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint16_t, u16, u16);
2e8cf49e
NC
3733 return;
3734
3735 case 2:
c0386d4d 3736 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint32_t, u32, u32);
2e8cf49e
NC
3737 return;
3738
2e8cf49e
NC
3739 case 3:
3740 HALT_UNALLOC;
3741 }
3742}
3743
3744static void
3745do_vec_MLA (sim_cpu *cpu)
3746{
3747 /* instr[31] = 0
3748 instr[30] = full/half selector
3749 instr[29,24] = 00 1110
3750 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3751 instr[21] = 1
3752 instr[20,16] = Vn
3753 instr[15,10] = 1001 01
3754 instr[9,5] = Vm
3755 instr[4.0] = Vd. */
3756
ef0d8ffc
NC
3757 unsigned vm = INSTR (20, 16);
3758 unsigned vn = INSTR (9, 5);
3759 unsigned vd = INSTR (4, 0);
2e8cf49e 3760 unsigned i;
ef0d8ffc 3761 int full = INSTR (30, 30);
2e8cf49e
NC
3762
3763 NYI_assert (29, 24, 0x0E);
3764 NYI_assert (21, 21, 1);
3765 NYI_assert (15, 10, 0x25);
3766
2cdad34c 3767 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3768 switch (INSTR (23, 22))
2e8cf49e
NC
3769 {
3770 case 0:
7517e550
NC
3771 {
3772 uint16_t a[16], b[16];
2e8cf49e 3773
7517e550
NC
3774 for (i = 0; i < (full ? 16 : 8); i++)
3775 {
3776 a[i] = aarch64_get_vec_u8 (cpu, vn, i);
3777 b[i] = aarch64_get_vec_u8 (cpu, vm, i);
3778 }
3779
3780 for (i = 0; i < (full ? 16 : 8); i++)
3781 {
3782 uint16_t v = aarch64_get_vec_u8 (cpu, vd, i);
3783
3784 aarch64_set_vec_u16 (cpu, vd, i, v + (a[i] * b[i]));
3785 }
3786 }
2e8cf49e
NC
3787 return;
3788
3789 case 1:
7517e550
NC
3790 {
3791 uint32_t a[8], b[8];
2e8cf49e 3792
7517e550
NC
3793 for (i = 0; i < (full ? 8 : 4); i++)
3794 {
3795 a[i] = aarch64_get_vec_u16 (cpu, vn, i);
3796 b[i] = aarch64_get_vec_u16 (cpu, vm, i);
3797 }
3798
3799 for (i = 0; i < (full ? 8 : 4); i++)
3800 {
3801 uint32_t v = aarch64_get_vec_u16 (cpu, vd, i);
3802
3803 aarch64_set_vec_u32 (cpu, vd, i, v + (a[i] * b[i]));
3804 }
3805 }
2e8cf49e
NC
3806 return;
3807
3808 case 2:
7517e550
NC
3809 {
3810 uint64_t a[4], b[4];
2e8cf49e 3811
7517e550
NC
3812 for (i = 0; i < (full ? 4 : 2); i++)
3813 {
3814 a[i] = aarch64_get_vec_u32 (cpu, vn, i);
3815 b[i] = aarch64_get_vec_u32 (cpu, vm, i);
3816 }
3817
3818 for (i = 0; i < (full ? 4 : 2); i++)
3819 {
3820 uint64_t v = aarch64_get_vec_u32 (cpu, vd, i);
3821
3822 aarch64_set_vec_u64 (cpu, vd, i, v + (a[i] * b[i]));
3823 }
3824 }
2e8cf49e
NC
3825 return;
3826
2e8cf49e
NC
3827 case 3:
3828 HALT_UNALLOC;
3829 }
3830}
3831
3832static float
3833fmaxnm (float a, float b)
3834{
c0386d4d 3835 if (! isnan (a))
2e8cf49e 3836 {
c0386d4d 3837 if (! isnan (b))
2e8cf49e
NC
3838 return a > b ? a : b;
3839 return a;
3840 }
c0386d4d 3841 else if (! isnan (b))
2e8cf49e
NC
3842 return b;
3843 return a;
3844}
3845
3846static float
3847fminnm (float a, float b)
3848{
c0386d4d 3849 if (! isnan (a))
2e8cf49e 3850 {
c0386d4d 3851 if (! isnan (b))
2e8cf49e
NC
3852 return a < b ? a : b;
3853 return a;
3854 }
c0386d4d 3855 else if (! isnan (b))
2e8cf49e
NC
3856 return b;
3857 return a;
3858}
3859
3860static double
3861dmaxnm (double a, double b)
3862{
c0386d4d 3863 if (! isnan (a))
2e8cf49e 3864 {
c0386d4d 3865 if (! isnan (b))
2e8cf49e
NC
3866 return a > b ? a : b;
3867 return a;
3868 }
c0386d4d 3869 else if (! isnan (b))
2e8cf49e
NC
3870 return b;
3871 return a;
3872}
3873
3874static double
3875dminnm (double a, double b)
3876{
c0386d4d 3877 if (! isnan (a))
2e8cf49e 3878 {
c0386d4d 3879 if (! isnan (b))
2e8cf49e
NC
3880 return a < b ? a : b;
3881 return a;
3882 }
c0386d4d 3883 else if (! isnan (b))
2e8cf49e
NC
3884 return b;
3885 return a;
3886}
3887
3888static void
3889do_vec_FminmaxNMP (sim_cpu *cpu)
3890{
ef0d8ffc
NC
3891 /* instr [31] = 0
3892 instr [30] = half (0)/full (1)
3893 instr [29,24] = 10 1110
3894 instr [23] = max(0)/min(1)
3895 instr [22] = float (0)/double (1)
3896 instr [21] = 1
3897 instr [20,16] = Vn
3898 instr [15,10] = 1100 01
3899 instr [9,5] = Vm
3900 instr [4.0] = Vd. */
3901
3902 unsigned vm = INSTR (20, 16);
3903 unsigned vn = INSTR (9, 5);
3904 unsigned vd = INSTR (4, 0);
3905 int full = INSTR (30, 30);
2e8cf49e
NC
3906
3907 NYI_assert (29, 24, 0x2E);
3908 NYI_assert (21, 21, 1);
3909 NYI_assert (15, 10, 0x31);
3910
2cdad34c 3911 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3912 if (INSTR (22, 22))
2e8cf49e 3913 {
ef0d8ffc 3914 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
3915 ? dminnm : dmaxnm;
3916
3917 if (! full)
3918 HALT_NYI;
3919 aarch64_set_vec_double (cpu, vd, 0,
3920 fn (aarch64_get_vec_double (cpu, vn, 0),
3921 aarch64_get_vec_double (cpu, vn, 1)));
3922 aarch64_set_vec_double (cpu, vd, 0,
3923 fn (aarch64_get_vec_double (cpu, vm, 0),
3924 aarch64_get_vec_double (cpu, vm, 1)));
3925 }
3926 else
3927 {
ef0d8ffc 3928 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
3929 ? fminnm : fmaxnm;
3930
3931 aarch64_set_vec_float (cpu, vd, 0,
3932 fn (aarch64_get_vec_float (cpu, vn, 0),
3933 aarch64_get_vec_float (cpu, vn, 1)));
3934 if (full)
3935 aarch64_set_vec_float (cpu, vd, 1,
3936 fn (aarch64_get_vec_float (cpu, vn, 2),
3937 aarch64_get_vec_float (cpu, vn, 3)));
3938
3939 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3940 fn (aarch64_get_vec_float (cpu, vm, 0),
3941 aarch64_get_vec_float (cpu, vm, 1)));
3942 if (full)
3943 aarch64_set_vec_float (cpu, vd, 3,
3944 fn (aarch64_get_vec_float (cpu, vm, 2),
3945 aarch64_get_vec_float (cpu, vm, 3)));
3946 }
3947}
3948
3949static void
3950do_vec_AND (sim_cpu *cpu)
3951{
3952 /* instr[31] = 0
3953 instr[30] = half (0)/full (1)
3954 instr[29,21] = 001110001
3955 instr[20,16] = Vm
3956 instr[15,10] = 000111
3957 instr[9,5] = Vn
3958 instr[4.0] = Vd. */
3959
ef0d8ffc
NC
3960 unsigned vm = INSTR (20, 16);
3961 unsigned vn = INSTR (9, 5);
3962 unsigned vd = INSTR (4, 0);
2e8cf49e 3963 unsigned i;
ef0d8ffc 3964 int full = INSTR (30, 30);
2e8cf49e
NC
3965
3966 NYI_assert (29, 21, 0x071);
3967 NYI_assert (15, 10, 0x07);
3968
2cdad34c 3969 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
3970 for (i = 0; i < (full ? 4 : 2); i++)
3971 aarch64_set_vec_u32 (cpu, vd, i,
3972 aarch64_get_vec_u32 (cpu, vn, i)
3973 & aarch64_get_vec_u32 (cpu, vm, i));
3974}
3975
3976static void
3977do_vec_BSL (sim_cpu *cpu)
3978{
3979 /* instr[31] = 0
3980 instr[30] = half (0)/full (1)
3981 instr[29,21] = 101110011
3982 instr[20,16] = Vm
3983 instr[15,10] = 000111
3984 instr[9,5] = Vn
3985 instr[4.0] = Vd. */
3986
ef0d8ffc
NC
3987 unsigned vm = INSTR (20, 16);
3988 unsigned vn = INSTR (9, 5);
3989 unsigned vd = INSTR (4, 0);
2e8cf49e 3990 unsigned i;
ef0d8ffc 3991 int full = INSTR (30, 30);
2e8cf49e
NC
3992
3993 NYI_assert (29, 21, 0x173);
3994 NYI_assert (15, 10, 0x07);
3995
2cdad34c 3996 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
3997 for (i = 0; i < (full ? 16 : 8); i++)
3998 aarch64_set_vec_u8 (cpu, vd, i,
3999 ( aarch64_get_vec_u8 (cpu, vd, i)
4000 & aarch64_get_vec_u8 (cpu, vn, i))
4001 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
4002 & aarch64_get_vec_u8 (cpu, vm, i)));
4003}
4004
4005static void
4006do_vec_EOR (sim_cpu *cpu)
4007{
4008 /* instr[31] = 0
4009 instr[30] = half (0)/full (1)
4010 instr[29,21] = 10 1110 001
4011 instr[20,16] = Vm
4012 instr[15,10] = 000111
4013 instr[9,5] = Vn
4014 instr[4.0] = Vd. */
4015
ef0d8ffc
NC
4016 unsigned vm = INSTR (20, 16);
4017 unsigned vn = INSTR (9, 5);
4018 unsigned vd = INSTR (4, 0);
2e8cf49e 4019 unsigned i;
ef0d8ffc 4020 int full = INSTR (30, 30);
2e8cf49e
NC
4021
4022 NYI_assert (29, 21, 0x171);
4023 NYI_assert (15, 10, 0x07);
4024
2cdad34c 4025 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4026 for (i = 0; i < (full ? 4 : 2); i++)
4027 aarch64_set_vec_u32 (cpu, vd, i,
4028 aarch64_get_vec_u32 (cpu, vn, i)
4029 ^ aarch64_get_vec_u32 (cpu, vm, i));
4030}
4031
4032static void
4033do_vec_bit (sim_cpu *cpu)
4034{
4035 /* instr[31] = 0
4036 instr[30] = half (0)/full (1)
4037 instr[29,23] = 10 1110 1
4038 instr[22] = BIT (0) / BIF (1)
4039 instr[21] = 1
4040 instr[20,16] = Vm
4041 instr[15,10] = 0001 11
4042 instr[9,5] = Vn
4043 instr[4.0] = Vd. */
4044
ef0d8ffc
NC
4045 unsigned vm = INSTR (20, 16);
4046 unsigned vn = INSTR (9, 5);
4047 unsigned vd = INSTR (4, 0);
4048 unsigned full = INSTR (30, 30);
4049 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
4050 unsigned i;
4051
4052 NYI_assert (29, 23, 0x5D);
4053 NYI_assert (21, 21, 1);
4054 NYI_assert (15, 10, 0x07);
4055
2cdad34c 4056 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4057 if (test_false)
4058 {
4059 for (i = 0; i < (full ? 16 : 8); i++)
4060 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
4061 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4062 }
4063 else
4064 {
4065 for (i = 0; i < (full ? 16 : 8); i++)
4066 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
4067 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4068 }
4069}
4070
4071static void
4072do_vec_ORN (sim_cpu *cpu)
4073{
4074 /* instr[31] = 0
4075 instr[30] = half (0)/full (1)
4076 instr[29,21] = 00 1110 111
4077 instr[20,16] = Vm
4078 instr[15,10] = 00 0111
4079 instr[9,5] = Vn
4080 instr[4.0] = Vd. */
4081
ef0d8ffc
NC
4082 unsigned vm = INSTR (20, 16);
4083 unsigned vn = INSTR (9, 5);
4084 unsigned vd = INSTR (4, 0);
2e8cf49e 4085 unsigned i;
ef0d8ffc 4086 int full = INSTR (30, 30);
2e8cf49e
NC
4087
4088 NYI_assert (29, 21, 0x077);
4089 NYI_assert (15, 10, 0x07);
4090
2cdad34c 4091 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4092 for (i = 0; i < (full ? 16 : 8); i++)
4093 aarch64_set_vec_u8 (cpu, vd, i,
4094 aarch64_get_vec_u8 (cpu, vn, i)
4095 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4096}
4097
4098static void
4099do_vec_ORR (sim_cpu *cpu)
4100{
4101 /* instr[31] = 0
4102 instr[30] = half (0)/full (1)
4103 instr[29,21] = 00 1110 101
4104 instr[20,16] = Vm
4105 instr[15,10] = 0001 11
4106 instr[9,5] = Vn
4107 instr[4.0] = Vd. */
4108
ef0d8ffc
NC
4109 unsigned vm = INSTR (20, 16);
4110 unsigned vn = INSTR (9, 5);
4111 unsigned vd = INSTR (4, 0);
2e8cf49e 4112 unsigned i;
ef0d8ffc 4113 int full = INSTR (30, 30);
2e8cf49e
NC
4114
4115 NYI_assert (29, 21, 0x075);
4116 NYI_assert (15, 10, 0x07);
4117
2cdad34c 4118 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4119 for (i = 0; i < (full ? 16 : 8); i++)
4120 aarch64_set_vec_u8 (cpu, vd, i,
4121 aarch64_get_vec_u8 (cpu, vn, i)
4122 | aarch64_get_vec_u8 (cpu, vm, i));
4123}
4124
4125static void
4126do_vec_BIC (sim_cpu *cpu)
4127{
4128 /* instr[31] = 0
4129 instr[30] = half (0)/full (1)
4130 instr[29,21] = 00 1110 011
4131 instr[20,16] = Vm
4132 instr[15,10] = 00 0111
4133 instr[9,5] = Vn
4134 instr[4.0] = Vd. */
4135
ef0d8ffc
NC
4136 unsigned vm = INSTR (20, 16);
4137 unsigned vn = INSTR (9, 5);
4138 unsigned vd = INSTR (4, 0);
2e8cf49e 4139 unsigned i;
ef0d8ffc 4140 int full = INSTR (30, 30);
2e8cf49e
NC
4141
4142 NYI_assert (29, 21, 0x073);
4143 NYI_assert (15, 10, 0x07);
4144
2cdad34c 4145 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4146 for (i = 0; i < (full ? 16 : 8); i++)
4147 aarch64_set_vec_u8 (cpu, vd, i,
4148 aarch64_get_vec_u8 (cpu, vn, i)
4149 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4150}
4151
4152static void
4153do_vec_XTN (sim_cpu *cpu)
4154{
4155 /* instr[31] = 0
4156 instr[30] = first part (0)/ second part (1)
4157 instr[29,24] = 00 1110
4158 instr[23,22] = size: byte(00), half(01), word (10)
4159 instr[21,10] = 1000 0100 1010
4160 instr[9,5] = Vs
4161 instr[4,0] = Vd. */
4162
ef0d8ffc
NC
4163 unsigned vs = INSTR (9, 5);
4164 unsigned vd = INSTR (4, 0);
4165 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4166 unsigned i;
4167
4168 NYI_assert (29, 24, 0x0E);
4169 NYI_assert (21, 10, 0x84A);
4170
2cdad34c 4171 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4172 switch (INSTR (23, 22))
2e8cf49e
NC
4173 {
4174 case 0:
4175 if (bias)
4176 for (i = 0; i < 8; i++)
4177 aarch64_set_vec_u8 (cpu, vd, i + 8,
4178 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4179 else
4180 for (i = 0; i < 8; i++)
4181 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4182 return;
4183
4184 case 1:
4185 if (bias)
4186 for (i = 0; i < 4; i++)
4187 aarch64_set_vec_u16 (cpu, vd, i + 4,
4188 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4189 else
4190 for (i = 0; i < 4; i++)
4191 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4192 return;
4193
4194 case 2:
4195 if (bias)
4196 for (i = 0; i < 2; i++)
4197 aarch64_set_vec_u32 (cpu, vd, i + 4,
4198 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4199 else
4200 for (i = 0; i < 2; i++)
4201 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4202 return;
2e8cf49e
NC
4203 }
4204}
4205
2e8cf49e
NC
4206static void
4207do_vec_maxv (sim_cpu *cpu)
4208{
4209 /* instr[31] = 0
4210 instr[30] = half(0)/full(1)
4211 instr[29] = signed (0)/unsigned(1)
4212 instr[28,24] = 0 1110
4213 instr[23,22] = size: byte(00), half(01), word (10)
4214 instr[21] = 1
4215 instr[20,17] = 1 000
4216 instr[16] = max(0)/min(1)
4217 instr[15,10] = 1010 10
4218 instr[9,5] = V source
4219 instr[4.0] = R dest. */
4220
ef0d8ffc
NC
4221 unsigned vs = INSTR (9, 5);
4222 unsigned rd = INSTR (4, 0);
4223 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4224 unsigned i;
4225
4226 NYI_assert (28, 24, 0x0E);
4227 NYI_assert (21, 21, 1);
4228 NYI_assert (20, 17, 8);
4229 NYI_assert (15, 10, 0x2A);
4230
2cdad34c 4231 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 4232 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4233 {
4234 case 0: /* SMAXV. */
4235 {
4236 int64_t smax;
ef0d8ffc 4237 switch (INSTR (23, 22))
2e8cf49e
NC
4238 {
4239 case 0:
4240 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4241 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4242 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4243 break;
4244 case 1:
4245 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4246 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4247 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4248 break;
4249 case 2:
4250 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4251 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4252 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4253 break;
2e8cf49e
NC
4254 case 3:
4255 HALT_UNALLOC;
4256 }
4257 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4258 return;
4259 }
4260
4261 case 1: /* SMINV. */
4262 {
4263 int64_t smin;
ef0d8ffc 4264 switch (INSTR (23, 22))
2e8cf49e
NC
4265 {
4266 case 0:
4267 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4268 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4269 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4270 break;
4271 case 1:
4272 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4273 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4274 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4275 break;
4276 case 2:
4277 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4278 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4279 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4280 break;
5ab6d79e 4281
2e8cf49e
NC
4282 case 3:
4283 HALT_UNALLOC;
4284 }
4285 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4286 return;
4287 }
4288
4289 case 2: /* UMAXV. */
4290 {
4291 uint64_t umax;
ef0d8ffc 4292 switch (INSTR (23, 22))
2e8cf49e
NC
4293 {
4294 case 0:
4295 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4296 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4297 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4298 break;
4299 case 1:
4300 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4301 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4302 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4303 break;
4304 case 2:
4305 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4306 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4307 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4308 break;
5ab6d79e 4309
2e8cf49e
NC
4310 case 3:
4311 HALT_UNALLOC;
4312 }
4313 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4314 return;
4315 }
4316
4317 case 3: /* UMINV. */
4318 {
4319 uint64_t umin;
ef0d8ffc 4320 switch (INSTR (23, 22))
2e8cf49e
NC
4321 {
4322 case 0:
4323 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4324 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4325 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4326 break;
4327 case 1:
4328 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4329 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4330 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4331 break;
4332 case 2:
4333 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4334 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4335 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4336 break;
5ab6d79e 4337
2e8cf49e
NC
4338 case 3:
4339 HALT_UNALLOC;
4340 }
4341 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4342 return;
4343 }
2e8cf49e
NC
4344 }
4345}
4346
4347static void
4348do_vec_fminmaxV (sim_cpu *cpu)
4349{
4350 /* instr[31,24] = 0110 1110
4351 instr[23] = max(0)/min(1)
4352 instr[22,14] = 011 0000 11
4353 instr[13,12] = nm(00)/normal(11)
4354 instr[11,10] = 10
4355 instr[9,5] = V source
4356 instr[4.0] = R dest. */
4357
ef0d8ffc
NC
4358 unsigned vs = INSTR (9, 5);
4359 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4360 unsigned i;
4361 float res = aarch64_get_vec_float (cpu, vs, 0);
4362
4363 NYI_assert (31, 24, 0x6E);
4364 NYI_assert (22, 14, 0x0C3);
4365 NYI_assert (11, 10, 2);
4366
2cdad34c 4367 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4368 if (INSTR (23, 23))
2e8cf49e 4369 {
ef0d8ffc 4370 switch (INSTR (13, 12))
2e8cf49e
NC
4371 {
4372 case 0: /* FMNINNMV. */
4373 for (i = 1; i < 4; i++)
4374 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4375 break;
4376
4377 case 3: /* FMINV. */
4378 for (i = 1; i < 4; i++)
bc273e17 4379 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4380 break;
4381
4382 default:
4383 HALT_NYI;
4384 }
4385 }
4386 else
4387 {
ef0d8ffc 4388 switch (INSTR (13, 12))
2e8cf49e
NC
4389 {
4390 case 0: /* FMNAXNMV. */
4391 for (i = 1; i < 4; i++)
4392 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4393 break;
4394
4395 case 3: /* FMAXV. */
4396 for (i = 1; i < 4; i++)
bc273e17 4397 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4398 break;
4399
4400 default:
4401 HALT_NYI;
4402 }
4403 }
4404
4405 aarch64_set_FP_float (cpu, rd, res);
4406}
4407
4408static void
4409do_vec_Fminmax (sim_cpu *cpu)
4410{
4411 /* instr[31] = 0
4412 instr[30] = half(0)/full(1)
4413 instr[29,24] = 00 1110
4414 instr[23] = max(0)/min(1)
4415 instr[22] = float(0)/double(1)
4416 instr[21] = 1
4417 instr[20,16] = Vm
4418 instr[15,14] = 11
4419 instr[13,12] = nm(00)/normal(11)
4420 instr[11,10] = 01
4421 instr[9,5] = Vn
4422 instr[4,0] = Vd. */
4423
ef0d8ffc
NC
4424 unsigned vm = INSTR (20, 16);
4425 unsigned vn = INSTR (9, 5);
4426 unsigned vd = INSTR (4, 0);
4427 unsigned full = INSTR (30, 30);
4428 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4429 unsigned i;
4430
4431 NYI_assert (29, 24, 0x0E);
4432 NYI_assert (21, 21, 1);
4433 NYI_assert (15, 14, 3);
4434 NYI_assert (11, 10, 1);
4435
2cdad34c 4436 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4437 if (INSTR (22, 22))
2e8cf49e
NC
4438 {
4439 double (* func)(double, double);
4440
4441 if (! full)
4442 HALT_NYI;
4443
ef0d8ffc 4444 if (INSTR (13, 12) == 0)
2e8cf49e 4445 func = min ? dminnm : dmaxnm;
ef0d8ffc 4446 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4447 func = min ? fmin : fmax;
4448 else
4449 HALT_NYI;
4450
4451 for (i = 0; i < 2; i++)
4452 aarch64_set_vec_double (cpu, vd, i,
4453 func (aarch64_get_vec_double (cpu, vn, i),
4454 aarch64_get_vec_double (cpu, vm, i)));
4455 }
4456 else
4457 {
4458 float (* func)(float, float);
4459
ef0d8ffc 4460 if (INSTR (13, 12) == 0)
2e8cf49e 4461 func = min ? fminnm : fmaxnm;
ef0d8ffc 4462 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4463 func = min ? fminf : fmaxf;
4464 else
4465 HALT_NYI;
4466
4467 for (i = 0; i < (full ? 4 : 2); i++)
4468 aarch64_set_vec_float (cpu, vd, i,
4469 func (aarch64_get_vec_float (cpu, vn, i),
4470 aarch64_get_vec_float (cpu, vm, i)));
4471 }
4472}
4473
4474static void
4475do_vec_SCVTF (sim_cpu *cpu)
4476{
4477 /* instr[31] = 0
4478 instr[30] = Q
4479 instr[29,23] = 00 1110 0
4480 instr[22] = float(0)/double(1)
4481 instr[21,10] = 10 0001 1101 10
4482 instr[9,5] = Vn
4483 instr[4,0] = Vd. */
4484
ef0d8ffc
NC
4485 unsigned vn = INSTR (9, 5);
4486 unsigned vd = INSTR (4, 0);
4487 unsigned full = INSTR (30, 30);
4488 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4489 unsigned i;
4490
4491 NYI_assert (29, 23, 0x1C);
4492 NYI_assert (21, 10, 0x876);
4493
2cdad34c 4494 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4495 if (size)
4496 {
4497 if (! full)
4498 HALT_UNALLOC;
4499
4500 for (i = 0; i < 2; i++)
4501 {
4502 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4503 aarch64_set_vec_double (cpu, vd, i, val);
4504 }
4505 }
4506 else
4507 {
4508 for (i = 0; i < (full ? 4 : 2); i++)
4509 {
4510 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4511 aarch64_set_vec_float (cpu, vd, i, val);
4512 }
4513 }
4514}
4515
4516#define VEC_CMP(SOURCE, CMP) \
4517 do \
4518 { \
4519 switch (size) \
4520 { \
4521 case 0: \
4522 for (i = 0; i < (full ? 16 : 8); i++) \
4523 aarch64_set_vec_u8 (cpu, vd, i, \
4524 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4525 CMP \
4526 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4527 ? -1 : 0); \
4528 return; \
4529 case 1: \
4530 for (i = 0; i < (full ? 8 : 4); i++) \
4531 aarch64_set_vec_u16 (cpu, vd, i, \
4532 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4533 CMP \
4534 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4535 ? -1 : 0); \
4536 return; \
4537 case 2: \
4538 for (i = 0; i < (full ? 4 : 2); i++) \
4539 aarch64_set_vec_u32 (cpu, vd, i, \
4540 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4541 CMP \
4542 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4543 ? -1 : 0); \
4544 return; \
4545 case 3: \
4546 if (! full) \
4547 HALT_UNALLOC; \
4548 for (i = 0; i < 2; i++) \
4549 aarch64_set_vec_u64 (cpu, vd, i, \
4550 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4551 CMP \
4552 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4553 ? -1ULL : 0); \
4554 return; \
2e8cf49e
NC
4555 } \
4556 } \
4557 while (0)
4558
4559#define VEC_CMP0(SOURCE, CMP) \
4560 do \
4561 { \
4562 switch (size) \
4563 { \
4564 case 0: \
4565 for (i = 0; i < (full ? 16 : 8); i++) \
4566 aarch64_set_vec_u8 (cpu, vd, i, \
4567 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4568 CMP 0 ? -1 : 0); \
4569 return; \
4570 case 1: \
4571 for (i = 0; i < (full ? 8 : 4); i++) \
4572 aarch64_set_vec_u16 (cpu, vd, i, \
4573 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4574 CMP 0 ? -1 : 0); \
4575 return; \
4576 case 2: \
4577 for (i = 0; i < (full ? 4 : 2); i++) \
4578 aarch64_set_vec_u32 (cpu, vd, i, \
4579 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4580 CMP 0 ? -1 : 0); \
4581 return; \
4582 case 3: \
4583 if (! full) \
4584 HALT_UNALLOC; \
4585 for (i = 0; i < 2; i++) \
4586 aarch64_set_vec_u64 (cpu, vd, i, \
4587 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4588 CMP 0 ? -1ULL : 0); \
4589 return; \
2e8cf49e
NC
4590 } \
4591 } \
4592 while (0)
4593
4594#define VEC_FCMP0(CMP) \
4595 do \
4596 { \
4597 if (vm != 0) \
4598 HALT_NYI; \
2cdad34c 4599 if (INSTR (22, 22)) \
2e8cf49e
NC
4600 { \
4601 if (! full) \
4602 HALT_NYI; \
4603 for (i = 0; i < 2; i++) \
4604 aarch64_set_vec_u64 (cpu, vd, i, \
4605 aarch64_get_vec_double (cpu, vn, i) \
4606 CMP 0.0 ? -1 : 0); \
4607 } \
4608 else \
4609 { \
4610 for (i = 0; i < (full ? 4 : 2); i++) \
4611 aarch64_set_vec_u32 (cpu, vd, i, \
4612 aarch64_get_vec_float (cpu, vn, i) \
4613 CMP 0.0 ? -1 : 0); \
4614 } \
4615 return; \
4616 } \
4617 while (0)
4618
4619#define VEC_FCMP(CMP) \
4620 do \
4621 { \
2cdad34c 4622 if (INSTR (22, 22)) \
2e8cf49e
NC
4623 { \
4624 if (! full) \
4625 HALT_NYI; \
4626 for (i = 0; i < 2; i++) \
4627 aarch64_set_vec_u64 (cpu, vd, i, \
4628 aarch64_get_vec_double (cpu, vn, i) \
4629 CMP \
4630 aarch64_get_vec_double (cpu, vm, i) \
4631 ? -1 : 0); \
4632 } \
4633 else \
4634 { \
4635 for (i = 0; i < (full ? 4 : 2); i++) \
4636 aarch64_set_vec_u32 (cpu, vd, i, \
4637 aarch64_get_vec_float (cpu, vn, i) \
4638 CMP \
4639 aarch64_get_vec_float (cpu, vm, i) \
4640 ? -1 : 0); \
4641 } \
4642 return; \
4643 } \
4644 while (0)
4645
4646static void
4647do_vec_compare (sim_cpu *cpu)
4648{
4649 /* instr[31] = 0
4650 instr[30] = half(0)/full(1)
4651 instr[29] = part-of-comparison-type
4652 instr[28,24] = 0 1110
4653 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4654 type of float compares: single (-0) / double (-1)
4655 instr[21] = 1
4656 instr[20,16] = Vm or 00000 (compare vs 0)
4657 instr[15,10] = part-of-comparison-type
4658 instr[9,5] = Vn
4659 instr[4.0] = Vd. */
4660
ef0d8ffc
NC
4661 int full = INSTR (30, 30);
4662 int size = INSTR (23, 22);
4663 unsigned vm = INSTR (20, 16);
4664 unsigned vn = INSTR (9, 5);
4665 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4666 unsigned i;
4667
4668 NYI_assert (28, 24, 0x0E);
4669 NYI_assert (21, 21, 1);
4670
2cdad34c 4671 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc
NC
4672 if ((INSTR (11, 11)
4673 && INSTR (14, 14))
4674 || ((INSTR (11, 11) == 0
4675 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4676 {
4677 /* A compare vs 0. */
4678 if (vm != 0)
4679 {
ef0d8ffc 4680 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4681 do_vec_maxv (cpu);
ef0d8ffc
NC
4682 else if (INSTR (15, 10) == 0x32
4683 || INSTR (15, 10) == 0x3E)
2e8cf49e 4684 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4685 else if (INSTR (29, 23) == 0x1C
4686 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4687 do_vec_SCVTF (cpu);
4688 else
4689 HALT_NYI;
4690 return;
4691 }
4692 }
4693
ef0d8ffc 4694 if (INSTR (14, 14))
2e8cf49e
NC
4695 {
4696 /* A floating point compare. */
7517e550 4697 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4698 | INSTR (13, 10);
2e8cf49e
NC
4699
4700 NYI_assert (15, 15, 1);
4701
4702 switch (decode)
4703 {
4704 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4705 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4706 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4707 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4708 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4709 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4710 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4711 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4712
4713 default:
4714 HALT_NYI;
4715 }
4716 }
4717 else
4718 {
7517e550 4719 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4720
4721 switch (decode)
4722 {
4723 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4724 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4725 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4726 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4727 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4728 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4729 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4730 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4731 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4732 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4733 default:
4734 if (vm == 0)
4735 HALT_NYI;
4736 do_vec_maxv (cpu);
4737 }
4738 }
4739}
4740
4741static void
4742do_vec_SSHL (sim_cpu *cpu)
4743{
4744 /* instr[31] = 0
4745 instr[30] = first part (0)/ second part (1)
4746 instr[29,24] = 00 1110
4747 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4748 instr[21] = 1
4749 instr[20,16] = Vm
4750 instr[15,10] = 0100 01
4751 instr[9,5] = Vn
4752 instr[4,0] = Vd. */
4753
ef0d8ffc
NC
4754 unsigned full = INSTR (30, 30);
4755 unsigned vm = INSTR (20, 16);
4756 unsigned vn = INSTR (9, 5);
4757 unsigned vd = INSTR (4, 0);
2e8cf49e 4758 unsigned i;
5ab6d79e 4759 signed int shift;
2e8cf49e
NC
4760
4761 NYI_assert (29, 24, 0x0E);
4762 NYI_assert (21, 21, 1);
4763 NYI_assert (15, 10, 0x11);
4764
4765 /* FIXME: What is a signed shift left in this context ?. */
4766
2cdad34c 4767 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4768 switch (INSTR (23, 22))
2e8cf49e
NC
4769 {
4770 case 0:
4771 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4772 {
4773 shift = aarch64_get_vec_s8 (cpu, vm, i);
4774 if (shift >= 0)
4775 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4776 << shift);
4777 else
4778 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4779 >> - shift);
4780 }
2e8cf49e
NC
4781 return;
4782
4783 case 1:
4784 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4785 {
7517e550 4786 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4787 if (shift >= 0)
4788 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4789 << shift);
4790 else
4791 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4792 >> - shift);
4793 }
2e8cf49e
NC
4794 return;
4795
4796 case 2:
4797 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4798 {
7517e550 4799 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4800 if (shift >= 0)
4801 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4802 << shift);
4803 else
4804 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4805 >> - shift);
4806 }
2e8cf49e
NC
4807 return;
4808
4809 case 3:
4810 if (! full)
4811 HALT_UNALLOC;
4812 for (i = 0; i < 2; i++)
5ab6d79e 4813 {
7517e550 4814 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4815 if (shift >= 0)
4816 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4817 << shift);
4818 else
4819 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4820 >> - shift);
4821 }
2e8cf49e 4822 return;
2e8cf49e
NC
4823 }
4824}
4825
4826static void
4827do_vec_USHL (sim_cpu *cpu)
4828{
4829 /* instr[31] = 0
4830 instr[30] = first part (0)/ second part (1)
4831 instr[29,24] = 10 1110
4832 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4833 instr[21] = 1
4834 instr[20,16] = Vm
4835 instr[15,10] = 0100 01
4836 instr[9,5] = Vn
4837 instr[4,0] = Vd */
4838
ef0d8ffc
NC
4839 unsigned full = INSTR (30, 30);
4840 unsigned vm = INSTR (20, 16);
4841 unsigned vn = INSTR (9, 5);
4842 unsigned vd = INSTR (4, 0);
2e8cf49e 4843 unsigned i;
5ab6d79e 4844 signed int shift;
2e8cf49e
NC
4845
4846 NYI_assert (29, 24, 0x2E);
4847 NYI_assert (15, 10, 0x11);
4848
2cdad34c 4849 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4850 switch (INSTR (23, 22))
2e8cf49e
NC
4851 {
4852 case 0:
5ab6d79e
NC
4853 for (i = 0; i < (full ? 16 : 8); i++)
4854 {
4855 shift = aarch64_get_vec_s8 (cpu, vm, i);
4856 if (shift >= 0)
4857 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4858 << shift);
4859 else
4860 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4861 >> - shift);
4862 }
2e8cf49e
NC
4863 return;
4864
4865 case 1:
4866 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4867 {
7517e550 4868 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4869 if (shift >= 0)
4870 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4871 << shift);
4872 else
4873 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4874 >> - shift);
4875 }
2e8cf49e
NC
4876 return;
4877
4878 case 2:
4879 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4880 {
7517e550 4881 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4882 if (shift >= 0)
4883 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4884 << shift);
4885 else
4886 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4887 >> - shift);
4888 }
2e8cf49e
NC
4889 return;
4890
4891 case 3:
4892 if (! full)
4893 HALT_UNALLOC;
4894 for (i = 0; i < 2; i++)
5ab6d79e 4895 {
7517e550 4896 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4897 if (shift >= 0)
4898 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4899 << shift);
4900 else
4901 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4902 >> - shift);
4903 }
2e8cf49e 4904 return;
2e8cf49e
NC
4905 }
4906}
4907
4908static void
4909do_vec_FMLA (sim_cpu *cpu)
4910{
4911 /* instr[31] = 0
4912 instr[30] = full/half selector
4913 instr[29,23] = 0011100
4914 instr[22] = size: 0=>float, 1=>double
4915 instr[21] = 1
4916 instr[20,16] = Vn
4917 instr[15,10] = 1100 11
4918 instr[9,5] = Vm
4919 instr[4.0] = Vd. */
4920
ef0d8ffc
NC
4921 unsigned vm = INSTR (20, 16);
4922 unsigned vn = INSTR (9, 5);
4923 unsigned vd = INSTR (4, 0);
2e8cf49e 4924 unsigned i;
ef0d8ffc 4925 int full = INSTR (30, 30);
2e8cf49e
NC
4926
4927 NYI_assert (29, 23, 0x1C);
4928 NYI_assert (21, 21, 1);
4929 NYI_assert (15, 10, 0x33);
4930
2cdad34c 4931 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4932 if (INSTR (22, 22))
2e8cf49e
NC
4933 {
4934 if (! full)
4935 HALT_UNALLOC;
4936 for (i = 0; i < 2; i++)
4937 aarch64_set_vec_double (cpu, vd, i,
4938 aarch64_get_vec_double (cpu, vn, i) *
4939 aarch64_get_vec_double (cpu, vm, i) +
4940 aarch64_get_vec_double (cpu, vd, i));
4941 }
4942 else
4943 {
4944 for (i = 0; i < (full ? 4 : 2); i++)
4945 aarch64_set_vec_float (cpu, vd, i,
4946 aarch64_get_vec_float (cpu, vn, i) *
4947 aarch64_get_vec_float (cpu, vm, i) +
4948 aarch64_get_vec_float (cpu, vd, i));
4949 }
4950}
4951
4952static void
4953do_vec_max (sim_cpu *cpu)
4954{
4955 /* instr[31] = 0
4956 instr[30] = full/half selector
4957 instr[29] = SMAX (0) / UMAX (1)
4958 instr[28,24] = 0 1110
4959 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4960 instr[21] = 1
4961 instr[20,16] = Vn
4962 instr[15,10] = 0110 01
4963 instr[9,5] = Vm
4964 instr[4.0] = Vd. */
4965
ef0d8ffc
NC
4966 unsigned vm = INSTR (20, 16);
4967 unsigned vn = INSTR (9, 5);
4968 unsigned vd = INSTR (4, 0);
2e8cf49e 4969 unsigned i;
ef0d8ffc 4970 int full = INSTR (30, 30);
2e8cf49e
NC
4971
4972 NYI_assert (28, 24, 0x0E);
4973 NYI_assert (21, 21, 1);
4974 NYI_assert (15, 10, 0x19);
4975
2cdad34c 4976 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4977 if (INSTR (29, 29))
2e8cf49e 4978 {
ef0d8ffc 4979 switch (INSTR (23, 22))
2e8cf49e
NC
4980 {
4981 case 0:
4982 for (i = 0; i < (full ? 16 : 8); i++)
4983 aarch64_set_vec_u8 (cpu, vd, i,
4984 aarch64_get_vec_u8 (cpu, vn, i)
4985 > aarch64_get_vec_u8 (cpu, vm, i)
4986 ? aarch64_get_vec_u8 (cpu, vn, i)
4987 : aarch64_get_vec_u8 (cpu, vm, i));
4988 return;
4989
4990 case 1:
4991 for (i = 0; i < (full ? 8 : 4); i++)
4992 aarch64_set_vec_u16 (cpu, vd, i,
4993 aarch64_get_vec_u16 (cpu, vn, i)
4994 > aarch64_get_vec_u16 (cpu, vm, i)
4995 ? aarch64_get_vec_u16 (cpu, vn, i)
4996 : aarch64_get_vec_u16 (cpu, vm, i));
4997 return;
4998
4999 case 2:
5000 for (i = 0; i < (full ? 4 : 2); i++)
5001 aarch64_set_vec_u32 (cpu, vd, i,
5002 aarch64_get_vec_u32 (cpu, vn, i)
5003 > aarch64_get_vec_u32 (cpu, vm, i)
5004 ? aarch64_get_vec_u32 (cpu, vn, i)
5005 : aarch64_get_vec_u32 (cpu, vm, i));
5006 return;
5007
2e8cf49e
NC
5008 case 3:
5009 HALT_UNALLOC;
5010 }
5011 }
5012 else
5013 {
ef0d8ffc 5014 switch (INSTR (23, 22))
2e8cf49e
NC
5015 {
5016 case 0:
5017 for (i = 0; i < (full ? 16 : 8); i++)
5018 aarch64_set_vec_s8 (cpu, vd, i,
5019 aarch64_get_vec_s8 (cpu, vn, i)
5020 > aarch64_get_vec_s8 (cpu, vm, i)
5021 ? aarch64_get_vec_s8 (cpu, vn, i)
5022 : aarch64_get_vec_s8 (cpu, vm, i));
5023 return;
5024
5025 case 1:
5026 for (i = 0; i < (full ? 8 : 4); i++)
5027 aarch64_set_vec_s16 (cpu, vd, i,
5028 aarch64_get_vec_s16 (cpu, vn, i)
5029 > aarch64_get_vec_s16 (cpu, vm, i)
5030 ? aarch64_get_vec_s16 (cpu, vn, i)
5031 : aarch64_get_vec_s16 (cpu, vm, i));
5032 return;
5033
5034 case 2:
5035 for (i = 0; i < (full ? 4 : 2); i++)
5036 aarch64_set_vec_s32 (cpu, vd, i,
5037 aarch64_get_vec_s32 (cpu, vn, i)
5038 > aarch64_get_vec_s32 (cpu, vm, i)
5039 ? aarch64_get_vec_s32 (cpu, vn, i)
5040 : aarch64_get_vec_s32 (cpu, vm, i));
5041 return;
5042
2e8cf49e
NC
5043 case 3:
5044 HALT_UNALLOC;
5045 }
5046 }
5047}
5048
5049static void
5050do_vec_min (sim_cpu *cpu)
5051{
5052 /* instr[31] = 0
5053 instr[30] = full/half selector
5054 instr[29] = SMIN (0) / UMIN (1)
5055 instr[28,24] = 0 1110
5056 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5057 instr[21] = 1
5058 instr[20,16] = Vn
5059 instr[15,10] = 0110 11
5060 instr[9,5] = Vm
5061 instr[4.0] = Vd. */
5062
ef0d8ffc
NC
5063 unsigned vm = INSTR (20, 16);
5064 unsigned vn = INSTR (9, 5);
5065 unsigned vd = INSTR (4, 0);
2e8cf49e 5066 unsigned i;
ef0d8ffc 5067 int full = INSTR (30, 30);
2e8cf49e
NC
5068
5069 NYI_assert (28, 24, 0x0E);
5070 NYI_assert (21, 21, 1);
5071 NYI_assert (15, 10, 0x1B);
5072
2cdad34c 5073 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5074 if (INSTR (29, 29))
2e8cf49e 5075 {
ef0d8ffc 5076 switch (INSTR (23, 22))
2e8cf49e
NC
5077 {
5078 case 0:
5079 for (i = 0; i < (full ? 16 : 8); i++)
5080 aarch64_set_vec_u8 (cpu, vd, i,
5081 aarch64_get_vec_u8 (cpu, vn, i)
5082 < aarch64_get_vec_u8 (cpu, vm, i)
5083 ? aarch64_get_vec_u8 (cpu, vn, i)
5084 : aarch64_get_vec_u8 (cpu, vm, i));
5085 return;
5086
5087 case 1:
5088 for (i = 0; i < (full ? 8 : 4); i++)
5089 aarch64_set_vec_u16 (cpu, vd, i,
5090 aarch64_get_vec_u16 (cpu, vn, i)
5091 < aarch64_get_vec_u16 (cpu, vm, i)
5092 ? aarch64_get_vec_u16 (cpu, vn, i)
5093 : aarch64_get_vec_u16 (cpu, vm, i));
5094 return;
5095
5096 case 2:
5097 for (i = 0; i < (full ? 4 : 2); i++)
5098 aarch64_set_vec_u32 (cpu, vd, i,
5099 aarch64_get_vec_u32 (cpu, vn, i)
5100 < aarch64_get_vec_u32 (cpu, vm, i)
5101 ? aarch64_get_vec_u32 (cpu, vn, i)
5102 : aarch64_get_vec_u32 (cpu, vm, i));
5103 return;
5104
2e8cf49e
NC
5105 case 3:
5106 HALT_UNALLOC;
5107 }
5108 }
5109 else
5110 {
ef0d8ffc 5111 switch (INSTR (23, 22))
2e8cf49e
NC
5112 {
5113 case 0:
5114 for (i = 0; i < (full ? 16 : 8); i++)
5115 aarch64_set_vec_s8 (cpu, vd, i,
5116 aarch64_get_vec_s8 (cpu, vn, i)
5117 < aarch64_get_vec_s8 (cpu, vm, i)
5118 ? aarch64_get_vec_s8 (cpu, vn, i)
5119 : aarch64_get_vec_s8 (cpu, vm, i));
5120 return;
5121
5122 case 1:
5123 for (i = 0; i < (full ? 8 : 4); i++)
5124 aarch64_set_vec_s16 (cpu, vd, i,
5125 aarch64_get_vec_s16 (cpu, vn, i)
5126 < aarch64_get_vec_s16 (cpu, vm, i)
5127 ? aarch64_get_vec_s16 (cpu, vn, i)
5128 : aarch64_get_vec_s16 (cpu, vm, i));
5129 return;
5130
5131 case 2:
5132 for (i = 0; i < (full ? 4 : 2); i++)
5133 aarch64_set_vec_s32 (cpu, vd, i,
5134 aarch64_get_vec_s32 (cpu, vn, i)
5135 < aarch64_get_vec_s32 (cpu, vm, i)
5136 ? aarch64_get_vec_s32 (cpu, vn, i)
5137 : aarch64_get_vec_s32 (cpu, vm, i));
5138 return;
5139
2e8cf49e
NC
5140 case 3:
5141 HALT_UNALLOC;
5142 }
5143 }
5144}
5145
5146static void
5147do_vec_sub_long (sim_cpu *cpu)
5148{
5149 /* instr[31] = 0
5150 instr[30] = lower (0) / upper (1)
5151 instr[29] = signed (0) / unsigned (1)
5152 instr[28,24] = 0 1110
5153 instr[23,22] = size: bytes (00), half (01), word (10)
5154 instr[21] = 1
5155 insrt[20,16] = Vm
5156 instr[15,10] = 0010 00
5157 instr[9,5] = Vn
5158 instr[4,0] = V dest. */
5159
ef0d8ffc
NC
5160 unsigned size = INSTR (23, 22);
5161 unsigned vm = INSTR (20, 16);
5162 unsigned vn = INSTR (9, 5);
5163 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5164 unsigned bias = 0;
5165 unsigned i;
5166
5167 NYI_assert (28, 24, 0x0E);
5168 NYI_assert (21, 21, 1);
5169 NYI_assert (15, 10, 0x08);
5170
5171 if (size == 3)
5172 HALT_UNALLOC;
5173
2cdad34c 5174 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5175 switch (INSTR (30, 29))
2e8cf49e
NC
5176 {
5177 case 2: /* SSUBL2. */
5178 bias = 2;
5179 case 0: /* SSUBL. */
5180 switch (size)
5181 {
5182 case 0:
5183 bias *= 3;
5184 for (i = 0; i < 8; i++)
5185 aarch64_set_vec_s16 (cpu, vd, i,
5186 aarch64_get_vec_s8 (cpu, vn, i + bias)
5187 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5188 break;
5189
5190 case 1:
5191 bias *= 2;
5192 for (i = 0; i < 4; i++)
5193 aarch64_set_vec_s32 (cpu, vd, i,
5194 aarch64_get_vec_s16 (cpu, vn, i + bias)
5195 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5196 break;
5197
5198 case 2:
5199 for (i = 0; i < 2; i++)
5200 aarch64_set_vec_s64 (cpu, vd, i,
5201 aarch64_get_vec_s32 (cpu, vn, i + bias)
5202 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5203 break;
5204
5205 default:
5206 HALT_UNALLOC;
5207 }
5208 break;
5209
5210 case 3: /* USUBL2. */
5211 bias = 2;
5212 case 1: /* USUBL. */
5213 switch (size)
5214 {
5215 case 0:
5216 bias *= 3;
5217 for (i = 0; i < 8; i++)
5218 aarch64_set_vec_u16 (cpu, vd, i,
5219 aarch64_get_vec_u8 (cpu, vn, i + bias)
5220 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5221 break;
5222
5223 case 1:
5224 bias *= 2;
5225 for (i = 0; i < 4; i++)
5226 aarch64_set_vec_u32 (cpu, vd, i,
5227 aarch64_get_vec_u16 (cpu, vn, i + bias)
5228 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5229 break;
5230
5231 case 2:
5232 for (i = 0; i < 2; i++)
5233 aarch64_set_vec_u64 (cpu, vd, i,
5234 aarch64_get_vec_u32 (cpu, vn, i + bias)
5235 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5236 break;
5237
5238 default:
5239 HALT_UNALLOC;
5240 }
5241 break;
5242 }
5243}
5244
2e8cf49e
NC
5245static void
5246do_vec_ADDP (sim_cpu *cpu)
5247{
5248 /* instr[31] = 0
5249 instr[30] = half(0)/full(1)
5250 instr[29,24] = 00 1110
5251 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5252 instr[21] = 1
5253 insrt[20,16] = Vm
5254 instr[15,10] = 1011 11
5255 instr[9,5] = Vn
5256 instr[4,0] = V dest. */
5257
57aa1742
NC
5258 FRegister copy_vn;
5259 FRegister copy_vm;
ef0d8ffc
NC
5260 unsigned full = INSTR (30, 30);
5261 unsigned size = INSTR (23, 22);
5262 unsigned vm = INSTR (20, 16);
5263 unsigned vn = INSTR (9, 5);
5264 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5265 unsigned i, range;
5266
5267 NYI_assert (29, 24, 0x0E);
5268 NYI_assert (21, 21, 1);
5269 NYI_assert (15, 10, 0x2F);
5270
57aa1742
NC
5271 /* Make copies of the source registers in case vd == vn/vm. */
5272 copy_vn = cpu->fr[vn];
5273 copy_vm = cpu->fr[vm];
5274
2cdad34c 5275 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
5276 switch (size)
5277 {
5278 case 0:
5279 range = full ? 8 : 4;
57aa1742
NC
5280 for (i = 0; i < range; i++)
5281 {
5282 aarch64_set_vec_u8 (cpu, vd, i,
5283 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5284 aarch64_set_vec_u8 (cpu, vd, i + range,
5285 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5286 }
2e8cf49e
NC
5287 return;
5288
5289 case 1:
5290 range = full ? 4 : 2;
57aa1742
NC
5291 for (i = 0; i < range; i++)
5292 {
5293 aarch64_set_vec_u16 (cpu, vd, i,
5294 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5295 aarch64_set_vec_u16 (cpu, vd, i + range,
5296 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5297 }
2e8cf49e
NC
5298 return;
5299
5300 case 2:
5301 range = full ? 2 : 1;
57aa1742
NC
5302 for (i = 0; i < range; i++)
5303 {
5304 aarch64_set_vec_u32 (cpu, vd, i,
5305 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5306 aarch64_set_vec_u32 (cpu, vd, i + range,
5307 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5308 }
2e8cf49e
NC
5309 return;
5310
5311 case 3:
5312 if (! full)
5313 HALT_UNALLOC;
57aa1742
NC
5314 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5315 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5316 return;
2e8cf49e
NC
5317 }
5318}
5319
5320static void
5321do_vec_UMOV (sim_cpu *cpu)
5322{
5323 /* instr[31] = 0
5324 instr[30] = 32-bit(0)/64-bit(1)
5325 instr[29,21] = 00 1110 000
5326 insrt[20,16] = size & index
5327 instr[15,10] = 0011 11
5328 instr[9,5] = V source
5329 instr[4,0] = R dest. */
5330
ef0d8ffc
NC
5331 unsigned vs = INSTR (9, 5);
5332 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
5333 unsigned index;
5334
5335 NYI_assert (29, 21, 0x070);
5336 NYI_assert (15, 10, 0x0F);
5337
2cdad34c 5338 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5339 if (INSTR (16, 16))
2e8cf49e
NC
5340 {
5341 /* Byte transfer. */
ef0d8ffc 5342 index = INSTR (20, 17);
2e8cf49e
NC
5343 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5344 aarch64_get_vec_u8 (cpu, vs, index));
5345 }
ef0d8ffc 5346 else if (INSTR (17, 17))
2e8cf49e 5347 {
ef0d8ffc 5348 index = INSTR (20, 18);
2e8cf49e
NC
5349 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5350 aarch64_get_vec_u16 (cpu, vs, index));
5351 }
ef0d8ffc 5352 else if (INSTR (18, 18))
2e8cf49e 5353 {
ef0d8ffc 5354 index = INSTR (20, 19);
2e8cf49e
NC
5355 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5356 aarch64_get_vec_u32 (cpu, vs, index));
5357 }
5358 else
5359 {
ef0d8ffc 5360 if (INSTR (30, 30) != 1)
2e8cf49e
NC
5361 HALT_UNALLOC;
5362
ef0d8ffc 5363 index = INSTR (20, 20);
2e8cf49e
NC
5364 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5365 aarch64_get_vec_u64 (cpu, vs, index));
5366 }
5367}
5368
5369static void
5370do_vec_FABS (sim_cpu *cpu)
5371{
5372 /* instr[31] = 0
5373 instr[30] = half(0)/full(1)
5374 instr[29,23] = 00 1110 1
5375 instr[22] = float(0)/double(1)
5376 instr[21,16] = 10 0000
5377 instr[15,10] = 1111 10
5378 instr[9,5] = Vn
5379 instr[4,0] = Vd. */
5380
ef0d8ffc
NC
5381 unsigned vn = INSTR (9, 5);
5382 unsigned vd = INSTR (4, 0);
5383 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5384 unsigned i;
5385
5386 NYI_assert (29, 23, 0x1D);
5387 NYI_assert (21, 10, 0x83E);
5388
2cdad34c 5389 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5390 if (INSTR (22, 22))
2e8cf49e
NC
5391 {
5392 if (! full)
5393 HALT_NYI;
5394
5395 for (i = 0; i < 2; i++)
5396 aarch64_set_vec_double (cpu, vd, i,
5397 fabs (aarch64_get_vec_double (cpu, vn, i)));
5398 }
5399 else
5400 {
5401 for (i = 0; i < (full ? 4 : 2); i++)
5402 aarch64_set_vec_float (cpu, vd, i,
5403 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5404 }
5405}
5406
5407static void
5408do_vec_FCVTZS (sim_cpu *cpu)
5409{
5410 /* instr[31] = 0
5411 instr[30] = half (0) / all (1)
5412 instr[29,23] = 00 1110 1
5413 instr[22] = single (0) / double (1)
5414 instr[21,10] = 10 0001 1011 10
5415 instr[9,5] = Rn
5416 instr[4,0] = Rd. */
5417
ef0d8ffc
NC
5418 unsigned rn = INSTR (9, 5);
5419 unsigned rd = INSTR (4, 0);
5420 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5421 unsigned i;
5422
5423 NYI_assert (31, 31, 0);
5424 NYI_assert (29, 23, 0x1D);
5425 NYI_assert (21, 10, 0x86E);
5426
2cdad34c 5427 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5428 if (INSTR (22, 22))
2e8cf49e
NC
5429 {
5430 if (! full)
5431 HALT_UNALLOC;
5432
5433 for (i = 0; i < 2; i++)
5434 aarch64_set_vec_s64 (cpu, rd, i,
5435 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5436 }
5437 else
5438 for (i = 0; i < (full ? 4 : 2); i++)
5439 aarch64_set_vec_s32 (cpu, rd, i,
5440 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5441}
5442
67f101ee
NC
5443static void
5444do_vec_REV64 (sim_cpu *cpu)
5445{
5446 /* instr[31] = 0
5447 instr[30] = full/half
5448 instr[29,24] = 00 1110
5449 instr[23,22] = size
5450 instr[21,10] = 10 0000 0000 10
5451 instr[9,5] = Rn
5452 instr[4,0] = Rd. */
5453
5454 unsigned rn = INSTR (9, 5);
5455 unsigned rd = INSTR (4, 0);
5456 unsigned size = INSTR (23, 22);
5457 unsigned full = INSTR (30, 30);
5458 unsigned i;
5459 FRegister val;
5460
5461 NYI_assert (29, 24, 0x0E);
5462 NYI_assert (21, 10, 0x802);
5463
2cdad34c 5464 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5465 switch (size)
5466 {
5467 case 0:
5468 for (i = 0; i < (full ? 16 : 8); i++)
5469 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5470 break;
5471
5472 case 1:
5473 for (i = 0; i < (full ? 8 : 4); i++)
5474 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5475 break;
5476
5477 case 2:
5478 for (i = 0; i < (full ? 4 : 2); i++)
5479 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5480 break;
5481
5482 case 3:
5483 HALT_UNALLOC;
5484 }
5485
5486 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5487 if (full)
5488 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5489}
5490
5491static void
5492do_vec_REV16 (sim_cpu *cpu)
5493{
5494 /* instr[31] = 0
5495 instr[30] = full/half
5496 instr[29,24] = 00 1110
5497 instr[23,22] = size
5498 instr[21,10] = 10 0000 0001 10
5499 instr[9,5] = Rn
5500 instr[4,0] = Rd. */
5501
5502 unsigned rn = INSTR (9, 5);
5503 unsigned rd = INSTR (4, 0);
5504 unsigned size = INSTR (23, 22);
5505 unsigned full = INSTR (30, 30);
5506 unsigned i;
5507 FRegister val;
5508
5509 NYI_assert (29, 24, 0x0E);
5510 NYI_assert (21, 10, 0x806);
5511
2cdad34c 5512 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5513 switch (size)
5514 {
5515 case 0:
5516 for (i = 0; i < (full ? 16 : 8); i++)
5517 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5518 break;
5519
5520 default:
5521 HALT_UNALLOC;
5522 }
5523
5524 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5525 if (full)
5526 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5527}
5528
2e8cf49e
NC
5529static void
5530do_vec_op1 (sim_cpu *cpu)
5531{
5532 /* instr[31] = 0
5533 instr[30] = half/full
5534 instr[29,24] = 00 1110
5535 instr[23,21] = ???
5536 instr[20,16] = Vm
5537 instr[15,10] = sub-opcode
5538 instr[9,5] = Vn
5539 instr[4,0] = Vd */
5540 NYI_assert (29, 24, 0x0E);
5541
ef0d8ffc 5542 if (INSTR (21, 21) == 0)
2e8cf49e 5543 {
ef0d8ffc 5544 if (INSTR (23, 22) == 0)
2e8cf49e 5545 {
ef0d8ffc
NC
5546 if (INSTR (30, 30) == 1
5547 && INSTR (17, 14) == 0
5548 && INSTR (12, 10) == 7)
2e8cf49e
NC
5549 return do_vec_ins_2 (cpu);
5550
ef0d8ffc 5551 switch (INSTR (15, 10))
2e8cf49e
NC
5552 {
5553 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5554 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5555 case 0x07: do_vec_INS (cpu); return;
5556 case 0x0A: do_vec_TRN (cpu); return;
5557
5558 case 0x0F:
ef0d8ffc 5559 if (INSTR (17, 16) == 0)
2e8cf49e
NC
5560 {
5561 do_vec_MOV_into_scalar (cpu);
5562 return;
5563 }
5564 break;
5565
5566 case 0x00:
5567 case 0x08:
5568 case 0x10:
5569 case 0x18:
5570 do_vec_TBL (cpu); return;
5571
5572 case 0x06:
5573 case 0x16:
5574 do_vec_UZP (cpu); return;
5575
5576 case 0x0E:
5577 case 0x1E:
5578 do_vec_ZIP (cpu); return;
5579
5580 default:
5581 HALT_NYI;
5582 }
5583 }
5584
ef0d8ffc 5585 switch (INSTR (13, 10))
2e8cf49e
NC
5586 {
5587 case 0x6: do_vec_UZP (cpu); return;
5588 case 0xE: do_vec_ZIP (cpu); return;
5589 case 0xA: do_vec_TRN (cpu); return;
5590 case 0xF: do_vec_UMOV (cpu); return;
5591 default: HALT_NYI;
5592 }
5593 }
5594
ef0d8ffc 5595 switch (INSTR (15, 10))
2e8cf49e 5596 {
67f101ee
NC
5597 case 0x02: do_vec_REV64 (cpu); return;
5598 case 0x06: do_vec_REV16 (cpu); return;
5599
2e8cf49e 5600 case 0x07:
ef0d8ffc 5601 switch (INSTR (23, 21))
2e8cf49e
NC
5602 {
5603 case 1: do_vec_AND (cpu); return;
5604 case 3: do_vec_BIC (cpu); return;
5605 case 5: do_vec_ORR (cpu); return;
5606 case 7: do_vec_ORN (cpu); return;
5607 default: HALT_NYI;
5608 }
5609
5610 case 0x08: do_vec_sub_long (cpu); return;
5611 case 0x0a: do_vec_XTN (cpu); return;
5612 case 0x11: do_vec_SSHL (cpu); return;
5613 case 0x19: do_vec_max (cpu); return;
5614 case 0x1B: do_vec_min (cpu); return;
5615 case 0x21: do_vec_add (cpu); return;
5616 case 0x25: do_vec_MLA (cpu); return;
5617 case 0x27: do_vec_mul (cpu); return;
5618 case 0x2F: do_vec_ADDP (cpu); return;
5619 case 0x30: do_vec_mull (cpu); return;
5620 case 0x33: do_vec_FMLA (cpu); return;
5621 case 0x35: do_vec_fadd (cpu); return;
5622
5623 case 0x2E:
ef0d8ffc 5624 switch (INSTR (20, 16))
2e8cf49e
NC
5625 {
5626 case 0x00: do_vec_ABS (cpu); return;
5627 case 0x01: do_vec_FCVTZS (cpu); return;
5628 case 0x11: do_vec_ADDV (cpu); return;
5629 default: HALT_NYI;
5630 }
5631
5632 case 0x31:
5633 case 0x3B:
5634 do_vec_Fminmax (cpu); return;
5635
5636 case 0x0D:
5637 case 0x0F:
5638 case 0x22:
5639 case 0x23:
5640 case 0x26:
5641 case 0x2A:
5642 case 0x32:
5643 case 0x36:
5644 case 0x39:
5645 case 0x3A:
5646 do_vec_compare (cpu); return;
5647
5648 case 0x3E:
5649 do_vec_FABS (cpu); return;
5650
5651 default:
5652 HALT_NYI;
5653 }
5654}
5655
5656static void
5657do_vec_xtl (sim_cpu *cpu)
5658{
5659 /* instr[31] = 0
5660 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5661 instr[28,22] = 0 1111 00
5662 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5663 instr[15,10] = 1010 01
5664 instr[9,5] = V source
5665 instr[4,0] = V dest. */
5666
ef0d8ffc
NC
5667 unsigned vs = INSTR (9, 5);
5668 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5669 unsigned i, shift, bias = 0;
5670
5671 NYI_assert (28, 22, 0x3C);
5672 NYI_assert (15, 10, 0x29);
5673
2cdad34c 5674 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5675 switch (INSTR (30, 29))
2e8cf49e
NC
5676 {
5677 case 2: /* SXTL2, SSHLL2. */
5678 bias = 2;
5679 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5680 if (INSTR (21, 21))
2e8cf49e 5681 {
7517e550
NC
5682 int64_t val1, val2;
5683
ef0d8ffc 5684 shift = INSTR (20, 16);
7517e550
NC
5685 /* Get the source values before setting the destination values
5686 in case the source and destination are the same. */
5687 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5688 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5689 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5690 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5691 }
ef0d8ffc 5692 else if (INSTR (20, 20))
2e8cf49e 5693 {
7517e550
NC
5694 int32_t v[4];
5695 int32_t v1,v2,v3,v4;
5696
ef0d8ffc 5697 shift = INSTR (19, 16);
2e8cf49e
NC
5698 bias *= 2;
5699 for (i = 0; i < 4; i++)
7517e550
NC
5700 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5701 for (i = 0; i < 4; i++)
5702 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5703 }
5704 else
5705 {
7517e550 5706 int16_t v[8];
2e8cf49e
NC
5707 NYI_assert (19, 19, 1);
5708
ef0d8ffc 5709 shift = INSTR (18, 16);
2e8cf49e
NC
5710 bias *= 3;
5711 for (i = 0; i < 8; i++)
7517e550
NC
5712 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5713 for (i = 0; i < 8; i++)
5714 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5715 }
5716 return;
5717
5718 case 3: /* UXTL2, USHLL2. */
5719 bias = 2;
5720 case 1: /* UXTL, USHLL. */
ef0d8ffc 5721 if (INSTR (21, 21))
2e8cf49e 5722 {
7517e550 5723 uint64_t v1, v2;
ef0d8ffc 5724 shift = INSTR (20, 16);
7517e550
NC
5725 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5726 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5727 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5728 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5729 }
ef0d8ffc 5730 else if (INSTR (20, 20))
2e8cf49e 5731 {
7517e550 5732 uint32_t v[4];
ef0d8ffc 5733 shift = INSTR (19, 16);
2e8cf49e
NC
5734 bias *= 2;
5735 for (i = 0; i < 4; i++)
7517e550
NC
5736 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5737 for (i = 0; i < 4; i++)
5738 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5739 }
5740 else
5741 {
7517e550 5742 uint16_t v[8];
2e8cf49e
NC
5743 NYI_assert (19, 19, 1);
5744
ef0d8ffc 5745 shift = INSTR (18, 16);
2e8cf49e
NC
5746 bias *= 3;
5747 for (i = 0; i < 8; i++)
7517e550
NC
5748 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5749 for (i = 0; i < 8; i++)
5750 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5751 }
5752 return;
2e8cf49e
NC
5753 }
5754}
5755
5756static void
5757do_vec_SHL (sim_cpu *cpu)
5758{
5759 /* instr [31] = 0
5760 instr [30] = half(0)/full(1)
5761 instr [29,23] = 001 1110
5762 instr [22,16] = size and shift amount
5763 instr [15,10] = 01 0101
5764 instr [9, 5] = Vs
5765 instr [4, 0] = Vd. */
5766
5767 int shift;
ef0d8ffc
NC
5768 int full = INSTR (30, 30);
5769 unsigned vs = INSTR (9, 5);
5770 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5771 unsigned i;
5772
5773 NYI_assert (29, 23, 0x1E);
5774 NYI_assert (15, 10, 0x15);
5775
2cdad34c 5776 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5777 if (INSTR (22, 22))
2e8cf49e 5778 {
ef0d8ffc 5779 shift = INSTR (21, 16);
2e8cf49e
NC
5780
5781 if (full == 0)
5782 HALT_UNALLOC;
5783
5784 for (i = 0; i < 2; i++)
5785 {
5786 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5787 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5788 }
5789
5790 return;
5791 }
5792
ef0d8ffc 5793 if (INSTR (21, 21))
2e8cf49e 5794 {
ef0d8ffc 5795 shift = INSTR (20, 16);
2e8cf49e
NC
5796
5797 for (i = 0; i < (full ? 4 : 2); i++)
5798 {
5799 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5800 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5801 }
5802
5803 return;
5804 }
5805
ef0d8ffc 5806 if (INSTR (20, 20))
2e8cf49e 5807 {
ef0d8ffc 5808 shift = INSTR (19, 16);
2e8cf49e
NC
5809
5810 for (i = 0; i < (full ? 8 : 4); i++)
5811 {
5812 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5813 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5814 }
5815
5816 return;
5817 }
5818
ef0d8ffc 5819 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5820 HALT_UNALLOC;
5821
ef0d8ffc 5822 shift = INSTR (18, 16);
2e8cf49e
NC
5823
5824 for (i = 0; i < (full ? 16 : 8); i++)
5825 {
5826 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5827 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5828 }
5829}
5830
5831static void
5832do_vec_SSHR_USHR (sim_cpu *cpu)
5833{
5834 /* instr [31] = 0
5835 instr [30] = half(0)/full(1)
5836 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5837 instr [28,23] = 0 1111 0
2e8cf49e
NC
5838 instr [22,16] = size and shift amount
5839 instr [15,10] = 0000 01
5840 instr [9, 5] = Vs
5841 instr [4, 0] = Vd. */
5842
5ab6d79e
NC
5843 int full = INSTR (30, 30);
5844 int sign = ! INSTR (29, 29);
5845 unsigned shift = INSTR (22, 16);
5846 unsigned vs = INSTR (9, 5);
5847 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5848 unsigned i;
5849
5850 NYI_assert (28, 23, 0x1E);
5851 NYI_assert (15, 10, 0x01);
5852
2cdad34c 5853 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5854 if (INSTR (22, 22))
2e8cf49e 5855 {
5ab6d79e 5856 shift = 128 - shift;
2e8cf49e
NC
5857
5858 if (full == 0)
5859 HALT_UNALLOC;
5860
5861 if (sign)
5862 for (i = 0; i < 2; i++)
5863 {
5864 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5865 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5866 }
5867 else
5868 for (i = 0; i < 2; i++)
5869 {
5870 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5871 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5872 }
5873
5874 return;
5875 }
5876
ef0d8ffc 5877 if (INSTR (21, 21))
2e8cf49e 5878 {
5ab6d79e 5879 shift = 64 - shift;
2e8cf49e
NC
5880
5881 if (sign)
5882 for (i = 0; i < (full ? 4 : 2); i++)
5883 {
5884 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5885 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5886 }
5887 else
5888 for (i = 0; i < (full ? 4 : 2); i++)
5889 {
5890 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5891 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5892 }
5893
5894 return;
5895 }
5896
ef0d8ffc 5897 if (INSTR (20, 20))
2e8cf49e 5898 {
5ab6d79e 5899 shift = 32 - shift;
2e8cf49e
NC
5900
5901 if (sign)
5902 for (i = 0; i < (full ? 8 : 4); i++)
5903 {
5904 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5905 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5906 }
5907 else
5908 for (i = 0; i < (full ? 8 : 4); i++)
5909 {
5910 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5911 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5912 }
5913
5914 return;
5915 }
5916
ef0d8ffc 5917 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5918 HALT_UNALLOC;
5919
5ab6d79e 5920 shift = 16 - shift;
2e8cf49e
NC
5921
5922 if (sign)
5923 for (i = 0; i < (full ? 16 : 8); i++)
5924 {
5925 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5926 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5927 }
5928 else
5929 for (i = 0; i < (full ? 16 : 8); i++)
5930 {
5931 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5932 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5933 }
5934}
5935
e101a78b
NC
5936static void
5937do_vec_MUL_by_element (sim_cpu *cpu)
5938{
5939 /* instr[31] = 0
5940 instr[30] = half/full
5941 instr[29,24] = 00 1111
5942 instr[23,22] = size
5943 instr[21] = L
5944 instr[20] = M
5945 instr[19,16] = m
5946 instr[15,12] = 1000
5947 instr[11] = H
5948 instr[10] = 0
5949 instr[9,5] = Vn
5950 instr[4,0] = Vd */
5951
ef0d8ffc
NC
5952 unsigned full = INSTR (30, 30);
5953 unsigned L = INSTR (21, 21);
5954 unsigned H = INSTR (11, 11);
5955 unsigned vn = INSTR (9, 5);
5956 unsigned vd = INSTR (4, 0);
5957 unsigned size = INSTR (23, 22);
e101a78b
NC
5958 unsigned index;
5959 unsigned vm;
5960 unsigned e;
5961
5962 NYI_assert (29, 24, 0x0F);
5963 NYI_assert (15, 12, 0x8);
5964 NYI_assert (10, 10, 0);
5965
2cdad34c 5966 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
5967 switch (size)
5968 {
5969 case 1:
5970 {
5971 /* 16 bit products. */
5972 uint16_t product;
5973 uint16_t element1;
5974 uint16_t element2;
5975
ef0d8ffc
NC
5976 index = (H << 2) | (L << 1) | INSTR (20, 20);
5977 vm = INSTR (19, 16);
e101a78b
NC
5978 element2 = aarch64_get_vec_u16 (cpu, vm, index);
5979
5980 for (e = 0; e < (full ? 8 : 4); e ++)
5981 {
5982 element1 = aarch64_get_vec_u16 (cpu, vn, e);
5983 product = element1 * element2;
5984 aarch64_set_vec_u16 (cpu, vd, e, product);
5985 }
5986 }
5987 break;
5988
5989 case 2:
5990 {
5991 /* 32 bit products. */
5992 uint32_t product;
5993 uint32_t element1;
5994 uint32_t element2;
5995
5996 index = (H << 1) | L;
ef0d8ffc 5997 vm = INSTR (20, 16);
e101a78b
NC
5998 element2 = aarch64_get_vec_u32 (cpu, vm, index);
5999
6000 for (e = 0; e < (full ? 4 : 2); e ++)
6001 {
6002 element1 = aarch64_get_vec_u32 (cpu, vn, e);
6003 product = element1 * element2;
6004 aarch64_set_vec_u32 (cpu, vd, e, product);
6005 }
6006 }
6007 break;
6008
6009 default:
6010 HALT_UNALLOC;
6011 }
6012}
6013
fd7ed446
NC
6014static void
6015do_FMLA_by_element (sim_cpu *cpu)
6016{
6017 /* instr[31] = 0
6018 instr[30] = half/full
6019 instr[29,23] = 00 1111 1
6020 instr[22] = size
6021 instr[21] = L
6022 instr[20,16] = m
6023 instr[15,12] = 0001
6024 instr[11] = H
6025 instr[10] = 0
6026 instr[9,5] = Vn
6027 instr[4,0] = Vd */
6028
6029 unsigned full = INSTR (30, 30);
6030 unsigned size = INSTR (22, 22);
6031 unsigned L = INSTR (21, 21);
6032 unsigned vm = INSTR (20, 16);
6033 unsigned H = INSTR (11, 11);
6034 unsigned vn = INSTR (9, 5);
6035 unsigned vd = INSTR (4, 0);
6036 unsigned e;
6037
6038 NYI_assert (29, 23, 0x1F);
6039 NYI_assert (15, 12, 0x1);
6040 NYI_assert (10, 10, 0);
6041
6042 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
6043 if (size)
6044 {
6045 double element1, element2;
6046
6047 if (! full || L)
6048 HALT_UNALLOC;
6049
6050 element2 = aarch64_get_vec_double (cpu, vm, H);
6051
6052 for (e = 0; e < 2; e++)
6053 {
6054 element1 = aarch64_get_vec_double (cpu, vn, e);
6055 element1 *= element2;
6056 element1 += aarch64_get_vec_double (cpu, vd, e);
6057 aarch64_set_vec_double (cpu, vd, e, element1);
6058 }
6059 }
6060 else
6061 {
6062 float element1;
6063 float element2 = aarch64_get_vec_float (cpu, vm, (H << 1) | L);
6064
6065 for (e = 0; e < (full ? 4 : 2); e++)
6066 {
6067 element1 = aarch64_get_vec_float (cpu, vn, e);
6068 element1 *= element2;
6069 element1 += aarch64_get_vec_float (cpu, vd, e);
6070 aarch64_set_vec_float (cpu, vd, e, element1);
6071 }
6072 }
6073}
6074
2e8cf49e
NC
6075static void
6076do_vec_op2 (sim_cpu *cpu)
6077{
6078 /* instr[31] = 0
6079 instr[30] = half/full
6080 instr[29,24] = 00 1111
6081 instr[23] = ?
6082 instr[22,16] = element size & index
6083 instr[15,10] = sub-opcode
6084 instr[9,5] = Vm
e101a78b 6085 instr[4,0] = Vd */
2e8cf49e
NC
6086
6087 NYI_assert (29, 24, 0x0F);
6088
ef0d8ffc 6089 if (INSTR (23, 23) != 0)
2e8cf49e 6090 {
ef0d8ffc 6091 switch (INSTR (15, 10))
e101a78b 6092 {
fd7ed446
NC
6093 case 0x04:
6094 case 0x06:
6095 do_FMLA_by_element (cpu);
6096 return;
6097
e101a78b 6098 case 0x20:
fd7ed446
NC
6099 case 0x22:
6100 do_vec_MUL_by_element (cpu);
6101 return;
6102
6103 default:
6104 HALT_NYI;
e101a78b
NC
6105 }
6106 }
6107 else
6108 {
ef0d8ffc 6109 switch (INSTR (15, 10))
e101a78b
NC
6110 {
6111 case 0x01: do_vec_SSHR_USHR (cpu); return;
6112 case 0x15: do_vec_SHL (cpu); return;
6113 case 0x20:
6114 case 0x22: do_vec_MUL_by_element (cpu); return;
6115 case 0x29: do_vec_xtl (cpu); return;
6116 default: HALT_NYI;
6117 }
2e8cf49e
NC
6118 }
6119}
6120
6121static void
6122do_vec_neg (sim_cpu *cpu)
6123{
6124 /* instr[31] = 0
6125 instr[30] = full(1)/half(0)
6126 instr[29,24] = 10 1110
6127 instr[23,22] = size: byte(00), half (01), word (10), long (11)
6128 instr[21,10] = 1000 0010 1110
6129 instr[9,5] = Vs
6130 instr[4,0] = Vd */
6131
ef0d8ffc
NC
6132 int full = INSTR (30, 30);
6133 unsigned vs = INSTR (9, 5);
6134 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6135 unsigned i;
6136
6137 NYI_assert (29, 24, 0x2E);
6138 NYI_assert (21, 10, 0x82E);
6139
2cdad34c 6140 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6141 switch (INSTR (23, 22))
2e8cf49e
NC
6142 {
6143 case 0:
6144 for (i = 0; i < (full ? 16 : 8); i++)
6145 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
6146 return;
6147
6148 case 1:
6149 for (i = 0; i < (full ? 8 : 4); i++)
6150 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
6151 return;
6152
6153 case 2:
6154 for (i = 0; i < (full ? 4 : 2); i++)
6155 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
6156 return;
6157
6158 case 3:
6159 if (! full)
6160 HALT_NYI;
6161 for (i = 0; i < 2; i++)
6162 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
6163 return;
2e8cf49e
NC
6164 }
6165}
6166
6167static void
6168do_vec_sqrt (sim_cpu *cpu)
6169{
6170 /* instr[31] = 0
6171 instr[30] = full(1)/half(0)
6172 instr[29,23] = 101 1101
6173 instr[22] = single(0)/double(1)
6174 instr[21,10] = 1000 0111 1110
6175 instr[9,5] = Vs
6176 instr[4,0] = Vd. */
6177
ef0d8ffc
NC
6178 int full = INSTR (30, 30);
6179 unsigned vs = INSTR (9, 5);
6180 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6181 unsigned i;
6182
6183 NYI_assert (29, 23, 0x5B);
6184 NYI_assert (21, 10, 0x87E);
6185
2cdad34c 6186 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6187 if (INSTR (22, 22) == 0)
2e8cf49e
NC
6188 for (i = 0; i < (full ? 4 : 2); i++)
6189 aarch64_set_vec_float (cpu, vd, i,
6190 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
6191 else
6192 for (i = 0; i < 2; i++)
6193 aarch64_set_vec_double (cpu, vd, i,
6194 sqrt (aarch64_get_vec_double (cpu, vs, i)));
6195}
6196
6197static void
6198do_vec_mls_indexed (sim_cpu *cpu)
6199{
6200 /* instr[31] = 0
6201 instr[30] = half(0)/full(1)
6202 instr[29,24] = 10 1111
6203 instr[23,22] = 16-bit(01)/32-bit(10)
6204 instr[21,20+11] = index (if 16-bit)
6205 instr[21+11] = index (if 32-bit)
6206 instr[20,16] = Vm
6207 instr[15,12] = 0100
6208 instr[11] = part of index
6209 instr[10] = 0
6210 instr[9,5] = Vs
6211 instr[4,0] = Vd. */
6212
ef0d8ffc
NC
6213 int full = INSTR (30, 30);
6214 unsigned vs = INSTR (9, 5);
6215 unsigned vd = INSTR (4, 0);
6216 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6217 unsigned i;
6218
6219 NYI_assert (15, 12, 4);
6220 NYI_assert (10, 10, 0);
6221
2cdad34c 6222 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6223 switch (INSTR (23, 22))
2e8cf49e
NC
6224 {
6225 case 1:
6226 {
6227 unsigned elem;
6228 uint32_t val;
6229
6230 if (vm > 15)
6231 HALT_NYI;
6232
7517e550 6233 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6234 val = aarch64_get_vec_u16 (cpu, vm, elem);
6235
6236 for (i = 0; i < (full ? 8 : 4); i++)
6237 aarch64_set_vec_u32 (cpu, vd, i,
6238 aarch64_get_vec_u32 (cpu, vd, i) -
6239 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6240 return;
6241 }
6242
6243 case 2:
6244 {
7517e550 6245 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6246 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6247
6248 for (i = 0; i < (full ? 4 : 2); i++)
6249 aarch64_set_vec_u64 (cpu, vd, i,
6250 aarch64_get_vec_u64 (cpu, vd, i) -
6251 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6252 return;
6253 }
6254
6255 case 0:
6256 case 3:
6257 default:
6258 HALT_NYI;
6259 }
6260}
6261
6262static void
6263do_vec_SUB (sim_cpu *cpu)
6264{
6265 /* instr [31] = 0
6266 instr [30] = half(0)/full(1)
6267 instr [29,24] = 10 1110
6268 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6269 instr [21] = 1
6270 instr [20,16] = Vm
6271 instr [15,10] = 10 0001
6272 instr [9, 5] = Vn
6273 instr [4, 0] = Vd. */
6274
ef0d8ffc
NC
6275 unsigned full = INSTR (30, 30);
6276 unsigned vm = INSTR (20, 16);
6277 unsigned vn = INSTR (9, 5);
6278 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6279 unsigned i;
6280
6281 NYI_assert (29, 24, 0x2E);
6282 NYI_assert (21, 21, 1);
6283 NYI_assert (15, 10, 0x21);
6284
2cdad34c 6285 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6286 switch (INSTR (23, 22))
2e8cf49e
NC
6287 {
6288 case 0:
6289 for (i = 0; i < (full ? 16 : 8); i++)
6290 aarch64_set_vec_s8 (cpu, vd, i,
6291 aarch64_get_vec_s8 (cpu, vn, i)
6292 - aarch64_get_vec_s8 (cpu, vm, i));
6293 return;
6294
6295 case 1:
6296 for (i = 0; i < (full ? 8 : 4); i++)
6297 aarch64_set_vec_s16 (cpu, vd, i,
6298 aarch64_get_vec_s16 (cpu, vn, i)
6299 - aarch64_get_vec_s16 (cpu, vm, i));
6300 return;
6301
6302 case 2:
6303 for (i = 0; i < (full ? 4 : 2); i++)
6304 aarch64_set_vec_s32 (cpu, vd, i,
6305 aarch64_get_vec_s32 (cpu, vn, i)
6306 - aarch64_get_vec_s32 (cpu, vm, i));
6307 return;
6308
6309 case 3:
6310 if (full == 0)
6311 HALT_UNALLOC;
6312
6313 for (i = 0; i < 2; i++)
6314 aarch64_set_vec_s64 (cpu, vd, i,
6315 aarch64_get_vec_s64 (cpu, vn, i)
6316 - aarch64_get_vec_s64 (cpu, vm, i));
6317 return;
2e8cf49e
NC
6318 }
6319}
6320
6321static void
6322do_vec_MLS (sim_cpu *cpu)
6323{
6324 /* instr [31] = 0
6325 instr [30] = half(0)/full(1)
6326 instr [29,24] = 10 1110
6327 instr [23,22] = size: byte(00, half(01), word (10)
6328 instr [21] = 1
6329 instr [20,16] = Vm
6330 instr [15,10] = 10 0101
6331 instr [9, 5] = Vn
6332 instr [4, 0] = Vd. */
6333
ef0d8ffc
NC
6334 unsigned full = INSTR (30, 30);
6335 unsigned vm = INSTR (20, 16);
6336 unsigned vn = INSTR (9, 5);
6337 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6338 unsigned i;
6339
6340 NYI_assert (29, 24, 0x2E);
6341 NYI_assert (21, 21, 1);
6342 NYI_assert (15, 10, 0x25);
6343
2cdad34c 6344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6345 switch (INSTR (23, 22))
2e8cf49e
NC
6346 {
6347 case 0:
6348 for (i = 0; i < (full ? 16 : 8); i++)
6349 aarch64_set_vec_u8 (cpu, vd, i,
c0386d4d
JW
6350 aarch64_get_vec_u8 (cpu, vd, i)
6351 - (aarch64_get_vec_u8 (cpu, vn, i)
6352 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
6353 return;
6354
6355 case 1:
6356 for (i = 0; i < (full ? 8 : 4); i++)
6357 aarch64_set_vec_u16 (cpu, vd, i,
c0386d4d
JW
6358 aarch64_get_vec_u16 (cpu, vd, i)
6359 - (aarch64_get_vec_u16 (cpu, vn, i)
6360 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
6361 return;
6362
6363 case 2:
6364 for (i = 0; i < (full ? 4 : 2); i++)
6365 aarch64_set_vec_u32 (cpu, vd, i,
c0386d4d
JW
6366 aarch64_get_vec_u32 (cpu, vd, i)
6367 - (aarch64_get_vec_u32 (cpu, vn, i)
6368 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
6369 return;
6370
6371 default:
6372 HALT_UNALLOC;
6373 }
6374}
6375
6376static void
6377do_vec_FDIV (sim_cpu *cpu)
6378{
6379 /* instr [31] = 0
6380 instr [30] = half(0)/full(1)
6381 instr [29,23] = 10 1110 0
6382 instr [22] = float()/double(1)
6383 instr [21] = 1
6384 instr [20,16] = Vm
6385 instr [15,10] = 1111 11
6386 instr [9, 5] = Vn
6387 instr [4, 0] = Vd. */
6388
ef0d8ffc
NC
6389 unsigned full = INSTR (30, 30);
6390 unsigned vm = INSTR (20, 16);
6391 unsigned vn = INSTR (9, 5);
6392 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6393 unsigned i;
6394
6395 NYI_assert (29, 23, 0x5C);
6396 NYI_assert (21, 21, 1);
6397 NYI_assert (15, 10, 0x3F);
6398
2cdad34c 6399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6400 if (INSTR (22, 22))
2e8cf49e
NC
6401 {
6402 if (! full)
6403 HALT_UNALLOC;
6404
6405 for (i = 0; i < 2; i++)
6406 aarch64_set_vec_double (cpu, vd, i,
6407 aarch64_get_vec_double (cpu, vn, i)
6408 / aarch64_get_vec_double (cpu, vm, i));
6409 }
6410 else
6411 for (i = 0; i < (full ? 4 : 2); i++)
6412 aarch64_set_vec_float (cpu, vd, i,
6413 aarch64_get_vec_float (cpu, vn, i)
6414 / aarch64_get_vec_float (cpu, vm, i));
6415}
6416
6417static void
6418do_vec_FMUL (sim_cpu *cpu)
6419{
6420 /* instr [31] = 0
6421 instr [30] = half(0)/full(1)
6422 instr [29,23] = 10 1110 0
6423 instr [22] = float(0)/double(1)
6424 instr [21] = 1
6425 instr [20,16] = Vm
6426 instr [15,10] = 1101 11
6427 instr [9, 5] = Vn
6428 instr [4, 0] = Vd. */
6429
ef0d8ffc
NC
6430 unsigned full = INSTR (30, 30);
6431 unsigned vm = INSTR (20, 16);
6432 unsigned vn = INSTR (9, 5);
6433 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6434 unsigned i;
6435
6436 NYI_assert (29, 23, 0x5C);
6437 NYI_assert (21, 21, 1);
6438 NYI_assert (15, 10, 0x37);
6439
2cdad34c 6440 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6441 if (INSTR (22, 22))
2e8cf49e
NC
6442 {
6443 if (! full)
6444 HALT_UNALLOC;
6445
6446 for (i = 0; i < 2; i++)
6447 aarch64_set_vec_double (cpu, vd, i,
6448 aarch64_get_vec_double (cpu, vn, i)
6449 * aarch64_get_vec_double (cpu, vm, i));
6450 }
6451 else
6452 for (i = 0; i < (full ? 4 : 2); i++)
6453 aarch64_set_vec_float (cpu, vd, i,
6454 aarch64_get_vec_float (cpu, vn, i)
6455 * aarch64_get_vec_float (cpu, vm, i));
6456}
6457
6458static void
6459do_vec_FADDP (sim_cpu *cpu)
6460{
6461 /* instr [31] = 0
6462 instr [30] = half(0)/full(1)
6463 instr [29,23] = 10 1110 0
6464 instr [22] = float(0)/double(1)
6465 instr [21] = 1
6466 instr [20,16] = Vm
6467 instr [15,10] = 1101 01
6468 instr [9, 5] = Vn
6469 instr [4, 0] = Vd. */
6470
ef0d8ffc
NC
6471 unsigned full = INSTR (30, 30);
6472 unsigned vm = INSTR (20, 16);
6473 unsigned vn = INSTR (9, 5);
6474 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6475
6476 NYI_assert (29, 23, 0x5C);
6477 NYI_assert (21, 21, 1);
6478 NYI_assert (15, 10, 0x35);
6479
2cdad34c 6480 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6481 if (INSTR (22, 22))
2e8cf49e 6482 {
57aa1742
NC
6483 /* Extract values before adding them incase vd == vn/vm. */
6484 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6485 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6486 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6487 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6488
2e8cf49e
NC
6489 if (! full)
6490 HALT_UNALLOC;
6491
57aa1742
NC
6492 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6493 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6494 }
6495 else
6496 {
57aa1742
NC
6497 /* Extract values before adding them incase vd == vn/vm. */
6498 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6499 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6500 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6501 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6502
2e8cf49e 6503 if (full)
57aa1742
NC
6504 {
6505 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6506 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6507 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6508 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6509
6510 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6511 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6512 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6513 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6514 }
6515 else
6516 {
6517 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6518 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6519 }
2e8cf49e
NC
6520 }
6521}
6522
6523static void
6524do_vec_FSQRT (sim_cpu *cpu)
6525{
6526 /* instr[31] = 0
6527 instr[30] = half(0)/full(1)
6528 instr[29,23] = 10 1110 1
6529 instr[22] = single(0)/double(1)
6530 instr[21,10] = 10 0001 1111 10
6531 instr[9,5] = Vsrc
6532 instr[4,0] = Vdest. */
6533
ef0d8ffc
NC
6534 unsigned vn = INSTR (9, 5);
6535 unsigned vd = INSTR (4, 0);
6536 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6537 int i;
6538
6539 NYI_assert (29, 23, 0x5D);
6540 NYI_assert (21, 10, 0x87E);
6541
2cdad34c 6542 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6543 if (INSTR (22, 22))
2e8cf49e
NC
6544 {
6545 if (! full)
6546 HALT_UNALLOC;
6547
6548 for (i = 0; i < 2; i++)
6549 aarch64_set_vec_double (cpu, vd, i,
6550 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6551 }
6552 else
6553 {
6554 for (i = 0; i < (full ? 4 : 2); i++)
6555 aarch64_set_vec_float (cpu, vd, i,
6556 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6557 }
6558}
6559
6560static void
6561do_vec_FNEG (sim_cpu *cpu)
6562{
6563 /* instr[31] = 0
6564 instr[30] = half (0)/full (1)
6565 instr[29,23] = 10 1110 1
6566 instr[22] = single (0)/double (1)
6567 instr[21,10] = 10 0000 1111 10
6568 instr[9,5] = Vsrc
6569 instr[4,0] = Vdest. */
6570
ef0d8ffc
NC
6571 unsigned vn = INSTR (9, 5);
6572 unsigned vd = INSTR (4, 0);
6573 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6574 int i;
6575
6576 NYI_assert (29, 23, 0x5D);
6577 NYI_assert (21, 10, 0x83E);
6578
2cdad34c 6579 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6580 if (INSTR (22, 22))
2e8cf49e
NC
6581 {
6582 if (! full)
6583 HALT_UNALLOC;
6584
6585 for (i = 0; i < 2; i++)
6586 aarch64_set_vec_double (cpu, vd, i,
6587 - aarch64_get_vec_double (cpu, vn, i));
6588 }
6589 else
6590 {
6591 for (i = 0; i < (full ? 4 : 2); i++)
6592 aarch64_set_vec_float (cpu, vd, i,
6593 - aarch64_get_vec_float (cpu, vn, i));
6594 }
6595}
6596
6597static void
6598do_vec_NOT (sim_cpu *cpu)
6599{
6600 /* instr[31] = 0
6601 instr[30] = half (0)/full (1)
5ab6d79e 6602 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6603 instr[9,5] = Vn
6604 instr[4.0] = Vd. */
6605
ef0d8ffc
NC
6606 unsigned vn = INSTR (9, 5);
6607 unsigned vd = INSTR (4, 0);
2e8cf49e 6608 unsigned i;
ef0d8ffc 6609 int full = INSTR (30, 30);
2e8cf49e
NC
6610
6611 NYI_assert (29, 10, 0xB8816);
6612
2cdad34c 6613 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6614 for (i = 0; i < (full ? 16 : 8); i++)
6615 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6616}
6617
5ab6d79e
NC
6618static unsigned int
6619clz (uint64_t val, unsigned size)
6620{
6621 uint64_t mask = 1;
6622 int count;
6623
6624 mask <<= (size - 1);
6625 count = 0;
6626 do
6627 {
6628 if (val & mask)
6629 break;
6630 mask >>= 1;
6631 count ++;
6632 }
6633 while (mask);
6634
6635 return count;
6636}
6637
6638static void
6639do_vec_CLZ (sim_cpu *cpu)
6640{
6641 /* instr[31] = 0
6642 instr[30] = half (0)/full (1)
6643 instr[29,24] = 10 1110
6644 instr[23,22] = size
6645 instr[21,10] = 10 0000 0100 10
6646 instr[9,5] = Vn
6647 instr[4.0] = Vd. */
6648
6649 unsigned vn = INSTR (9, 5);
6650 unsigned vd = INSTR (4, 0);
6651 unsigned i;
6652 int full = INSTR (30,30);
6653
6654 NYI_assert (29, 24, 0x2E);
6655 NYI_assert (21, 10, 0x812);
6656
2cdad34c 6657 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
6658 switch (INSTR (23, 22))
6659 {
6660 case 0:
6661 for (i = 0; i < (full ? 16 : 8); i++)
6662 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6663 break;
6664 case 1:
6665 for (i = 0; i < (full ? 8 : 4); i++)
6666 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6667 break;
6668 case 2:
6669 for (i = 0; i < (full ? 4 : 2); i++)
6670 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6671 break;
6672 case 3:
6673 if (! full)
6674 HALT_UNALLOC;
6675 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6676 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6677 break;
6678 }
6679}
6680
2e8cf49e
NC
6681static void
6682do_vec_MOV_element (sim_cpu *cpu)
6683{
6684 /* instr[31,21] = 0110 1110 000
6685 instr[20,16] = size & dest index
6686 instr[15] = 0
6687 instr[14,11] = source index
6688 instr[10] = 1
6689 instr[9,5] = Vs
6690 instr[4.0] = Vd. */
6691
ef0d8ffc
NC
6692 unsigned vs = INSTR (9, 5);
6693 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6694 unsigned src_index;
6695 unsigned dst_index;
6696
6697 NYI_assert (31, 21, 0x370);
6698 NYI_assert (15, 15, 0);
6699 NYI_assert (10, 10, 1);
6700
2cdad34c 6701 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6702 if (INSTR (16, 16))
2e8cf49e
NC
6703 {
6704 /* Move a byte. */
ef0d8ffc
NC
6705 src_index = INSTR (14, 11);
6706 dst_index = INSTR (20, 17);
2e8cf49e
NC
6707 aarch64_set_vec_u8 (cpu, vd, dst_index,
6708 aarch64_get_vec_u8 (cpu, vs, src_index));
6709 }
ef0d8ffc 6710 else if (INSTR (17, 17))
2e8cf49e
NC
6711 {
6712 /* Move 16-bits. */
6713 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6714 src_index = INSTR (14, 12);
6715 dst_index = INSTR (20, 18);
2e8cf49e
NC
6716 aarch64_set_vec_u16 (cpu, vd, dst_index,
6717 aarch64_get_vec_u16 (cpu, vs, src_index));
6718 }
ef0d8ffc 6719 else if (INSTR (18, 18))
2e8cf49e
NC
6720 {
6721 /* Move 32-bits. */
6722 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6723 src_index = INSTR (14, 13);
6724 dst_index = INSTR (20, 19);
2e8cf49e
NC
6725 aarch64_set_vec_u32 (cpu, vd, dst_index,
6726 aarch64_get_vec_u32 (cpu, vs, src_index));
6727 }
6728 else
6729 {
6730 NYI_assert (19, 19, 1);
6731 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6732 src_index = INSTR (14, 14);
6733 dst_index = INSTR (20, 20);
2e8cf49e
NC
6734 aarch64_set_vec_u64 (cpu, vd, dst_index,
6735 aarch64_get_vec_u64 (cpu, vs, src_index));
6736 }
6737}
6738
67f101ee
NC
6739static void
6740do_vec_REV32 (sim_cpu *cpu)
6741{
6742 /* instr[31] = 0
6743 instr[30] = full/half
6744 instr[29,24] = 10 1110
6745 instr[23,22] = size
6746 instr[21,10] = 10 0000 0000 10
6747 instr[9,5] = Rn
6748 instr[4,0] = Rd. */
6749
6750 unsigned rn = INSTR (9, 5);
6751 unsigned rd = INSTR (4, 0);
6752 unsigned size = INSTR (23, 22);
6753 unsigned full = INSTR (30, 30);
6754 unsigned i;
6755 FRegister val;
6756
6757 NYI_assert (29, 24, 0x2E);
6758 NYI_assert (21, 10, 0x802);
6759
2cdad34c 6760 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6761 switch (size)
6762 {
6763 case 0:
6764 for (i = 0; i < (full ? 16 : 8); i++)
6765 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6766 break;
6767
6768 case 1:
6769 for (i = 0; i < (full ? 8 : 4); i++)
6770 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6771 break;
6772
6773 default:
6774 HALT_UNALLOC;
6775 }
6776
6777 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6778 if (full)
6779 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6780}
6781
6782static void
6783do_vec_EXT (sim_cpu *cpu)
6784{
6785 /* instr[31] = 0
6786 instr[30] = full/half
6787 instr[29,21] = 10 1110 000
6788 instr[20,16] = Vm
6789 instr[15] = 0
6790 instr[14,11] = source index
6791 instr[10] = 0
6792 instr[9,5] = Vn
6793 instr[4.0] = Vd. */
6794
6795 unsigned vm = INSTR (20, 16);
6796 unsigned vn = INSTR (9, 5);
6797 unsigned vd = INSTR (4, 0);
6798 unsigned src_index = INSTR (14, 11);
6799 unsigned full = INSTR (30, 30);
6800 unsigned i;
6801 unsigned j;
6802 FRegister val;
6803
6804 NYI_assert (31, 21, 0x370);
6805 NYI_assert (15, 15, 0);
6806 NYI_assert (10, 10, 0);
6807
6808 if (!full && (src_index & 0x8))
6809 HALT_UNALLOC;
6810
6811 j = 0;
6812
2cdad34c 6813 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6814 for (i = src_index; i < (full ? 16 : 8); i++)
6815 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6816 for (i = 0; i < src_index; i++)
6817 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6818
6819 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6820 if (full)
6821 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6822}
6823
2e8cf49e
NC
6824static void
6825dexAdvSIMD0 (sim_cpu *cpu)
6826{
6827 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6828 if ( INSTR (15, 10) == 0x07
6829 && (INSTR (9, 5) ==
6830 INSTR (20, 16)))
2e8cf49e 6831 {
ef0d8ffc
NC
6832 if (INSTR (31, 21) == 0x075
6833 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6834 {
6835 do_vec_MOV_whole_vector (cpu);
6836 return;
6837 }
6838 }
6839
ef0d8ffc 6840 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6841 {
6842 do_vec_MOV_immediate (cpu);
6843 return;
6844 }
6845
ef0d8ffc 6846 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6847 {
6848 do_vec_MVNI (cpu);
6849 return;
6850 }
6851
ef0d8ffc
NC
6852 if (INSTR (29, 19) == 0x1C0
6853 || INSTR (29, 19) == 0x1C1)
2e8cf49e 6854 {
ef0d8ffc 6855 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
6856 {
6857 do_vec_DUP_scalar_into_vector (cpu);
6858 return;
6859 }
6860 }
6861
ef0d8ffc 6862 switch (INSTR (29, 24))
2e8cf49e
NC
6863 {
6864 case 0x0E: do_vec_op1 (cpu); return;
6865 case 0x0F: do_vec_op2 (cpu); return;
6866
2e8cf49e 6867 case 0x2E:
ef0d8ffc 6868 if (INSTR (21, 21) == 1)
2e8cf49e 6869 {
ef0d8ffc 6870 switch (INSTR (15, 10))
2e8cf49e 6871 {
67f101ee
NC
6872 case 0x02:
6873 do_vec_REV32 (cpu);
6874 return;
6875
2e8cf49e 6876 case 0x07:
ef0d8ffc 6877 switch (INSTR (23, 22))
2e8cf49e
NC
6878 {
6879 case 0: do_vec_EOR (cpu); return;
6880 case 1: do_vec_BSL (cpu); return;
6881 case 2:
6882 case 3: do_vec_bit (cpu); return;
6883 }
6884 break;
6885
6886 case 0x08: do_vec_sub_long (cpu); return;
6887 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 6888 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
6889 case 0x16: do_vec_NOT (cpu); return;
6890 case 0x19: do_vec_max (cpu); return;
6891 case 0x1B: do_vec_min (cpu); return;
6892 case 0x21: do_vec_SUB (cpu); return;
6893 case 0x25: do_vec_MLS (cpu); return;
6894 case 0x31: do_vec_FminmaxNMP (cpu); return;
6895 case 0x35: do_vec_FADDP (cpu); return;
6896 case 0x37: do_vec_FMUL (cpu); return;
6897 case 0x3F: do_vec_FDIV (cpu); return;
6898
6899 case 0x3E:
ef0d8ffc 6900 switch (INSTR (20, 16))
2e8cf49e
NC
6901 {
6902 case 0x00: do_vec_FNEG (cpu); return;
6903 case 0x01: do_vec_FSQRT (cpu); return;
6904 default: HALT_NYI;
6905 }
6906
6907 case 0x0D:
6908 case 0x0F:
6909 case 0x22:
6910 case 0x23:
6911 case 0x26:
6912 case 0x2A:
6913 case 0x32:
6914 case 0x36:
6915 case 0x39:
6916 case 0x3A:
6917 do_vec_compare (cpu); return;
6918
5ab6d79e
NC
6919 default:
6920 break;
2e8cf49e
NC
6921 }
6922 }
6923
ef0d8ffc 6924 if (INSTR (31, 21) == 0x370)
2e8cf49e 6925 {
67f101ee
NC
6926 if (INSTR (10, 10))
6927 do_vec_MOV_element (cpu);
6928 else
6929 do_vec_EXT (cpu);
2e8cf49e
NC
6930 return;
6931 }
6932
ef0d8ffc 6933 switch (INSTR (21, 10))
2e8cf49e
NC
6934 {
6935 case 0x82E: do_vec_neg (cpu); return;
6936 case 0x87E: do_vec_sqrt (cpu); return;
6937 default:
ef0d8ffc 6938 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
6939 {
6940 do_vec_mull (cpu);
6941 return;
6942 }
6943 break;
6944 }
6945 break;
6946
67f101ee
NC
6947 case 0x2f:
6948 switch (INSTR (15, 10))
6949 {
6950 case 0x01: do_vec_SSHR_USHR (cpu); return;
6951 case 0x10:
6952 case 0x12: do_vec_mls_indexed (cpu); return;
6953 case 0x29: do_vec_xtl (cpu); return;
6954 default:
6955 HALT_NYI;
6956 }
6957
2e8cf49e
NC
6958 default:
6959 break;
6960 }
6961
6962 HALT_NYI;
6963}
6964
6965/* 3 sources. */
6966
6967/* Float multiply add. */
6968static void
6969fmadds (sim_cpu *cpu)
6970{
ef0d8ffc
NC
6971 unsigned sa = INSTR (14, 10);
6972 unsigned sm = INSTR (20, 16);
6973 unsigned sn = INSTR ( 9, 5);
6974 unsigned sd = INSTR ( 4, 0);
2e8cf49e 6975
2cdad34c 6976 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6977 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6978 + aarch64_get_FP_float (cpu, sn)
6979 * aarch64_get_FP_float (cpu, sm));
6980}
6981
6982/* Double multiply add. */
6983static void
6984fmaddd (sim_cpu *cpu)
6985{
ef0d8ffc
NC
6986 unsigned sa = INSTR (14, 10);
6987 unsigned sm = INSTR (20, 16);
6988 unsigned sn = INSTR ( 9, 5);
6989 unsigned sd = INSTR ( 4, 0);
2e8cf49e 6990
2cdad34c 6991 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6992 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6993 + aarch64_get_FP_double (cpu, sn)
6994 * aarch64_get_FP_double (cpu, sm));
6995}
6996
6997/* Float multiply subtract. */
6998static void
6999fmsubs (sim_cpu *cpu)
7000{
ef0d8ffc
NC
7001 unsigned sa = INSTR (14, 10);
7002 unsigned sm = INSTR (20, 16);
7003 unsigned sn = INSTR ( 9, 5);
7004 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7005
2cdad34c 7006 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7007 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7008 - aarch64_get_FP_float (cpu, sn)
7009 * aarch64_get_FP_float (cpu, sm));
7010}
7011
7012/* Double multiply subtract. */
7013static void
7014fmsubd (sim_cpu *cpu)
7015{
ef0d8ffc
NC
7016 unsigned sa = INSTR (14, 10);
7017 unsigned sm = INSTR (20, 16);
7018 unsigned sn = INSTR ( 9, 5);
7019 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7020
2cdad34c 7021 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7022 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7023 - aarch64_get_FP_double (cpu, sn)
7024 * aarch64_get_FP_double (cpu, sm));
7025}
7026
7027/* Float negative multiply add. */
7028static void
7029fnmadds (sim_cpu *cpu)
7030{
ef0d8ffc
NC
7031 unsigned sa = INSTR (14, 10);
7032 unsigned sm = INSTR (20, 16);
7033 unsigned sn = INSTR ( 9, 5);
7034 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7035
2cdad34c 7036 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7037 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7038 + (- aarch64_get_FP_float (cpu, sn))
7039 * aarch64_get_FP_float (cpu, sm));
7040}
7041
7042/* Double negative multiply add. */
7043static void
7044fnmaddd (sim_cpu *cpu)
7045{
ef0d8ffc
NC
7046 unsigned sa = INSTR (14, 10);
7047 unsigned sm = INSTR (20, 16);
7048 unsigned sn = INSTR ( 9, 5);
7049 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7050
2cdad34c 7051 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7052 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7053 + (- aarch64_get_FP_double (cpu, sn))
7054 * aarch64_get_FP_double (cpu, sm));
7055}
7056
7057/* Float negative multiply subtract. */
7058static void
7059fnmsubs (sim_cpu *cpu)
7060{
ef0d8ffc
NC
7061 unsigned sa = INSTR (14, 10);
7062 unsigned sm = INSTR (20, 16);
7063 unsigned sn = INSTR ( 9, 5);
7064 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7065
2cdad34c 7066 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7067 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7068 + aarch64_get_FP_float (cpu, sn)
7069 * aarch64_get_FP_float (cpu, sm));
7070}
7071
7072/* Double negative multiply subtract. */
7073static void
7074fnmsubd (sim_cpu *cpu)
7075{
ef0d8ffc
NC
7076 unsigned sa = INSTR (14, 10);
7077 unsigned sm = INSTR (20, 16);
7078 unsigned sn = INSTR ( 9, 5);
7079 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7080
2cdad34c 7081 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7082 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7083 + aarch64_get_FP_double (cpu, sn)
7084 * aarch64_get_FP_double (cpu, sm));
7085}
7086
7087static void
7088dexSimpleFPDataProc3Source (sim_cpu *cpu)
7089{
7090 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7091 instr[30] = 0
7092 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7093 instr[28,25] = 1111
7094 instr[24] = 1
7095 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7096 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
7097 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
7098
7517e550 7099 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 7100 /* dispatch on combined type:o1:o2. */
7517e550 7101 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
7102
7103 if (M_S != 0)
7104 HALT_UNALLOC;
7105
7106 switch (dispatch)
7107 {
7108 case 0: fmadds (cpu); return;
7109 case 1: fmsubs (cpu); return;
7110 case 2: fnmadds (cpu); return;
7111 case 3: fnmsubs (cpu); return;
7112 case 4: fmaddd (cpu); return;
7113 case 5: fmsubd (cpu); return;
7114 case 6: fnmaddd (cpu); return;
7115 case 7: fnmsubd (cpu); return;
7116 default:
7117 /* type > 1 is currently unallocated. */
7118 HALT_UNALLOC;
7119 }
7120}
7121
7122static void
7123dexSimpleFPFixedConvert (sim_cpu *cpu)
7124{
7125 HALT_NYI;
7126}
7127
7128static void
7129dexSimpleFPCondCompare (sim_cpu *cpu)
7130{
5ab6d79e
NC
7131 /* instr [31,23] = 0001 1110 0
7132 instr [22] = type
7133 instr [21] = 1
7134 instr [20,16] = Rm
7135 instr [15,12] = condition
7136 instr [11,10] = 01
7137 instr [9,5] = Rn
7138 instr [4] = 0
7139 instr [3,0] = nzcv */
7140
7141 unsigned rm = INSTR (20, 16);
7142 unsigned rn = INSTR (9, 5);
7143
7144 NYI_assert (31, 23, 0x3C);
7145 NYI_assert (11, 10, 0x1);
7146 NYI_assert (4, 4, 0);
7147
2cdad34c 7148 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7149 if (! testConditionCode (cpu, INSTR (15, 12)))
7150 {
7151 aarch64_set_CPSR (cpu, INSTR (3, 0));
7152 return;
7153 }
7154
7155 if (INSTR (22, 22))
7156 {
7157 /* Double precision. */
7158 double val1 = aarch64_get_vec_double (cpu, rn, 0);
7159 double val2 = aarch64_get_vec_double (cpu, rm, 0);
7160
7161 /* FIXME: Check for NaNs. */
7162 if (val1 == val2)
7163 aarch64_set_CPSR (cpu, (Z | C));
7164 else if (val1 < val2)
7165 aarch64_set_CPSR (cpu, N);
7166 else /* val1 > val2 */
7167 aarch64_set_CPSR (cpu, C);
7168 }
7169 else
7170 {
7171 /* Single precision. */
7172 float val1 = aarch64_get_vec_float (cpu, rn, 0);
7173 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 7174
5ab6d79e
NC
7175 /* FIXME: Check for NaNs. */
7176 if (val1 == val2)
7177 aarch64_set_CPSR (cpu, (Z | C));
7178 else if (val1 < val2)
7179 aarch64_set_CPSR (cpu, N);
7180 else /* val1 > val2 */
7181 aarch64_set_CPSR (cpu, C);
7182 }
2e8cf49e
NC
7183}
7184
7185/* 2 sources. */
7186
7187/* Float add. */
7188static void
7189fadds (sim_cpu *cpu)
7190{
ef0d8ffc
NC
7191 unsigned sm = INSTR (20, 16);
7192 unsigned sn = INSTR ( 9, 5);
7193 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7194
2cdad34c 7195 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7196 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7197 + aarch64_get_FP_float (cpu, sm));
7198}
7199
7200/* Double add. */
7201static void
7202faddd (sim_cpu *cpu)
7203{
ef0d8ffc
NC
7204 unsigned sm = INSTR (20, 16);
7205 unsigned sn = INSTR ( 9, 5);
7206 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7207
2cdad34c 7208 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7209 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7210 + aarch64_get_FP_double (cpu, sm));
7211}
7212
7213/* Float divide. */
7214static void
7215fdivs (sim_cpu *cpu)
7216{
ef0d8ffc
NC
7217 unsigned sm = INSTR (20, 16);
7218 unsigned sn = INSTR ( 9, 5);
7219 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7220
2cdad34c 7221 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7222 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7223 / aarch64_get_FP_float (cpu, sm));
7224}
7225
7226/* Double divide. */
7227static void
7228fdivd (sim_cpu *cpu)
7229{
ef0d8ffc
NC
7230 unsigned sm = INSTR (20, 16);
7231 unsigned sn = INSTR ( 9, 5);
7232 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7233
2cdad34c 7234 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7235 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7236 / aarch64_get_FP_double (cpu, sm));
7237}
7238
7239/* Float multiply. */
7240static void
7241fmuls (sim_cpu *cpu)
7242{
ef0d8ffc
NC
7243 unsigned sm = INSTR (20, 16);
7244 unsigned sn = INSTR ( 9, 5);
7245 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7246
2cdad34c 7247 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7248 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7249 * aarch64_get_FP_float (cpu, sm));
7250}
7251
7252/* Double multiply. */
7253static void
7254fmuld (sim_cpu *cpu)
7255{
ef0d8ffc
NC
7256 unsigned sm = INSTR (20, 16);
7257 unsigned sn = INSTR ( 9, 5);
7258 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7259
2cdad34c 7260 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7261 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7262 * aarch64_get_FP_double (cpu, sm));
7263}
7264
7265/* Float negate and multiply. */
7266static void
7267fnmuls (sim_cpu *cpu)
7268{
ef0d8ffc
NC
7269 unsigned sm = INSTR (20, 16);
7270 unsigned sn = INSTR ( 9, 5);
7271 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7272
2cdad34c 7273 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7274 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7275 * aarch64_get_FP_float (cpu, sm)));
7276}
7277
7278/* Double negate and multiply. */
7279static void
7280fnmuld (sim_cpu *cpu)
7281{
ef0d8ffc
NC
7282 unsigned sm = INSTR (20, 16);
7283 unsigned sn = INSTR ( 9, 5);
7284 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7285
2cdad34c 7286 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7287 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7288 * aarch64_get_FP_double (cpu, sm)));
7289}
7290
7291/* Float subtract. */
7292static void
7293fsubs (sim_cpu *cpu)
7294{
ef0d8ffc
NC
7295 unsigned sm = INSTR (20, 16);
7296 unsigned sn = INSTR ( 9, 5);
7297 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7298
2cdad34c 7299 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7300 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7301 - aarch64_get_FP_float (cpu, sm));
7302}
7303
7304/* Double subtract. */
7305static void
7306fsubd (sim_cpu *cpu)
7307{
ef0d8ffc
NC
7308 unsigned sm = INSTR (20, 16);
7309 unsigned sn = INSTR ( 9, 5);
7310 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7311
2cdad34c 7312 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7313 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7314 - aarch64_get_FP_double (cpu, sm));
7315}
7316
7317static void
7318do_FMINNM (sim_cpu *cpu)
7319{
7320 /* instr[31,23] = 0 0011 1100
7321 instr[22] = float(0)/double(1)
7322 instr[21] = 1
7323 instr[20,16] = Sm
7324 instr[15,10] = 01 1110
7325 instr[9,5] = Sn
7326 instr[4,0] = Cpu */
7327
ef0d8ffc
NC
7328 unsigned sm = INSTR (20, 16);
7329 unsigned sn = INSTR ( 9, 5);
7330 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7331
7332 NYI_assert (31, 23, 0x03C);
7333 NYI_assert (15, 10, 0x1E);
7334
2cdad34c 7335 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7336 if (INSTR (22, 22))
2e8cf49e
NC
7337 aarch64_set_FP_double (cpu, sd,
7338 dminnm (aarch64_get_FP_double (cpu, sn),
7339 aarch64_get_FP_double (cpu, sm)));
7340 else
7341 aarch64_set_FP_float (cpu, sd,
7342 fminnm (aarch64_get_FP_float (cpu, sn),
7343 aarch64_get_FP_float (cpu, sm)));
7344}
7345
7346static void
7347do_FMAXNM (sim_cpu *cpu)
7348{
7349 /* instr[31,23] = 0 0011 1100
7350 instr[22] = float(0)/double(1)
7351 instr[21] = 1
7352 instr[20,16] = Sm
7353 instr[15,10] = 01 1010
7354 instr[9,5] = Sn
7355 instr[4,0] = Cpu */
7356
ef0d8ffc
NC
7357 unsigned sm = INSTR (20, 16);
7358 unsigned sn = INSTR ( 9, 5);
7359 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7360
7361 NYI_assert (31, 23, 0x03C);
7362 NYI_assert (15, 10, 0x1A);
7363
2cdad34c 7364 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7365 if (INSTR (22, 22))
2e8cf49e
NC
7366 aarch64_set_FP_double (cpu, sd,
7367 dmaxnm (aarch64_get_FP_double (cpu, sn),
7368 aarch64_get_FP_double (cpu, sm)));
7369 else
7370 aarch64_set_FP_float (cpu, sd,
7371 fmaxnm (aarch64_get_FP_float (cpu, sn),
7372 aarch64_get_FP_float (cpu, sm)));
7373}
7374
7375static void
7376dexSimpleFPDataProc2Source (sim_cpu *cpu)
7377{
7378 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7379 instr[30] = 0
7380 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7381 instr[28,25] = 1111
7382 instr[24] = 0
7383 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7384 instr[21] = 1
7385 instr[20,16] = Vm
7386 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7387 0010 ==> FADD, 0011 ==> FSUB,
7388 0100 ==> FMAX, 0101 ==> FMIN
7389 0110 ==> FMAXNM, 0111 ==> FMINNM
7390 1000 ==> FNMUL, ow ==> UNALLOC
7391 instr[11,10] = 10
7392 instr[9,5] = Vn
7393 instr[4,0] = Vd */
7394
7517e550 7395 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7396 uint32_t type = INSTR (23, 22);
2e8cf49e 7397 /* Dispatch on opcode. */
ef0d8ffc 7398 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7399
7400 if (type > 1)
7401 HALT_UNALLOC;
7402
7403 if (M_S != 0)
7404 HALT_UNALLOC;
7405
7406 if (type)
7407 switch (dispatch)
7408 {
7409 case 0: fmuld (cpu); return;
7410 case 1: fdivd (cpu); return;
7411 case 2: faddd (cpu); return;
7412 case 3: fsubd (cpu); return;
7413 case 6: do_FMAXNM (cpu); return;
7414 case 7: do_FMINNM (cpu); return;
7415 case 8: fnmuld (cpu); return;
7416
7417 /* Have not yet implemented fmax and fmin. */
7418 case 4:
7419 case 5:
7420 HALT_NYI;
7421
7422 default:
7423 HALT_UNALLOC;
7424 }
7425 else /* type == 0 => floats. */
7426 switch (dispatch)
7427 {
7428 case 0: fmuls (cpu); return;
7429 case 1: fdivs (cpu); return;
7430 case 2: fadds (cpu); return;
7431 case 3: fsubs (cpu); return;
7432 case 6: do_FMAXNM (cpu); return;
7433 case 7: do_FMINNM (cpu); return;
7434 case 8: fnmuls (cpu); return;
7435
7436 case 4:
7437 case 5:
7438 HALT_NYI;
7439
7440 default:
7441 HALT_UNALLOC;
7442 }
7443}
7444
7445static void
7446dexSimpleFPCondSelect (sim_cpu *cpu)
7447{
7448 /* FCSEL
7449 instr[31,23] = 0 0011 1100
7450 instr[22] = 0=>single 1=>double
7451 instr[21] = 1
7452 instr[20,16] = Sm
7453 instr[15,12] = cond
7454 instr[11,10] = 11
7455 instr[9,5] = Sn
7456 instr[4,0] = Cpu */
ef0d8ffc
NC
7457 unsigned sm = INSTR (20, 16);
7458 unsigned sn = INSTR ( 9, 5);
7459 unsigned sd = INSTR ( 4, 0);
7460 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7461
7462 NYI_assert (31, 23, 0x03C);
7463 NYI_assert (11, 10, 0x3);
7464
2cdad34c 7465 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7466 if (INSTR (22, 22))
c0386d4d
JW
7467 aarch64_set_FP_double (cpu, sd, (set ? aarch64_get_FP_double (cpu, sn)
7468 : aarch64_get_FP_double (cpu, sm)));
2e8cf49e 7469 else
c0386d4d
JW
7470 aarch64_set_FP_float (cpu, sd, (set ? aarch64_get_FP_float (cpu, sn)
7471 : aarch64_get_FP_float (cpu, sm)));
2e8cf49e
NC
7472}
7473
7474/* Store 32 bit unscaled signed 9 bit. */
7475static void
7476fsturs (sim_cpu *cpu, int32_t offset)
7477{
ef0d8ffc
NC
7478 unsigned int rn = INSTR (9, 5);
7479 unsigned int st = INSTR (4, 0);
2e8cf49e 7480
2cdad34c 7481 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7482 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7483 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
7484}
7485
7486/* Store 64 bit unscaled signed 9 bit. */
7487static void
7488fsturd (sim_cpu *cpu, int32_t offset)
7489{
ef0d8ffc
NC
7490 unsigned int rn = INSTR (9, 5);
7491 unsigned int st = INSTR (4, 0);
2e8cf49e 7492
2cdad34c 7493 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7494 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7495 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
7496}
7497
7498/* Store 128 bit unscaled signed 9 bit. */
7499static void
7500fsturq (sim_cpu *cpu, int32_t offset)
7501{
ef0d8ffc
NC
7502 unsigned int rn = INSTR (9, 5);
7503 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7504 FRegister a;
7505
2cdad34c 7506 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1 7507 aarch64_get_FP_long_double (cpu, st, & a);
2e8cf49e 7508 aarch64_set_mem_long_double (cpu,
88ddd4a1 7509 aarch64_get_reg_u64 (cpu, rn, 1)
2e8cf49e
NC
7510 + offset, a);
7511}
7512
7513/* TODO FP move register. */
7514
7515/* 32 bit fp to fp move register. */
7516static void
7517ffmovs (sim_cpu *cpu)
7518{
ef0d8ffc
NC
7519 unsigned int rn = INSTR (9, 5);
7520 unsigned int st = INSTR (4, 0);
2e8cf49e 7521
2cdad34c 7522 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7523 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7524}
7525
7526/* 64 bit fp to fp move register. */
7527static void
7528ffmovd (sim_cpu *cpu)
7529{
ef0d8ffc
NC
7530 unsigned int rn = INSTR (9, 5);
7531 unsigned int st = INSTR (4, 0);
2e8cf49e 7532
2cdad34c 7533 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7534 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7535}
7536
7537/* 32 bit GReg to Vec move register. */
7538static void
7539fgmovs (sim_cpu *cpu)
7540{
ef0d8ffc
NC
7541 unsigned int rn = INSTR (9, 5);
7542 unsigned int st = INSTR (4, 0);
2e8cf49e 7543
2cdad34c 7544 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7545 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7546}
7547
7548/* 64 bit g to fp move register. */
7549static void
7550fgmovd (sim_cpu *cpu)
7551{
ef0d8ffc
NC
7552 unsigned int rn = INSTR (9, 5);
7553 unsigned int st = INSTR (4, 0);
2e8cf49e 7554
2cdad34c 7555 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7556 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7557}
7558
7559/* 32 bit fp to g move register. */
7560static void
7561gfmovs (sim_cpu *cpu)
7562{
ef0d8ffc
NC
7563 unsigned int rn = INSTR (9, 5);
7564 unsigned int st = INSTR (4, 0);
2e8cf49e 7565
2cdad34c 7566 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7567 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7568}
7569
7570/* 64 bit fp to g move register. */
7571static void
7572gfmovd (sim_cpu *cpu)
7573{
ef0d8ffc
NC
7574 unsigned int rn = INSTR (9, 5);
7575 unsigned int st = INSTR (4, 0);
2e8cf49e 7576
2cdad34c 7577 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7578 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7579}
7580
7581/* FP move immediate
7582
7583 These install an immediate 8 bit value in the target register
7584 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7585 bit exponent. */
7586
7587static void
7588fmovs (sim_cpu *cpu)
7589{
ef0d8ffc
NC
7590 unsigned int sd = INSTR (4, 0);
7591 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7592 float f = fp_immediate_for_encoding_32 (imm);
7593
2cdad34c 7594 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7595 aarch64_set_FP_float (cpu, sd, f);
7596}
7597
7598static void
7599fmovd (sim_cpu *cpu)
7600{
ef0d8ffc
NC
7601 unsigned int sd = INSTR (4, 0);
7602 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7603 double d = fp_immediate_for_encoding_64 (imm);
7604
2cdad34c 7605 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7606 aarch64_set_FP_double (cpu, sd, d);
7607}
7608
7609static void
7610dexSimpleFPImmediate (sim_cpu *cpu)
7611{
7612 /* instr[31,23] == 00111100
7613 instr[22] == type : single(0)/double(1)
7614 instr[21] == 1
7615 instr[20,13] == imm8
7616 instr[12,10] == 100
7617 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7618 instr[4,0] == Rd */
ef0d8ffc 7619 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7620
7621 NYI_assert (31, 23, 0x3C);
7622
7623 if (imm5 != 0)
7624 HALT_UNALLOC;
7625
ef0d8ffc 7626 if (INSTR (22, 22))
2e8cf49e
NC
7627 fmovd (cpu);
7628 else
7629 fmovs (cpu);
7630}
7631
7632/* TODO specific decode and execute for group Load Store. */
7633
7634/* TODO FP load/store single register (unscaled offset). */
7635
7636/* TODO load 8 bit unscaled signed 9 bit. */
7637/* TODO load 16 bit unscaled signed 9 bit. */
7638
7639/* Load 32 bit unscaled signed 9 bit. */
7640static void
7641fldurs (sim_cpu *cpu, int32_t offset)
7642{
ef0d8ffc
NC
7643 unsigned int rn = INSTR (9, 5);
7644 unsigned int st = INSTR (4, 0);
2e8cf49e 7645
2cdad34c 7646 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7647 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7648 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7649}
7650
7651/* Load 64 bit unscaled signed 9 bit. */
7652static void
7653fldurd (sim_cpu *cpu, int32_t offset)
7654{
ef0d8ffc
NC
7655 unsigned int rn = INSTR (9, 5);
7656 unsigned int st = INSTR (4, 0);
2e8cf49e 7657
2cdad34c 7658 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7659 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7660 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7661}
7662
7663/* Load 128 bit unscaled signed 9 bit. */
7664static void
7665fldurq (sim_cpu *cpu, int32_t offset)
7666{
ef0d8ffc
NC
7667 unsigned int rn = INSTR (9, 5);
7668 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7669 FRegister a;
7670 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7671
2cdad34c 7672 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7673 aarch64_get_mem_long_double (cpu, addr, & a);
7674 aarch64_set_FP_long_double (cpu, st, a);
7675}
7676
7677/* TODO store 8 bit unscaled signed 9 bit. */
7678/* TODO store 16 bit unscaled signed 9 bit. */
7679
7680
7681/* 1 source. */
7682
7683/* Float absolute value. */
7684static void
7685fabss (sim_cpu *cpu)
7686{
ef0d8ffc
NC
7687 unsigned sn = INSTR (9, 5);
7688 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7689 float value = aarch64_get_FP_float (cpu, sn);
7690
2cdad34c 7691 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7692 aarch64_set_FP_float (cpu, sd, fabsf (value));
7693}
7694
7695/* Double absolute value. */
7696static void
7697fabcpu (sim_cpu *cpu)
7698{
ef0d8ffc
NC
7699 unsigned sn = INSTR (9, 5);
7700 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7701 double value = aarch64_get_FP_double (cpu, sn);
7702
2cdad34c 7703 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7704 aarch64_set_FP_double (cpu, sd, fabs (value));
7705}
7706
7707/* Float negative value. */
7708static void
7709fnegs (sim_cpu *cpu)
7710{
ef0d8ffc
NC
7711 unsigned sn = INSTR (9, 5);
7712 unsigned sd = INSTR (4, 0);
2e8cf49e 7713
2cdad34c 7714 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7715 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7716}
7717
7718/* Double negative value. */
7719static void
7720fnegd (sim_cpu *cpu)
7721{
ef0d8ffc
NC
7722 unsigned sn = INSTR (9, 5);
7723 unsigned sd = INSTR (4, 0);
2e8cf49e 7724
2cdad34c 7725 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7726 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7727}
7728
7729/* Float square root. */
7730static void
7731fsqrts (sim_cpu *cpu)
7732{
ef0d8ffc
NC
7733 unsigned sn = INSTR (9, 5);
7734 unsigned sd = INSTR (4, 0);
2e8cf49e 7735
2cdad34c 7736 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
0f118bc7 7737 aarch64_set_FP_float (cpu, sd, sqrtf (aarch64_get_FP_float (cpu, sn)));
2e8cf49e
NC
7738}
7739
7740/* Double square root. */
7741static void
7742fsqrtd (sim_cpu *cpu)
7743{
ef0d8ffc
NC
7744 unsigned sn = INSTR (9, 5);
7745 unsigned sd = INSTR (4, 0);
2e8cf49e 7746
2cdad34c 7747 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7748 aarch64_set_FP_double (cpu, sd,
7749 sqrt (aarch64_get_FP_double (cpu, sn)));
7750}
7751
7752/* Convert double to float. */
7753static void
7754fcvtds (sim_cpu *cpu)
7755{
ef0d8ffc
NC
7756 unsigned sn = INSTR (9, 5);
7757 unsigned sd = INSTR (4, 0);
2e8cf49e 7758
2cdad34c 7759 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7760 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7761}
7762
7763/* Convert float to double. */
7764static void
7765fcvtcpu (sim_cpu *cpu)
7766{
ef0d8ffc
NC
7767 unsigned sn = INSTR (9, 5);
7768 unsigned sd = INSTR (4, 0);
2e8cf49e 7769
2cdad34c 7770 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7771 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7772}
7773
7774static void
7775do_FRINT (sim_cpu *cpu)
7776{
7777 /* instr[31,23] = 0001 1110 0
7778 instr[22] = single(0)/double(1)
7779 instr[21,18] = 1001
7780 instr[17,15] = rounding mode
7781 instr[14,10] = 10000
7782 instr[9,5] = source
7783 instr[4,0] = dest */
7784
7785 float val;
ef0d8ffc
NC
7786 unsigned rs = INSTR (9, 5);
7787 unsigned rd = INSTR (4, 0);
7788 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7789
7790 NYI_assert (31, 23, 0x03C);
7791 NYI_assert (21, 18, 0x9);
7792 NYI_assert (14, 10, 0x10);
7793
7794 if (rmode == 6 || rmode == 7)
7795 /* FIXME: Add support for rmode == 6 exactness check. */
7796 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7797
2cdad34c 7798 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7799 if (INSTR (22, 22))
2e8cf49e
NC
7800 {
7801 double val = aarch64_get_FP_double (cpu, rs);
7802
7803 switch (rmode)
7804 {
7805 case 0: /* mode N: nearest or even. */
7806 {
7807 double rval = round (val);
7808
7809 if (val - rval == 0.5)
7810 {
7811 if (((rval / 2.0) * 2.0) != rval)
7812 rval += 1.0;
7813 }
7814
7815 aarch64_set_FP_double (cpu, rd, round (val));
7816 return;
7817 }
7818
7819 case 1: /* mode P: towards +inf. */
7820 if (val < 0.0)
7821 aarch64_set_FP_double (cpu, rd, trunc (val));
7822 else
7823 aarch64_set_FP_double (cpu, rd, round (val));
7824 return;
7825
7826 case 2: /* mode M: towards -inf. */
7827 if (val < 0.0)
7828 aarch64_set_FP_double (cpu, rd, round (val));
7829 else
7830 aarch64_set_FP_double (cpu, rd, trunc (val));
7831 return;
7832
7833 case 3: /* mode Z: towards 0. */
7834 aarch64_set_FP_double (cpu, rd, trunc (val));
7835 return;
7836
7837 case 4: /* mode A: away from 0. */
7838 aarch64_set_FP_double (cpu, rd, round (val));
7839 return;
7840
7841 case 6: /* mode X: use FPCR with exactness check. */
7842 case 7: /* mode I: use FPCR mode. */
7843 HALT_NYI;
7844
7845 default:
7846 HALT_UNALLOC;
7847 }
7848 }
7849
7850 val = aarch64_get_FP_float (cpu, rs);
7851
7852 switch (rmode)
7853 {
7854 case 0: /* mode N: nearest or even. */
7855 {
7856 float rval = roundf (val);
7857
7858 if (val - rval == 0.5)
7859 {
7860 if (((rval / 2.0) * 2.0) != rval)
7861 rval += 1.0;
7862 }
7863
7864 aarch64_set_FP_float (cpu, rd, rval);
7865 return;
7866 }
7867
7868 case 1: /* mode P: towards +inf. */
7869 if (val < 0.0)
7870 aarch64_set_FP_float (cpu, rd, truncf (val));
7871 else
7872 aarch64_set_FP_float (cpu, rd, roundf (val));
7873 return;
7874
7875 case 2: /* mode M: towards -inf. */
7876 if (val < 0.0)
7877 aarch64_set_FP_float (cpu, rd, truncf (val));
7878 else
7879 aarch64_set_FP_float (cpu, rd, roundf (val));
7880 return;
7881
7882 case 3: /* mode Z: towards 0. */
7883 aarch64_set_FP_float (cpu, rd, truncf (val));
7884 return;
7885
7886 case 4: /* mode A: away from 0. */
7887 aarch64_set_FP_float (cpu, rd, roundf (val));
7888 return;
7889
7890 case 6: /* mode X: use FPCR with exactness check. */
7891 case 7: /* mode I: use FPCR mode. */
7892 HALT_NYI;
7893
7894 default:
7895 HALT_UNALLOC;
7896 }
7897}
7898
5ab6d79e
NC
7899/* Convert half to float. */
7900static void
ef0d8ffc 7901do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
7902{
7903 unsigned rn = INSTR (9, 5);
7904 unsigned rd = INSTR (4, 0);
7905
7906 NYI_assert (31, 10, 0x7B890);
7907
2cdad34c 7908 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7909 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
7910}
7911
7517e550 7912/* Convert half to double. */
5ab6d79e 7913static void
ef0d8ffc 7914do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
7915{
7916 unsigned rn = INSTR (9, 5);
7917 unsigned rd = INSTR (4, 0);
7918
7919 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 7920
2cdad34c 7921 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7922 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
7923}
7924
7925static void
ef0d8ffc 7926do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
7927{
7928 unsigned rn = INSTR (9, 5);
7929 unsigned rd = INSTR (4, 0);
7930
7931 NYI_assert (31, 10, 0x788F0);
7932
2cdad34c 7933 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7934 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
7935}
7936
7517e550 7937/* Convert double to half. */
5ab6d79e 7938static void
ef0d8ffc 7939do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
7940{
7941 unsigned rn = INSTR (9, 5);
7942 unsigned rd = INSTR (4, 0);
7943
7944 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 7945
2cdad34c 7946 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7947 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
7948}
7949
2e8cf49e
NC
7950static void
7951dexSimpleFPDataProc1Source (sim_cpu *cpu)
7952{
7953 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7954 instr[30] = 0
7955 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7956 instr[28,25] = 1111
7957 instr[24] = 0
7958 instr[23,22] ==> type : 00 ==> source is single,
7959 01 ==> source is double
7960 10 ==> UNALLOC
7961 11 ==> UNALLOC or source is half
7962 instr[21] = 1
7963 instr[20,15] ==> opcode : with type 00 or 01
7964 000000 ==> FMOV, 000001 ==> FABS,
7965 000010 ==> FNEG, 000011 ==> FSQRT,
7966 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7967 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7968 001000 ==> FRINTN, 001001 ==> FRINTP,
7969 001010 ==> FRINTM, 001011 ==> FRINTZ,
7970 001100 ==> FRINTA, 001101 ==> UNALLOC
7971 001110 ==> FRINTX, 001111 ==> FRINTI
7972 with type 11
7973 000100 ==> FCVT (half-to-single)
7974 000101 ==> FCVT (half-to-double)
7975 instr[14,10] = 10000. */
7976
7517e550 7977 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
7978 uint32_t type = INSTR (23, 22);
7979 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
7980
7981 if (M_S != 0)
7982 HALT_UNALLOC;
7983
7984 if (type == 3)
7985 {
5ab6d79e
NC
7986 if (opcode == 4)
7987 do_FCVT_half_to_single (cpu);
7988 else if (opcode == 5)
7989 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
7990 else
7991 HALT_UNALLOC;
5ab6d79e 7992 return;
2e8cf49e
NC
7993 }
7994
7995 if (type == 2)
7996 HALT_UNALLOC;
7997
7998 switch (opcode)
7999 {
8000 case 0:
8001 if (type)
8002 ffmovd (cpu);
8003 else
8004 ffmovs (cpu);
8005 return;
8006
8007 case 1:
8008 if (type)
8009 fabcpu (cpu);
8010 else
8011 fabss (cpu);
8012 return;
8013
8014 case 2:
8015 if (type)
8016 fnegd (cpu);
8017 else
8018 fnegs (cpu);
8019 return;
8020
8021 case 3:
8022 if (type)
8023 fsqrtd (cpu);
8024 else
8025 fsqrts (cpu);
8026 return;
8027
8028 case 4:
8029 if (type)
8030 fcvtds (cpu);
8031 else
8032 HALT_UNALLOC;
8033 return;
8034
8035 case 5:
8036 if (type)
8037 HALT_UNALLOC;
8038 fcvtcpu (cpu);
8039 return;
8040
8041 case 8: /* FRINTN etc. */
8042 case 9:
8043 case 10:
8044 case 11:
8045 case 12:
8046 case 14:
8047 case 15:
8048 do_FRINT (cpu);
8049 return;
8050
5ab6d79e
NC
8051 case 7:
8052 if (INSTR (22, 22))
8053 do_FCVT_double_to_half (cpu);
8054 else
8055 do_FCVT_single_to_half (cpu);
8056 return;
8057
2e8cf49e
NC
8058 case 13:
8059 HALT_NYI;
8060
8061 default:
8062 HALT_UNALLOC;
8063 }
8064}
8065
8066/* 32 bit signed int to float. */
8067static void
8068scvtf32 (sim_cpu *cpu)
8069{
ef0d8ffc
NC
8070 unsigned rn = INSTR (9, 5);
8071 unsigned sd = INSTR (4, 0);
2e8cf49e 8072
2cdad34c 8073 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8074 aarch64_set_FP_float
8075 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8076}
8077
8078/* signed int to float. */
8079static void
8080scvtf (sim_cpu *cpu)
8081{
ef0d8ffc
NC
8082 unsigned rn = INSTR (9, 5);
8083 unsigned sd = INSTR (4, 0);
2e8cf49e 8084
2cdad34c 8085 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8086 aarch64_set_FP_float
8087 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8088}
8089
8090/* 32 bit signed int to double. */
8091static void
8092scvtd32 (sim_cpu *cpu)
8093{
ef0d8ffc
NC
8094 unsigned rn = INSTR (9, 5);
8095 unsigned sd = INSTR (4, 0);
2e8cf49e 8096
2cdad34c 8097 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8098 aarch64_set_FP_double
8099 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8100}
8101
8102/* signed int to double. */
8103static void
8104scvtd (sim_cpu *cpu)
8105{
ef0d8ffc
NC
8106 unsigned rn = INSTR (9, 5);
8107 unsigned sd = INSTR (4, 0);
2e8cf49e 8108
2cdad34c 8109 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8110 aarch64_set_FP_double
8111 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8112}
8113
8114static const float FLOAT_INT_MAX = (float) INT_MAX;
8115static const float FLOAT_INT_MIN = (float) INT_MIN;
8116static const double DOUBLE_INT_MAX = (double) INT_MAX;
8117static const double DOUBLE_INT_MIN = (double) INT_MIN;
8118static const float FLOAT_LONG_MAX = (float) LONG_MAX;
8119static const float FLOAT_LONG_MIN = (float) LONG_MIN;
8120static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
8121static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
8122
c0386d4d
JW
8123#define UINT_MIN 0
8124#define ULONG_MIN 0
8125static const float FLOAT_UINT_MAX = (float) UINT_MAX;
8126static const float FLOAT_UINT_MIN = (float) UINT_MIN;
8127static const double DOUBLE_UINT_MAX = (double) UINT_MAX;
8128static const double DOUBLE_UINT_MIN = (double) UINT_MIN;
8129static const float FLOAT_ULONG_MAX = (float) ULONG_MAX;
8130static const float FLOAT_ULONG_MIN = (float) ULONG_MIN;
8131static const double DOUBLE_ULONG_MAX = (double) ULONG_MAX;
8132static const double DOUBLE_ULONG_MIN = (double) ULONG_MIN;
8133
2e8cf49e
NC
8134/* Check for FP exception conditions:
8135 NaN raises IO
8136 Infinity raises IO
8137 Out of Range raises IO and IX and saturates value
8138 Denormal raises ID and IX and sets to zero. */
8139#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
8140 do \
8141 { \
8142 switch (fpclassify (F)) \
8143 { \
8144 case FP_INFINITE: \
8145 case FP_NAN: \
8146 aarch64_set_FPSR (cpu, IO); \
8147 if (signbit (F)) \
8148 VALUE = ITYPE##_MAX; \
8149 else \
8150 VALUE = ITYPE##_MIN; \
8151 break; \
8152 \
8153 case FP_NORMAL: \
8154 if (F >= FTYPE##_##ITYPE##_MAX) \
8155 { \
8156 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8157 VALUE = ITYPE##_MAX; \
8158 } \
8159 else if (F <= FTYPE##_##ITYPE##_MIN) \
8160 { \
8161 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8162 VALUE = ITYPE##_MIN; \
8163 } \
8164 break; \
8165 \
8166 case FP_SUBNORMAL: \
8167 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
8168 VALUE = 0; \
8169 break; \
8170 \
8171 default: \
8172 case FP_ZERO: \
8173 VALUE = 0; \
8174 break; \
8175 } \
8176 } \
8177 while (0)
8178
8179/* 32 bit convert float to signed int truncate towards zero. */
8180static void
8181fcvtszs32 (sim_cpu *cpu)
8182{
ef0d8ffc
NC
8183 unsigned sn = INSTR (9, 5);
8184 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8185 /* TODO : check that this rounds toward zero. */
8186 float f = aarch64_get_FP_float (cpu, sn);
8187 int32_t value = (int32_t) f;
8188
8189 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8190
2cdad34c 8191 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8192 /* Avoid sign extension to 64 bit. */
8193 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8194}
8195
8196/* 64 bit convert float to signed int truncate towards zero. */
8197static void
8198fcvtszs (sim_cpu *cpu)
8199{
ef0d8ffc
NC
8200 unsigned sn = INSTR (9, 5);
8201 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8202 float f = aarch64_get_FP_float (cpu, sn);
8203 int64_t value = (int64_t) f;
8204
8205 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8206
2cdad34c 8207 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8208 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8209}
8210
8211/* 32 bit convert double to signed int truncate towards zero. */
8212static void
8213fcvtszd32 (sim_cpu *cpu)
8214{
ef0d8ffc
NC
8215 unsigned sn = INSTR (9, 5);
8216 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8217 /* TODO : check that this rounds toward zero. */
8218 double d = aarch64_get_FP_double (cpu, sn);
8219 int32_t value = (int32_t) d;
8220
8221 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8222
2cdad34c 8223 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8224 /* Avoid sign extension to 64 bit. */
8225 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8226}
8227
8228/* 64 bit convert double to signed int truncate towards zero. */
8229static void
8230fcvtszd (sim_cpu *cpu)
8231{
ef0d8ffc
NC
8232 unsigned sn = INSTR (9, 5);
8233 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8234 /* TODO : check that this rounds toward zero. */
8235 double d = aarch64_get_FP_double (cpu, sn);
8236 int64_t value;
8237
8238 value = (int64_t) d;
8239
8240 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8241
2cdad34c 8242 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8243 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8244}
8245
8246static void
8247do_fcvtzu (sim_cpu *cpu)
8248{
8249 /* instr[31] = size: 32-bit (0), 64-bit (1)
8250 instr[30,23] = 00111100
8251 instr[22] = type: single (0)/ double (1)
8252 instr[21] = enable (0)/disable(1) precision
8253 instr[20,16] = 11001
8254 instr[15,10] = precision
8255 instr[9,5] = Rs
8256 instr[4,0] = Rd. */
8257
ef0d8ffc
NC
8258 unsigned rs = INSTR (9, 5);
8259 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8260
8261 NYI_assert (30, 23, 0x3C);
8262 NYI_assert (20, 16, 0x19);
8263
ef0d8ffc 8264 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8265 /* Convert to fixed point. */
8266 HALT_NYI;
8267
2cdad34c 8268 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8269 if (INSTR (31, 31))
2e8cf49e
NC
8270 {
8271 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 8272 if (INSTR (22, 22))
2e8cf49e
NC
8273 {
8274 double d = aarch64_get_FP_double (cpu, rs);
8275 uint64_t value = (uint64_t) d;
8276
8277 /* Do not raise an exception if we have reached ULONG_MAX. */
8278 if (value != (1UL << 63))
c0386d4d 8279 RAISE_EXCEPTIONS (d, value, DOUBLE, ULONG);
2e8cf49e
NC
8280
8281 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8282 }
8283 else
8284 {
8285 float f = aarch64_get_FP_float (cpu, rs);
8286 uint64_t value = (uint64_t) f;
8287
8288 /* Do not raise an exception if we have reached ULONG_MAX. */
8289 if (value != (1UL << 63))
c0386d4d 8290 RAISE_EXCEPTIONS (f, value, FLOAT, ULONG);
2e8cf49e
NC
8291
8292 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8293 }
8294 }
8295 else
8296 {
8297 uint32_t value;
8298
8299 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8300 if (INSTR (22, 22))
2e8cf49e
NC
8301 {
8302 double d = aarch64_get_FP_double (cpu, rs);
8303
8304 value = (uint32_t) d;
8305 /* Do not raise an exception if we have reached UINT_MAX. */
8306 if (value != (1UL << 31))
c0386d4d 8307 RAISE_EXCEPTIONS (d, value, DOUBLE, UINT);
2e8cf49e
NC
8308 }
8309 else
8310 {
8311 float f = aarch64_get_FP_float (cpu, rs);
8312
8313 value = (uint32_t) f;
8314 /* Do not raise an exception if we have reached UINT_MAX. */
8315 if (value != (1UL << 31))
c0386d4d 8316 RAISE_EXCEPTIONS (f, value, FLOAT, UINT);
2e8cf49e
NC
8317 }
8318
8319 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8320 }
8321}
8322
8323static void
8324do_UCVTF (sim_cpu *cpu)
8325{
8326 /* instr[31] = size: 32-bit (0), 64-bit (1)
8327 instr[30,23] = 001 1110 0
8328 instr[22] = type: single (0)/ double (1)
8329 instr[21] = enable (0)/disable(1) precision
8330 instr[20,16] = 0 0011
8331 instr[15,10] = precision
8332 instr[9,5] = Rs
8333 instr[4,0] = Rd. */
8334
ef0d8ffc
NC
8335 unsigned rs = INSTR (9, 5);
8336 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8337
8338 NYI_assert (30, 23, 0x3C);
8339 NYI_assert (20, 16, 0x03);
8340
ef0d8ffc 8341 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8342 HALT_NYI;
8343
8344 /* FIXME: Add exception raising. */
2cdad34c 8345 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8346 if (INSTR (31, 31))
2e8cf49e
NC
8347 {
8348 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8349
ef0d8ffc 8350 if (INSTR (22, 22))
2e8cf49e
NC
8351 aarch64_set_FP_double (cpu, rd, (double) value);
8352 else
8353 aarch64_set_FP_float (cpu, rd, (float) value);
8354 }
8355 else
8356 {
8357 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8358
ef0d8ffc 8359 if (INSTR (22, 22))
2e8cf49e
NC
8360 aarch64_set_FP_double (cpu, rd, (double) value);
8361 else
8362 aarch64_set_FP_float (cpu, rd, (float) value);
8363 }
8364}
8365
8366static void
8367float_vector_move (sim_cpu *cpu)
8368{
8369 /* instr[31,17] == 100 1111 0101 0111
8370 instr[16] ==> direction 0=> to GR, 1=> from GR
8371 instr[15,10] => ???
8372 instr[9,5] ==> source
8373 instr[4,0] ==> dest. */
8374
ef0d8ffc
NC
8375 unsigned rn = INSTR (9, 5);
8376 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8377
8378 NYI_assert (31, 17, 0x4F57);
8379
ef0d8ffc 8380 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8381 HALT_UNALLOC;
8382
2cdad34c 8383 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8384 if (INSTR (16, 16))
2e8cf49e
NC
8385 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8386 else
8387 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8388}
8389
8390static void
8391dexSimpleFPIntegerConvert (sim_cpu *cpu)
8392{
8393 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8394 instr[30 = 0
8395 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8396 instr[28,25] = 1111
8397 instr[24] = 0
8398 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8399 instr[21] = 1
8400 instr[20,19] = rmode
8401 instr[18,16] = opcode
8402 instr[15,10] = 10 0000 */
8403
8404 uint32_t rmode_opcode;
8405 uint32_t size_type;
8406 uint32_t type;
8407 uint32_t size;
8408 uint32_t S;
8409
ef0d8ffc 8410 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8411 {
8412 float_vector_move (cpu);
8413 return;
8414 }
8415
ef0d8ffc
NC
8416 size = INSTR (31, 31);
8417 S = INSTR (29, 29);
2e8cf49e
NC
8418 if (S != 0)
8419 HALT_UNALLOC;
8420
ef0d8ffc 8421 type = INSTR (23, 22);
2e8cf49e
NC
8422 if (type > 1)
8423 HALT_UNALLOC;
8424
ef0d8ffc 8425 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8426 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8427
8428 switch (rmode_opcode)
8429 {
8430 case 2: /* SCVTF. */
8431 switch (size_type)
8432 {
8433 case 0: scvtf32 (cpu); return;
8434 case 1: scvtd32 (cpu); return;
8435 case 2: scvtf (cpu); return;
8436 case 3: scvtd (cpu); return;
2e8cf49e
NC
8437 }
8438
8439 case 6: /* FMOV GR, Vec. */
8440 switch (size_type)
8441 {
8442 case 0: gfmovs (cpu); return;
8443 case 3: gfmovd (cpu); return;
8444 default: HALT_UNALLOC;
8445 }
8446
8447 case 7: /* FMOV vec, GR. */
8448 switch (size_type)
8449 {
8450 case 0: fgmovs (cpu); return;
8451 case 3: fgmovd (cpu); return;
8452 default: HALT_UNALLOC;
8453 }
8454
8455 case 24: /* FCVTZS. */
8456 switch (size_type)
8457 {
8458 case 0: fcvtszs32 (cpu); return;
8459 case 1: fcvtszd32 (cpu); return;
8460 case 2: fcvtszs (cpu); return;
8461 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8462 }
8463
8464 case 25: do_fcvtzu (cpu); return;
8465 case 3: do_UCVTF (cpu); return;
8466
8467 case 0: /* FCVTNS. */
8468 case 1: /* FCVTNU. */
8469 case 4: /* FCVTAS. */
8470 case 5: /* FCVTAU. */
8471 case 8: /* FCVPTS. */
8472 case 9: /* FCVTPU. */
8473 case 16: /* FCVTMS. */
8474 case 17: /* FCVTMU. */
8475 default:
8476 HALT_NYI;
8477 }
8478}
8479
8480static void
8481set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8482{
8483 uint32_t flags;
8484
87903eaf 8485 /* FIXME: Add exception raising. */
2e8cf49e
NC
8486 if (isnan (fvalue1) || isnan (fvalue2))
8487 flags = C|V;
87903eaf
JW
8488 else if (isinf (fvalue1) && isinf (fvalue2))
8489 {
8490 /* Subtracting two infinities may give a NaN. We only need to compare
8491 the signs, which we can get from isinf. */
8492 int result = isinf (fvalue1) - isinf (fvalue2);
8493
8494 if (result == 0)
8495 flags = Z|C;
8496 else if (result < 0)
8497 flags = N;
8498 else /* (result > 0). */
8499 flags = C;
8500 }
2e8cf49e
NC
8501 else
8502 {
8503 float result = fvalue1 - fvalue2;
8504
8505 if (result == 0.0)
8506 flags = Z|C;
8507 else if (result < 0)
8508 flags = N;
8509 else /* (result > 0). */
8510 flags = C;
8511 }
8512
8513 aarch64_set_CPSR (cpu, flags);
8514}
8515
8516static void
8517fcmps (sim_cpu *cpu)
8518{
ef0d8ffc
NC
8519 unsigned sm = INSTR (20, 16);
8520 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8521
8522 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8523 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8524
2cdad34c 8525 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8526 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8527}
8528
8529/* Float compare to zero -- Invalid Operation exception
8530 only on signaling NaNs. */
8531static void
8532fcmpzs (sim_cpu *cpu)
8533{
ef0d8ffc 8534 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8535 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8536
2cdad34c 8537 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8538 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8539}
8540
8541/* Float compare -- Invalid Operation exception on all NaNs. */
8542static void
8543fcmpes (sim_cpu *cpu)
8544{
ef0d8ffc
NC
8545 unsigned sm = INSTR (20, 16);
8546 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8547
8548 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8549 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8550
2cdad34c 8551 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8552 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8553}
8554
8555/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8556static void
8557fcmpzes (sim_cpu *cpu)
8558{
ef0d8ffc 8559 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8560 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8561
2cdad34c 8562 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8563 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8564}
8565
8566static void
8567set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8568{
8569 uint32_t flags;
8570
87903eaf 8571 /* FIXME: Add exception raising. */
2e8cf49e
NC
8572 if (isnan (dval1) || isnan (dval2))
8573 flags = C|V;
87903eaf
JW
8574 else if (isinf (dval1) && isinf (dval2))
8575 {
8576 /* Subtracting two infinities may give a NaN. We only need to compare
8577 the signs, which we can get from isinf. */
8578 int result = isinf (dval1) - isinf (dval2);
8579
8580 if (result == 0)
8581 flags = Z|C;
8582 else if (result < 0)
8583 flags = N;
8584 else /* (result > 0). */
8585 flags = C;
8586 }
2e8cf49e
NC
8587 else
8588 {
8589 double result = dval1 - dval2;
8590
8591 if (result == 0.0)
8592 flags = Z|C;
8593 else if (result < 0)
8594 flags = N;
8595 else /* (result > 0). */
8596 flags = C;
8597 }
8598
8599 aarch64_set_CPSR (cpu, flags);
8600}
8601
8602/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8603static void
8604fcmpd (sim_cpu *cpu)
8605{
ef0d8ffc
NC
8606 unsigned sm = INSTR (20, 16);
8607 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8608
8609 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8610 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8611
2cdad34c 8612 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8613 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8614}
8615
8616/* Double compare to zero -- Invalid Operation exception
8617 only on signaling NaNs. */
8618static void
8619fcmpzd (sim_cpu *cpu)
8620{
ef0d8ffc 8621 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8622 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8623
2cdad34c 8624 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8625 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8626}
8627
8628/* Double compare -- Invalid Operation exception on all NaNs. */
8629static void
8630fcmped (sim_cpu *cpu)
8631{
ef0d8ffc
NC
8632 unsigned sm = INSTR (20, 16);
8633 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8634
8635 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8636 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8637
2cdad34c 8638 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8639 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8640}
8641
8642/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8643static void
8644fcmpzed (sim_cpu *cpu)
8645{
ef0d8ffc 8646 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8647 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8648
2cdad34c 8649 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8650 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8651}
8652
8653static void
8654dexSimpleFPCompare (sim_cpu *cpu)
8655{
8656 /* assert instr[28,25] == 1111
8657 instr[30:24:21:13,10] = 0011000
8658 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8659 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8660 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8661 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8662 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8663 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8664 ow ==> UNALLOC */
8665 uint32_t dispatch;
7517e550 8666 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8667 uint32_t type = INSTR (23, 22);
8668 uint32_t op = INSTR (15, 14);
8669 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8670
8671 if (op2_2_0 != 0)
8672 HALT_UNALLOC;
8673
8674 if (M_S != 0)
8675 HALT_UNALLOC;
8676
8677 if (type > 1)
8678 HALT_UNALLOC;
8679
8680 if (op != 0)
8681 HALT_UNALLOC;
8682
8683 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8684 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8685
8686 switch (dispatch)
8687 {
8688 case 0: fcmps (cpu); return;
8689 case 1: fcmpzs (cpu); return;
8690 case 2: fcmpes (cpu); return;
8691 case 3: fcmpzes (cpu); return;
8692 case 4: fcmpd (cpu); return;
8693 case 5: fcmpzd (cpu); return;
8694 case 6: fcmped (cpu); return;
8695 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8696 }
8697}
8698
8699static void
8700do_scalar_FADDP (sim_cpu *cpu)
8701{
7517e550 8702 /* instr [31,23] = 0111 1110 0
2e8cf49e 8703 instr [22] = single(0)/double(1)
7517e550 8704 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8705 instr [9,5] = Fn
8706 instr [4,0] = Fd. */
8707
ef0d8ffc
NC
8708 unsigned Fn = INSTR (9, 5);
8709 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8710
8711 NYI_assert (31, 23, 0x0FC);
8712 NYI_assert (21, 10, 0xC36);
8713
2cdad34c 8714 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8715 if (INSTR (22, 22))
2e8cf49e
NC
8716 {
8717 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8718 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8719
8720 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8721 }
8722 else
8723 {
8724 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8725 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8726
8727 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8728 }
8729}
8730
8731/* Floating point absolute difference. */
8732
8733static void
8734do_scalar_FABD (sim_cpu *cpu)
8735{
8736 /* instr [31,23] = 0111 1110 1
8737 instr [22] = float(0)/double(1)
8738 instr [21] = 1
8739 instr [20,16] = Rm
8740 instr [15,10] = 1101 01
8741 instr [9, 5] = Rn
8742 instr [4, 0] = Rd. */
8743
ef0d8ffc
NC
8744 unsigned rm = INSTR (20, 16);
8745 unsigned rn = INSTR (9, 5);
8746 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8747
8748 NYI_assert (31, 23, 0x0FD);
8749 NYI_assert (21, 21, 1);
8750 NYI_assert (15, 10, 0x35);
8751
2cdad34c 8752 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8753 if (INSTR (22, 22))
2e8cf49e
NC
8754 aarch64_set_FP_double (cpu, rd,
8755 fabs (aarch64_get_FP_double (cpu, rn)
8756 - aarch64_get_FP_double (cpu, rm)));
8757 else
8758 aarch64_set_FP_float (cpu, rd,
8759 fabsf (aarch64_get_FP_float (cpu, rn)
8760 - aarch64_get_FP_float (cpu, rm)));
8761}
8762
8763static void
8764do_scalar_CMGT (sim_cpu *cpu)
8765{
8766 /* instr [31,21] = 0101 1110 111
8767 instr [20,16] = Rm
8768 instr [15,10] = 00 1101
8769 instr [9, 5] = Rn
8770 instr [4, 0] = Rd. */
8771
ef0d8ffc
NC
8772 unsigned rm = INSTR (20, 16);
8773 unsigned rn = INSTR (9, 5);
8774 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8775
8776 NYI_assert (31, 21, 0x2F7);
8777 NYI_assert (15, 10, 0x0D);
8778
2cdad34c 8779 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8780 aarch64_set_vec_u64 (cpu, rd, 0,
8781 aarch64_get_vec_u64 (cpu, rn, 0) >
8782 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8783}
8784
8785static void
8786do_scalar_USHR (sim_cpu *cpu)
8787{
8788 /* instr [31,23] = 0111 1111 0
8789 instr [22,16] = shift amount
8790 instr [15,10] = 0000 01
8791 instr [9, 5] = Rn
8792 instr [4, 0] = Rd. */
8793
5ab6d79e
NC
8794 unsigned amount = 128 - INSTR (22, 16);
8795 unsigned rn = INSTR (9, 5);
8796 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8797
8798 NYI_assert (31, 23, 0x0FE);
8799 NYI_assert (15, 10, 0x01);
8800
2cdad34c 8801 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8802 aarch64_set_vec_u64 (cpu, rd, 0,
8803 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8804}
8805
8806static void
5ab6d79e
NC
8807do_scalar_SSHL (sim_cpu *cpu)
8808{
8809 /* instr [31,21] = 0101 1110 111
8810 instr [20,16] = Rm
8811 instr [15,10] = 0100 01
8812 instr [9, 5] = Rn
8813 instr [4, 0] = Rd. */
8814
8815 unsigned rm = INSTR (20, 16);
8816 unsigned rn = INSTR (9, 5);
8817 unsigned rd = INSTR (4, 0);
8818 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8819
8820 NYI_assert (31, 21, 0x2F7);
8821 NYI_assert (15, 10, 0x11);
8822
2cdad34c 8823 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8824 if (shift >= 0)
8825 aarch64_set_vec_s64 (cpu, rd, 0,
8826 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8827 else
8828 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8829 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8830}
8831
8832static void
8833do_scalar_shift (sim_cpu *cpu)
2e8cf49e 8834{
5ab6d79e 8835 /* instr [31,23] = 0101 1111 0
2e8cf49e 8836 instr [22,16] = shift amount
5ab6d79e
NC
8837 instr [15,10] = 0101 01 [SHL]
8838 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
8839 instr [9, 5] = Rn
8840 instr [4, 0] = Rd. */
8841
5ab6d79e
NC
8842 unsigned rn = INSTR (9, 5);
8843 unsigned rd = INSTR (4, 0);
8844 unsigned amount;
2e8cf49e
NC
8845
8846 NYI_assert (31, 23, 0x0BE);
2e8cf49e 8847
5ab6d79e 8848 if (INSTR (22, 22) == 0)
2e8cf49e
NC
8849 HALT_UNALLOC;
8850
2cdad34c 8851 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8852 switch (INSTR (15, 10))
8853 {
8854 case 0x01: /* SSHR */
8855 amount = 128 - INSTR (22, 16);
8856 aarch64_set_vec_s64 (cpu, rd, 0,
8857 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
8858 return;
8859 case 0x15: /* SHL */
8860 amount = INSTR (22, 16) - 64;
8861 aarch64_set_vec_u64 (cpu, rd, 0,
8862 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8863 return;
8864 default:
8865 HALT_NYI;
8866 }
2e8cf49e
NC
8867}
8868
8869/* FCMEQ FCMGT FCMGE. */
8870static void
8871do_scalar_FCM (sim_cpu *cpu)
8872{
8873 /* instr [31,30] = 01
8874 instr [29] = U
8875 instr [28,24] = 1 1110
8876 instr [23] = E
8877 instr [22] = size
8878 instr [21] = 1
8879 instr [20,16] = Rm
8880 instr [15,12] = 1110
8881 instr [11] = AC
8882 instr [10] = 1
8883 instr [9, 5] = Rn
8884 instr [4, 0] = Rd. */
8885
ef0d8ffc
NC
8886 unsigned rm = INSTR (20, 16);
8887 unsigned rn = INSTR (9, 5);
8888 unsigned rd = INSTR (4, 0);
7517e550 8889 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
8890 unsigned result;
8891 float val1;
8892 float val2;
8893
8894 NYI_assert (31, 30, 1);
8895 NYI_assert (28, 24, 0x1E);
8896 NYI_assert (21, 21, 1);
8897 NYI_assert (15, 12, 0xE);
8898 NYI_assert (10, 10, 1);
8899
2cdad34c 8900 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8901 if (INSTR (22, 22))
2e8cf49e
NC
8902 {
8903 double val1 = aarch64_get_FP_double (cpu, rn);
8904 double val2 = aarch64_get_FP_double (cpu, rm);
8905
8906 switch (EUac)
8907 {
8908 case 0: /* 000 */
8909 result = val1 == val2;
8910 break;
8911
8912 case 3: /* 011 */
8913 val1 = fabs (val1);
8914 val2 = fabs (val2);
8915 /* Fall through. */
8916 case 2: /* 010 */
8917 result = val1 >= val2;
8918 break;
8919
8920 case 7: /* 111 */
8921 val1 = fabs (val1);
8922 val2 = fabs (val2);
8923 /* Fall through. */
8924 case 6: /* 110 */
8925 result = val1 > val2;
8926 break;
8927
8928 default:
8929 HALT_UNALLOC;
8930 }
8931
8932 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8933 return;
8934 }
8935
8936 val1 = aarch64_get_FP_float (cpu, rn);
8937 val2 = aarch64_get_FP_float (cpu, rm);
8938
8939 switch (EUac)
8940 {
8941 case 0: /* 000 */
8942 result = val1 == val2;
8943 break;
8944
8945 case 3: /* 011 */
8946 val1 = fabsf (val1);
8947 val2 = fabsf (val2);
8948 /* Fall through. */
8949 case 2: /* 010 */
8950 result = val1 >= val2;
8951 break;
8952
8953 case 7: /* 111 */
8954 val1 = fabsf (val1);
8955 val2 = fabsf (val2);
8956 /* Fall through. */
8957 case 6: /* 110 */
8958 result = val1 > val2;
8959 break;
8960
8961 default:
8962 HALT_UNALLOC;
8963 }
8964
8965 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8966}
8967
8968/* An alias of DUP. */
8969static void
8970do_scalar_MOV (sim_cpu *cpu)
8971{
8972 /* instr [31,21] = 0101 1110 000
8973 instr [20,16] = imm5
8974 instr [15,10] = 0000 01
8975 instr [9, 5] = Rn
8976 instr [4, 0] = Rd. */
8977
ef0d8ffc
NC
8978 unsigned rn = INSTR (9, 5);
8979 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8980 unsigned index;
8981
8982 NYI_assert (31, 21, 0x2F0);
8983 NYI_assert (15, 10, 0x01);
8984
2cdad34c 8985 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8986 if (INSTR (16, 16))
2e8cf49e
NC
8987 {
8988 /* 8-bit. */
ef0d8ffc 8989 index = INSTR (20, 17);
2e8cf49e
NC
8990 aarch64_set_vec_u8
8991 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8992 }
ef0d8ffc 8993 else if (INSTR (17, 17))
2e8cf49e
NC
8994 {
8995 /* 16-bit. */
ef0d8ffc 8996 index = INSTR (20, 18);
2e8cf49e
NC
8997 aarch64_set_vec_u16
8998 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8999 }
ef0d8ffc 9000 else if (INSTR (18, 18))
2e8cf49e
NC
9001 {
9002 /* 32-bit. */
ef0d8ffc 9003 index = INSTR (20, 19);
2e8cf49e
NC
9004 aarch64_set_vec_u32
9005 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
9006 }
ef0d8ffc 9007 else if (INSTR (19, 19))
2e8cf49e
NC
9008 {
9009 /* 64-bit. */
ef0d8ffc 9010 index = INSTR (20, 20);
2e8cf49e
NC
9011 aarch64_set_vec_u64
9012 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
9013 }
9014 else
9015 HALT_UNALLOC;
9016}
9017
e101a78b
NC
9018static void
9019do_scalar_NEG (sim_cpu *cpu)
9020{
5ab6d79e 9021 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
9022 instr [9, 5] = Rn
9023 instr [4, 0] = Rd. */
9024
ef0d8ffc
NC
9025 unsigned rn = INSTR (9, 5);
9026 unsigned rd = INSTR (4, 0);
e101a78b 9027
5ab6d79e 9028 NYI_assert (31, 10, 0x1FB82E);
e101a78b 9029
2cdad34c 9030 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
9031 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
9032}
9033
5ab6d79e
NC
9034static void
9035do_scalar_USHL (sim_cpu *cpu)
9036{
9037 /* instr [31,21] = 0111 1110 111
9038 instr [20,16] = Rm
9039 instr [15,10] = 0100 01
9040 instr [9, 5] = Rn
9041 instr [4, 0] = Rd. */
9042
9043 unsigned rm = INSTR (20, 16);
9044 unsigned rn = INSTR (9, 5);
9045 unsigned rd = INSTR (4, 0);
9046 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
9047
9048 NYI_assert (31, 21, 0x3F7);
9049 NYI_assert (15, 10, 0x11);
9050
2cdad34c 9051 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9052 if (shift >= 0)
9053 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
9054 else
9055 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
9056}
9057
2e8cf49e
NC
9058static void
9059do_double_add (sim_cpu *cpu)
9060{
5ab6d79e
NC
9061 /* instr [31,21] = 0101 1110 111
9062 instr [20,16] = Fn
9063 instr [15,10] = 1000 01
9064 instr [9,5] = Fm
9065 instr [4,0] = Fd. */
2e8cf49e
NC
9066 unsigned Fd;
9067 unsigned Fm;
9068 unsigned Fn;
9069 double val1;
9070 double val2;
9071
5ab6d79e
NC
9072 NYI_assert (31, 21, 0x2F7);
9073 NYI_assert (15, 10, 0x21);
9074
9075 Fd = INSTR (4, 0);
9076 Fm = INSTR (9, 5);
9077 Fn = INSTR (20, 16);
9078
2cdad34c 9079 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9080 val1 = aarch64_get_FP_double (cpu, Fm);
9081 val2 = aarch64_get_FP_double (cpu, Fn);
9082
9083 aarch64_set_FP_double (cpu, Fd, val1 + val2);
9084}
9085
7517e550
NC
9086static void
9087do_scalar_UCVTF (sim_cpu *cpu)
9088{
9089 /* instr [31,23] = 0111 1110 0
9090 instr [22] = single(0)/double(1)
9091 instr [21,10] = 10 0001 1101 10
9092 instr [9,5] = rn
9093 instr [4,0] = rd. */
9094
9095 unsigned rn = INSTR (9, 5);
9096 unsigned rd = INSTR (4, 0);
9097
9098 NYI_assert (31, 23, 0x0FC);
9099 NYI_assert (21, 10, 0x876);
9100
2cdad34c 9101 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
9102 if (INSTR (22, 22))
9103 {
9104 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
9105
9106 aarch64_set_vec_double (cpu, rd, 0, (double) val);
9107 }
9108 else
9109 {
9110 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
9111
9112 aarch64_set_vec_float (cpu, rd, 0, (float) val);
9113 }
9114}
9115
5ab6d79e
NC
9116static void
9117do_scalar_vec (sim_cpu *cpu)
9118{
9119 /* instr [30] = 1. */
9120 /* instr [28,25] = 1111. */
ef0d8ffc 9121 switch (INSTR (31, 23))
2e8cf49e
NC
9122 {
9123 case 0xBC:
ef0d8ffc 9124 switch (INSTR (15, 10))
2e8cf49e
NC
9125 {
9126 case 0x01: do_scalar_MOV (cpu); return;
9127 case 0x39: do_scalar_FCM (cpu); return;
9128 case 0x3B: do_scalar_FCM (cpu); return;
9129 }
9130 break;
9131
5ab6d79e 9132 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
9133
9134 case 0xFC:
ef0d8ffc 9135 switch (INSTR (15, 10))
2e8cf49e 9136 {
7517e550
NC
9137 case 0x36:
9138 switch (INSTR (21, 16))
9139 {
9140 case 0x30: do_scalar_FADDP (cpu); return;
9141 case 0x21: do_scalar_UCVTF (cpu); return;
9142 }
9143 HALT_NYI;
2e8cf49e
NC
9144 case 0x39: do_scalar_FCM (cpu); return;
9145 case 0x3B: do_scalar_FCM (cpu); return;
9146 }
9147 break;
9148
9149 case 0xFD:
ef0d8ffc 9150 switch (INSTR (15, 10))
2e8cf49e
NC
9151 {
9152 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
9153 case 0x11: do_scalar_USHL (cpu); return;
9154 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
9155 case 0x35: do_scalar_FABD (cpu); return;
9156 case 0x39: do_scalar_FCM (cpu); return;
9157 case 0x3B: do_scalar_FCM (cpu); return;
9158 default:
9159 HALT_NYI;
9160 }
9161
9162 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
9163
9164 case 0xBD:
9165 switch (INSTR (15, 10))
9166 {
9167 case 0x21: do_double_add (cpu); return;
9168 case 0x11: do_scalar_SSHL (cpu); return;
9169 default:
9170 HALT_NYI;
9171 }
ef0d8ffc 9172
2e8cf49e 9173 default:
5ab6d79e 9174 HALT_NYI;
2e8cf49e 9175 }
2e8cf49e
NC
9176}
9177
9178static void
9179dexAdvSIMD1 (sim_cpu *cpu)
9180{
9181 /* instr [28,25] = 1 111. */
9182
5ab6d79e 9183 /* We are currently only interested in the basic
2e8cf49e 9184 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 9185 if (INSTR (30, 30))
5ab6d79e 9186 do_scalar_vec (cpu);
2e8cf49e
NC
9187
9188 /* instr[24] is set for FP data processing 3-source and clear for
9189 all other basic scalar fp instruction groups. */
ef0d8ffc 9190 else if (INSTR (24, 24))
2e8cf49e
NC
9191 dexSimpleFPDataProc3Source (cpu);
9192
9193 /* instr[21] is clear for floating <-> fixed conversions and set for
9194 all other basic scalar fp instruction groups. */
ef0d8ffc 9195 else if (!INSTR (21, 21))
2e8cf49e
NC
9196 dexSimpleFPFixedConvert (cpu);
9197
9198 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
9199 11 ==> cond select, 00 ==> other. */
9200 else
ef0d8ffc 9201 switch (INSTR (11, 10))
2e8cf49e
NC
9202 {
9203 case 1: dexSimpleFPCondCompare (cpu); return;
9204 case 2: dexSimpleFPDataProc2Source (cpu); return;
9205 case 3: dexSimpleFPCondSelect (cpu); return;
9206
9207 default:
9208 /* Now an ordered cascade of tests.
ef0d8ffc
NC
9209 FP immediate has instr [12] == 1.
9210 FP compare has instr [13] == 1.
9211 FP Data Proc 1 Source has instr [14] == 1.
9212 FP floating <--> integer conversions has instr [15] == 0. */
9213 if (INSTR (12, 12))
2e8cf49e
NC
9214 dexSimpleFPImmediate (cpu);
9215
ef0d8ffc 9216 else if (INSTR (13, 13))
2e8cf49e
NC
9217 dexSimpleFPCompare (cpu);
9218
ef0d8ffc 9219 else if (INSTR (14, 14))
2e8cf49e
NC
9220 dexSimpleFPDataProc1Source (cpu);
9221
ef0d8ffc 9222 else if (!INSTR (15, 15))
2e8cf49e
NC
9223 dexSimpleFPIntegerConvert (cpu);
9224
9225 else
9226 /* If we get here then instr[15] == 1 which means UNALLOC. */
9227 HALT_UNALLOC;
9228 }
9229}
9230
9231/* PC relative addressing. */
9232
9233static void
9234pcadr (sim_cpu *cpu)
9235{
9236 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
9237 instr[30,29] = immlo
9238 instr[23,5] = immhi. */
9239 uint64_t address;
ef0d8ffc
NC
9240 unsigned rd = INSTR (4, 0);
9241 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
9242 union { int64_t u64; uint64_t s64; } imm;
9243 uint64_t offset;
9244
9245 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
9246 offset = imm.u64;
ef0d8ffc 9247 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
9248
9249 address = aarch64_get_PC (cpu);
9250
9251 if (isPage)
9252 {
9253 offset <<= 12;
9254 address &= ~0xfff;
9255 }
9256
2cdad34c 9257 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9258 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
9259}
9260
9261/* Specific decode and execute for group Data Processing Immediate. */
9262
9263static void
9264dexPCRelAddressing (sim_cpu *cpu)
9265{
9266 /* assert instr[28,24] = 10000. */
9267 pcadr (cpu);
9268}
9269
9270/* Immediate logical.
9271 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
9272 16, 32 or 64 bit sequence pulled out at decode and possibly
9273 inverting it..
9274
9275 N.B. the output register (dest) can normally be Xn or SP
9276 the exception occurs for flag setting instructions which may
9277 only use Xn for the output (dest). The input register can
9278 never be SP. */
9279
9280/* 32 bit and immediate. */
9281static void
9282and32 (sim_cpu *cpu, uint32_t bimm)
9283{
ef0d8ffc
NC
9284 unsigned rn = INSTR (9, 5);
9285 unsigned rd = INSTR (4, 0);
2e8cf49e 9286
2cdad34c 9287 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9288 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9289 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
9290}
9291
9292/* 64 bit and immediate. */
9293static void
9294and64 (sim_cpu *cpu, uint64_t bimm)
9295{
ef0d8ffc
NC
9296 unsigned rn = INSTR (9, 5);
9297 unsigned rd = INSTR (4, 0);
2e8cf49e 9298
2cdad34c 9299 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9300 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9301 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
9302}
9303
9304/* 32 bit and immediate set flags. */
9305static void
9306ands32 (sim_cpu *cpu, uint32_t bimm)
9307{
ef0d8ffc
NC
9308 unsigned rn = INSTR (9, 5);
9309 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9310
9311 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9312 uint32_t value2 = bimm;
9313
2cdad34c 9314 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9315 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9316 set_flags_for_binop32 (cpu, value1 & value2);
9317}
9318
9319/* 64 bit and immediate set flags. */
9320static void
9321ands64 (sim_cpu *cpu, uint64_t bimm)
9322{
ef0d8ffc
NC
9323 unsigned rn = INSTR (9, 5);
9324 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9325
9326 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9327 uint64_t value2 = bimm;
9328
2cdad34c 9329 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9330 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9331 set_flags_for_binop64 (cpu, value1 & value2);
9332}
9333
9334/* 32 bit exclusive or immediate. */
9335static void
9336eor32 (sim_cpu *cpu, uint32_t bimm)
9337{
ef0d8ffc
NC
9338 unsigned rn = INSTR (9, 5);
9339 unsigned rd = INSTR (4, 0);
2e8cf49e 9340
2cdad34c 9341 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9342 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9343 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9344}
9345
9346/* 64 bit exclusive or immediate. */
9347static void
9348eor64 (sim_cpu *cpu, uint64_t bimm)
9349{
ef0d8ffc
NC
9350 unsigned rn = INSTR (9, 5);
9351 unsigned rd = INSTR (4, 0);
2e8cf49e 9352
2cdad34c 9353 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9354 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9355 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9356}
9357
9358/* 32 bit or immediate. */
9359static void
9360orr32 (sim_cpu *cpu, uint32_t bimm)
9361{
ef0d8ffc
NC
9362 unsigned rn = INSTR (9, 5);
9363 unsigned rd = INSTR (4, 0);
2e8cf49e 9364
2cdad34c 9365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9366 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9367 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9368}
9369
9370/* 64 bit or immediate. */
9371static void
9372orr64 (sim_cpu *cpu, uint64_t bimm)
9373{
ef0d8ffc
NC
9374 unsigned rn = INSTR (9, 5);
9375 unsigned rd = INSTR (4, 0);
2e8cf49e 9376
2cdad34c 9377 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9378 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9379 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9380}
9381
9382/* Logical shifted register.
9383 These allow an optional LSL, ASR, LSR or ROR to the second source
9384 register with a count up to the register bit count.
9385 N.B register args may not be SP. */
9386
9387/* 32 bit AND shifted register. */
9388static void
9389and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9390{
ef0d8ffc
NC
9391 unsigned rm = INSTR (20, 16);
9392 unsigned rn = INSTR (9, 5);
9393 unsigned rd = INSTR (4, 0);
2e8cf49e 9394
2cdad34c 9395 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9396 aarch64_set_reg_u64
9397 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9398 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9399}
9400
9401/* 64 bit AND shifted register. */
9402static void
9403and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9404{
ef0d8ffc
NC
9405 unsigned rm = INSTR (20, 16);
9406 unsigned rn = INSTR (9, 5);
9407 unsigned rd = INSTR (4, 0);
2e8cf49e 9408
2cdad34c 9409 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9410 aarch64_set_reg_u64
9411 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9412 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9413}
9414
9415/* 32 bit AND shifted register setting flags. */
9416static void
9417ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9418{
ef0d8ffc
NC
9419 unsigned rm = INSTR (20, 16);
9420 unsigned rn = INSTR (9, 5);
9421 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9422
9423 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9424 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9425 shift, count);
9426
2cdad34c 9427 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9428 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9429 set_flags_for_binop32 (cpu, value1 & value2);
9430}
9431
9432/* 64 bit AND shifted register setting flags. */
9433static void
9434ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9435{
ef0d8ffc
NC
9436 unsigned rm = INSTR (20, 16);
9437 unsigned rn = INSTR (9, 5);
9438 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9439
9440 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9441 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9442 shift, count);
9443
2cdad34c 9444 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9445 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9446 set_flags_for_binop64 (cpu, value1 & value2);
9447}
9448
9449/* 32 bit BIC shifted register. */
9450static void
9451bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9452{
ef0d8ffc
NC
9453 unsigned rm = INSTR (20, 16);
9454 unsigned rn = INSTR (9, 5);
9455 unsigned rd = INSTR (4, 0);
2e8cf49e 9456
2cdad34c 9457 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9458 aarch64_set_reg_u64
9459 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9460 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9461}
9462
9463/* 64 bit BIC shifted register. */
9464static void
9465bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9466{
ef0d8ffc
NC
9467 unsigned rm = INSTR (20, 16);
9468 unsigned rn = INSTR (9, 5);
9469 unsigned rd = INSTR (4, 0);
2e8cf49e 9470
2cdad34c 9471 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9472 aarch64_set_reg_u64
9473 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9474 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9475}
9476
9477/* 32 bit BIC shifted register setting flags. */
9478static void
9479bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9480{
ef0d8ffc
NC
9481 unsigned rm = INSTR (20, 16);
9482 unsigned rn = INSTR (9, 5);
9483 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9484
9485 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9486 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9487 shift, count);
9488
2cdad34c 9489 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9490 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9491 set_flags_for_binop32 (cpu, value1 & value2);
9492}
9493
9494/* 64 bit BIC shifted register setting flags. */
9495static void
9496bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9497{
ef0d8ffc
NC
9498 unsigned rm = INSTR (20, 16);
9499 unsigned rn = INSTR (9, 5);
9500 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9501
9502 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9503 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9504 shift, count);
9505
2cdad34c 9506 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9507 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9508 set_flags_for_binop64 (cpu, value1 & value2);
9509}
9510
9511/* 32 bit EON shifted register. */
9512static void
9513eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9514{
ef0d8ffc
NC
9515 unsigned rm = INSTR (20, 16);
9516 unsigned rn = INSTR (9, 5);
9517 unsigned rd = INSTR (4, 0);
2e8cf49e 9518
2cdad34c 9519 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9520 aarch64_set_reg_u64
9521 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9522 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9523}
9524
9525/* 64 bit EON shifted register. */
9526static void
9527eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9528{
ef0d8ffc
NC
9529 unsigned rm = INSTR (20, 16);
9530 unsigned rn = INSTR (9, 5);
9531 unsigned rd = INSTR (4, 0);
2e8cf49e 9532
2cdad34c 9533 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9534 aarch64_set_reg_u64
9535 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9536 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9537}
9538
9539/* 32 bit EOR shifted register. */
9540static void
9541eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9542{
ef0d8ffc
NC
9543 unsigned rm = INSTR (20, 16);
9544 unsigned rn = INSTR (9, 5);
9545 unsigned rd = INSTR (4, 0);
2e8cf49e 9546
2cdad34c 9547 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9548 aarch64_set_reg_u64
9549 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9550 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9551}
9552
9553/* 64 bit EOR shifted register. */
9554static void
9555eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9556{
ef0d8ffc
NC
9557 unsigned rm = INSTR (20, 16);
9558 unsigned rn = INSTR (9, 5);
9559 unsigned rd = INSTR (4, 0);
2e8cf49e 9560
2cdad34c 9561 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9562 aarch64_set_reg_u64
9563 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9564 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9565}
9566
9567/* 32 bit ORR shifted register. */
9568static void
9569orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9570{
ef0d8ffc
NC
9571 unsigned rm = INSTR (20, 16);
9572 unsigned rn = INSTR (9, 5);
9573 unsigned rd = INSTR (4, 0);
2e8cf49e 9574
2cdad34c 9575 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9576 aarch64_set_reg_u64
9577 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9578 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9579}
9580
9581/* 64 bit ORR shifted register. */
9582static void
9583orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9584{
ef0d8ffc
NC
9585 unsigned rm = INSTR (20, 16);
9586 unsigned rn = INSTR (9, 5);
9587 unsigned rd = INSTR (4, 0);
2e8cf49e 9588
2cdad34c 9589 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9590 aarch64_set_reg_u64
9591 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9592 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9593}
9594
9595/* 32 bit ORN shifted register. */
9596static void
9597orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9598{
ef0d8ffc
NC
9599 unsigned rm = INSTR (20, 16);
9600 unsigned rn = INSTR (9, 5);
9601 unsigned rd = INSTR (4, 0);
2e8cf49e 9602
2cdad34c 9603 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9604 aarch64_set_reg_u64
9605 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9606 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9607}
9608
9609/* 64 bit ORN shifted register. */
9610static void
9611orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9612{
ef0d8ffc
NC
9613 unsigned rm = INSTR (20, 16);
9614 unsigned rn = INSTR (9, 5);
9615 unsigned rd = INSTR (4, 0);
2e8cf49e 9616
2cdad34c 9617 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9618 aarch64_set_reg_u64
9619 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9620 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9621}
9622
9623static void
9624dexLogicalImmediate (sim_cpu *cpu)
9625{
9626 /* assert instr[28,23] = 1001000
9627 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9628 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9629 instr[22] = N : used to construct immediate mask
9630 instr[21,16] = immr
9631 instr[15,10] = imms
9632 instr[9,5] = Rn
9633 instr[4,0] = Rd */
9634
9635 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9636 uint32_t size = INSTR (31, 31);
9637 uint32_t N = INSTR (22, 22);
9638 /* uint32_t immr = INSTR (21, 16);. */
9639 /* uint32_t imms = INSTR (15, 10);. */
9640 uint32_t index = INSTR (22, 10);
2e8cf49e 9641 uint64_t bimm64 = LITable [index];
ef0d8ffc 9642 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9643
9644 if (~size & N)
9645 HALT_UNALLOC;
9646
9647 if (!bimm64)
9648 HALT_UNALLOC;
9649
9650 if (size == 0)
9651 {
9652 uint32_t bimm = (uint32_t) bimm64;
9653
9654 switch (dispatch)
9655 {
9656 case 0: and32 (cpu, bimm); return;
9657 case 1: orr32 (cpu, bimm); return;
9658 case 2: eor32 (cpu, bimm); return;
9659 case 3: ands32 (cpu, bimm); return;
9660 }
9661 }
9662 else
9663 {
9664 switch (dispatch)
9665 {
9666 case 0: and64 (cpu, bimm64); return;
9667 case 1: orr64 (cpu, bimm64); return;
9668 case 2: eor64 (cpu, bimm64); return;
9669 case 3: ands64 (cpu, bimm64); return;
9670 }
9671 }
9672 HALT_UNALLOC;
9673}
9674
9675/* Immediate move.
9676 The uimm argument is a 16 bit value to be inserted into the
9677 target register the pos argument locates the 16 bit word in the
9678 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9679 3} for 64 bit.
9680 N.B register arg may not be SP so it should be.
9681 accessed using the setGZRegisterXXX accessors. */
9682
9683/* 32 bit move 16 bit immediate zero remaining shorts. */
9684static void
9685movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9686{
ef0d8ffc 9687 unsigned rd = INSTR (4, 0);
2e8cf49e 9688
2cdad34c 9689 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9690 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9691}
9692
9693/* 64 bit move 16 bit immediate zero remaining shorts. */
9694static void
9695movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9696{
ef0d8ffc 9697 unsigned rd = INSTR (4, 0);
2e8cf49e 9698
2cdad34c 9699 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9700 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9701}
9702
9703/* 32 bit move 16 bit immediate negated. */
9704static void
9705movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9706{
ef0d8ffc 9707 unsigned rd = INSTR (4, 0);
2e8cf49e 9708
2cdad34c 9709 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9710 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
9711}
9712
9713/* 64 bit move 16 bit immediate negated. */
9714static void
9715movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9716{
ef0d8ffc 9717 unsigned rd = INSTR (4, 0);
2e8cf49e 9718
2cdad34c 9719 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9720 aarch64_set_reg_u64
9721 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
9722 ^ 0xffffffffffffffffULL));
9723}
9724
9725/* 32 bit move 16 bit immediate keep remaining shorts. */
9726static void
9727movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9728{
ef0d8ffc 9729 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9730 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9731 uint32_t value = val << (pos * 16);
9732 uint32_t mask = ~(0xffffU << (pos * 16));
9733
2cdad34c 9734 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9735 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9736}
9737
9738/* 64 bit move 16 it immediate keep remaining shorts. */
9739static void
9740movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9741{
ef0d8ffc 9742 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9743 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
9744 uint64_t value = (uint64_t) val << (pos * 16);
9745 uint64_t mask = ~(0xffffULL << (pos * 16));
9746
2cdad34c 9747 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9748 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9749}
9750
9751static void
9752dexMoveWideImmediate (sim_cpu *cpu)
9753{
9754 /* assert instr[28:23] = 100101
9755 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9756 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
9757 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
9758 instr[20,5] = uimm16
9759 instr[4,0] = Rd */
9760
9761 /* N.B. the (multiple of 16) shift is applied by the called routine,
9762 we just pass the multiplier. */
9763
9764 uint32_t imm;
ef0d8ffc
NC
9765 uint32_t size = INSTR (31, 31);
9766 uint32_t op = INSTR (30, 29);
9767 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
9768
9769 /* 32 bit can only shift 0 or 1 lot of 16.
9770 anything else is an unallocated instruction. */
9771 if (size == 0 && (shift > 1))
9772 HALT_UNALLOC;
9773
9774 if (op == 1)
9775 HALT_UNALLOC;
9776
ef0d8ffc 9777 imm = INSTR (20, 5);
2e8cf49e
NC
9778
9779 if (size == 0)
9780 {
9781 if (op == 0)
9782 movn32 (cpu, imm, shift);
9783 else if (op == 2)
9784 movz32 (cpu, imm, shift);
9785 else
9786 movk32 (cpu, imm, shift);
9787 }
9788 else
9789 {
9790 if (op == 0)
9791 movn64 (cpu, imm, shift);
9792 else if (op == 2)
9793 movz64 (cpu, imm, shift);
9794 else
9795 movk64 (cpu, imm, shift);
9796 }
9797}
9798
9799/* Bitfield operations.
9800 These take a pair of bit positions r and s which are in {0..31}
9801 or {0..63} depending on the instruction word size.
9802 N.B register args may not be SP. */
9803
9804/* OK, we start with ubfm which just needs to pick
9805 some bits out of source zero the rest and write
9806 the result to dest. Just need two logical shifts. */
9807
9808/* 32 bit bitfield move, left and right of affected zeroed
9809 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9810static void
9811ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9812{
9813 unsigned rd;
ef0d8ffc 9814 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9815 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9816
9817 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9818 if (r <= s)
9819 {
9820 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9821 We want only bits s:xxx:r at the bottom of the word
9822 so we LSL bit s up to bit 31 i.e. by 31 - s
9823 and then we LSR to bring bit 31 down to bit s - r
9824 i.e. by 31 + r - s. */
9825 value <<= 31 - s;
9826 value >>= 31 + r - s;
9827 }
9828 else
9829 {
9830 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
9831 We want only bits s:xxx:0 starting at it 31-(r-1)
9832 so we LSL bit s up to bit 31 i.e. by 31 - s
9833 and then we LSL to bring bit 31 down to 31-(r-1)+s
9834 i.e. by r - (s + 1). */
9835 value <<= 31 - s;
9836 value >>= r - (s + 1);
9837 }
9838
2cdad34c 9839 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9840 rd = INSTR (4, 0);
2e8cf49e
NC
9841 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9842}
9843
9844/* 64 bit bitfield move, left and right of affected zeroed
9845 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9846static void
9847ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9848{
9849 unsigned rd;
ef0d8ffc 9850 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9851 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9852
9853 if (r <= s)
9854 {
9855 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9856 We want only bits s:xxx:r at the bottom of the word.
9857 So we LSL bit s up to bit 63 i.e. by 63 - s
9858 and then we LSR to bring bit 63 down to bit s - r
9859 i.e. by 63 + r - s. */
9860 value <<= 63 - s;
9861 value >>= 63 + r - s;
9862 }
9863 else
9864 {
9865 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9866 We want only bits s:xxx:0 starting at it 63-(r-1).
9867 So we LSL bit s up to bit 63 i.e. by 63 - s
9868 and then we LSL to bring bit 63 down to 63-(r-1)+s
9869 i.e. by r - (s + 1). */
9870 value <<= 63 - s;
9871 value >>= r - (s + 1);
9872 }
9873
2cdad34c 9874 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9875 rd = INSTR (4, 0);
2e8cf49e
NC
9876 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9877}
9878
9879/* The signed versions need to insert sign bits
9880 on the left of the inserted bit field. so we do
9881 much the same as the unsigned version except we
9882 use an arithmetic shift right -- this just means
9883 we need to operate on signed values. */
9884
9885/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9886/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9887static void
9888sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9889{
9890 unsigned rd;
ef0d8ffc 9891 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9892 /* as per ubfm32 but use an ASR instead of an LSR. */
9893 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9894
9895 if (r <= s)
9896 {
9897 value <<= 31 - s;
9898 value >>= 31 + r - s;
9899 }
9900 else
9901 {
9902 value <<= 31 - s;
9903 value >>= r - (s + 1);
9904 }
9905
2cdad34c 9906 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9907 rd = INSTR (4, 0);
2e8cf49e
NC
9908 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
9909}
9910
9911/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
9912/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9913static void
9914sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9915{
9916 unsigned rd;
ef0d8ffc 9917 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9918 /* acpu per ubfm but use an ASR instead of an LSR. */
9919 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
9920
9921 if (r <= s)
9922 {
9923 value <<= 63 - s;
9924 value >>= 63 + r - s;
9925 }
9926 else
9927 {
9928 value <<= 63 - s;
9929 value >>= r - (s + 1);
9930 }
9931
2cdad34c 9932 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9933 rd = INSTR (4, 0);
2e8cf49e
NC
9934 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
9935}
9936
9937/* Finally, these versions leave non-affected bits
9938 as is. so we need to generate the bits as per
9939 ubfm and also generate a mask to pick the
9940 bits from the original and computed values. */
9941
9942/* 32 bit bitfield move, non-affected bits left as is.
9943 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9944static void
9945bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9946{
ef0d8ffc 9947 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9948 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9949 uint32_t mask = -1;
9950 unsigned rd;
9951 uint32_t value2;
9952
9953 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9954 if (r <= s)
9955 {
9956 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9957 We want only bits s:xxx:r at the bottom of the word
9958 so we LSL bit s up to bit 31 i.e. by 31 - s
9959 and then we LSR to bring bit 31 down to bit s - r
9960 i.e. by 31 + r - s. */
9961 value <<= 31 - s;
9962 value >>= 31 + r - s;
9963 /* the mask must include the same bits. */
9964 mask <<= 31 - s;
9965 mask >>= 31 + r - s;
9966 }
9967 else
9968 {
9969 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9970 We want only bits s:xxx:0 starting at it 31-(r-1)
9971 so we LSL bit s up to bit 31 i.e. by 31 - s
9972 and then we LSL to bring bit 31 down to 31-(r-1)+s
9973 i.e. by r - (s + 1). */
9974 value <<= 31 - s;
9975 value >>= r - (s + 1);
9976 /* The mask must include the same bits. */
9977 mask <<= 31 - s;
9978 mask >>= r - (s + 1);
9979 }
9980
ef0d8ffc 9981 rd = INSTR (4, 0);
2e8cf49e
NC
9982 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9983
9984 value2 &= ~mask;
9985 value2 |= value;
9986
2cdad34c 9987 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9988 aarch64_set_reg_u64
9989 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9990}
9991
9992/* 64 bit bitfield move, non-affected bits left as is.
9993 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9994static void
9995bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9996{
9997 unsigned rd;
ef0d8ffc 9998 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9999 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
10000 uint64_t mask = 0xffffffffffffffffULL;
10001
10002 if (r <= s)
10003 {
10004 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
10005 We want only bits s:xxx:r at the bottom of the word
10006 so we LSL bit s up to bit 63 i.e. by 63 - s
10007 and then we LSR to bring bit 63 down to bit s - r
10008 i.e. by 63 + r - s. */
10009 value <<= 63 - s;
10010 value >>= 63 + r - s;
10011 /* The mask must include the same bits. */
10012 mask <<= 63 - s;
10013 mask >>= 63 + r - s;
10014 }
10015 else
10016 {
10017 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
10018 We want only bits s:xxx:0 starting at it 63-(r-1)
10019 so we LSL bit s up to bit 63 i.e. by 63 - s
10020 and then we LSL to bring bit 63 down to 63-(r-1)+s
10021 i.e. by r - (s + 1). */
10022 value <<= 63 - s;
10023 value >>= r - (s + 1);
10024 /* The mask must include the same bits. */
10025 mask <<= 63 - s;
10026 mask >>= r - (s + 1);
10027 }
10028
2cdad34c 10029 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10030 rd = INSTR (4, 0);
2e8cf49e
NC
10031 aarch64_set_reg_u64
10032 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
10033}
10034
10035static void
10036dexBitfieldImmediate (sim_cpu *cpu)
10037{
10038 /* assert instr[28:23] = 100110
10039 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10040 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
10041 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
10042 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
10043 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10044 instr[9,5] = Rn
10045 instr[4,0] = Rd */
10046
10047 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10048 uint32_t dispatch;
10049 uint32_t imms;
ef0d8ffc
NC
10050 uint32_t size = INSTR (31, 31);
10051 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10052 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
10053 /* or else we have an UNALLOC. */
ef0d8ffc 10054 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
10055
10056 if (~size & N)
10057 HALT_UNALLOC;
10058
10059 if (!size && uimm (immr, 5, 5))
10060 HALT_UNALLOC;
10061
ef0d8ffc 10062 imms = INSTR (15, 10);
2e8cf49e
NC
10063 if (!size && uimm (imms, 5, 5))
10064 HALT_UNALLOC;
10065
10066 /* Switch on combined size and op. */
ef0d8ffc 10067 dispatch = INSTR (31, 29);
2e8cf49e
NC
10068 switch (dispatch)
10069 {
10070 case 0: sbfm32 (cpu, immr, imms); return;
10071 case 1: bfm32 (cpu, immr, imms); return;
10072 case 2: ubfm32 (cpu, immr, imms); return;
10073 case 4: sbfm (cpu, immr, imms); return;
10074 case 5: bfm (cpu, immr, imms); return;
10075 case 6: ubfm (cpu, immr, imms); return;
10076 default: HALT_UNALLOC;
10077 }
10078}
10079
10080static void
10081do_EXTR_32 (sim_cpu *cpu)
10082{
10083 /* instr[31:21] = 00010011100
10084 instr[20,16] = Rm
10085 instr[15,10] = imms : 0xxxxx for 32 bit
10086 instr[9,5] = Rn
10087 instr[4,0] = Rd */
ef0d8ffc
NC
10088 unsigned rm = INSTR (20, 16);
10089 unsigned imms = INSTR (15, 10) & 31;
10090 unsigned rn = INSTR ( 9, 5);
10091 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10092 uint64_t val1;
10093 uint64_t val2;
10094
10095 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
10096 val1 >>= imms;
10097 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10098 val2 <<= (32 - imms);
10099
2cdad34c 10100 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10101 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
10102}
10103
10104static void
10105do_EXTR_64 (sim_cpu *cpu)
10106{
10107 /* instr[31:21] = 10010011100
10108 instr[20,16] = Rm
10109 instr[15,10] = imms
10110 instr[9,5] = Rn
10111 instr[4,0] = Rd */
ef0d8ffc
NC
10112 unsigned rm = INSTR (20, 16);
10113 unsigned imms = INSTR (15, 10) & 63;
10114 unsigned rn = INSTR ( 9, 5);
10115 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10116 uint64_t val;
10117
10118 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
10119 val >>= imms;
10120 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
10121
10122 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
10123}
10124
10125static void
10126dexExtractImmediate (sim_cpu *cpu)
10127{
10128 /* assert instr[28:23] = 100111
10129 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10130 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
10131 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
10132 instr[21] = op0 : must be 0 or UNALLOC
10133 instr[20,16] = Rm
10134 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10135 instr[9,5] = Rn
10136 instr[4,0] = Rd */
10137
10138 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10139 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
10140 uint32_t dispatch;
ef0d8ffc
NC
10141 uint32_t size = INSTR (31, 31);
10142 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10143 /* 32 bit operations must have imms[5] = 0
10144 or else we have an UNALLOC. */
ef0d8ffc 10145 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
10146
10147 if (size ^ N)
10148 HALT_UNALLOC;
10149
10150 if (!size && uimm (imms, 5, 5))
10151 HALT_UNALLOC;
10152
10153 /* Switch on combined size and op. */
ef0d8ffc 10154 dispatch = INSTR (31, 29);
2e8cf49e
NC
10155
10156 if (dispatch == 0)
10157 do_EXTR_32 (cpu);
10158
10159 else if (dispatch == 4)
10160 do_EXTR_64 (cpu);
10161
10162 else if (dispatch == 1)
10163 HALT_NYI;
10164 else
10165 HALT_UNALLOC;
10166}
10167
10168static void
10169dexDPImm (sim_cpu *cpu)
10170{
10171 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
10172 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
10173 bits [25,23] of a DPImm are the secondary dispatch vector. */
10174 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
10175
10176 switch (group2)
10177 {
10178 case DPIMM_PCADR_000:
10179 case DPIMM_PCADR_001:
10180 dexPCRelAddressing (cpu);
10181 return;
10182
10183 case DPIMM_ADDSUB_010:
10184 case DPIMM_ADDSUB_011:
10185 dexAddSubtractImmediate (cpu);
10186 return;
10187
10188 case DPIMM_LOG_100:
10189 dexLogicalImmediate (cpu);
10190 return;
10191
10192 case DPIMM_MOV_101:
10193 dexMoveWideImmediate (cpu);
10194 return;
10195
10196 case DPIMM_BITF_110:
10197 dexBitfieldImmediate (cpu);
10198 return;
10199
10200 case DPIMM_EXTR_111:
10201 dexExtractImmediate (cpu);
10202 return;
10203
10204 default:
10205 /* Should never reach here. */
10206 HALT_NYI;
10207 }
10208}
10209
10210static void
10211dexLoadUnscaledImmediate (sim_cpu *cpu)
10212{
10213 /* instr[29,24] == 111_00
10214 instr[21] == 0
10215 instr[11,10] == 00
10216 instr[31,30] = size
10217 instr[26] = V
10218 instr[23,22] = opc
10219 instr[20,12] = simm9
10220 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
10221 /* unsigned rt = INSTR (4, 0); */
10222 uint32_t V = INSTR (26, 26);
7517e550 10223 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
10224 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10225
10226 if (!V)
10227 {
10228 /* GReg operations. */
10229 switch (dispatch)
10230 {
10231 case 0: sturb (cpu, imm); return;
10232 case 1: ldurb32 (cpu, imm); return;
10233 case 2: ldursb64 (cpu, imm); return;
10234 case 3: ldursb32 (cpu, imm); return;
10235 case 4: sturh (cpu, imm); return;
10236 case 5: ldurh32 (cpu, imm); return;
10237 case 6: ldursh64 (cpu, imm); return;
10238 case 7: ldursh32 (cpu, imm); return;
10239 case 8: stur32 (cpu, imm); return;
10240 case 9: ldur32 (cpu, imm); return;
10241 case 10: ldursw (cpu, imm); return;
10242 case 12: stur64 (cpu, imm); return;
10243 case 13: ldur64 (cpu, imm); return;
10244
10245 case 14:
10246 /* PRFUM NYI. */
10247 HALT_NYI;
10248
10249 default:
10250 case 11:
10251 case 15:
10252 HALT_UNALLOC;
10253 }
10254 }
10255
10256 /* FReg operations. */
10257 switch (dispatch)
10258 {
10259 case 2: fsturq (cpu, imm); return;
10260 case 3: fldurq (cpu, imm); return;
10261 case 8: fsturs (cpu, imm); return;
10262 case 9: fldurs (cpu, imm); return;
10263 case 12: fsturd (cpu, imm); return;
10264 case 13: fldurd (cpu, imm); return;
10265
10266 case 0: /* STUR 8 bit FP. */
10267 case 1: /* LDUR 8 bit FP. */
10268 case 4: /* STUR 16 bit FP. */
10269 case 5: /* LDUR 8 bit FP. */
10270 HALT_NYI;
10271
10272 default:
10273 case 6:
10274 case 7:
10275 case 10:
10276 case 11:
10277 case 14:
10278 case 15:
10279 HALT_UNALLOC;
10280 }
10281}
10282
10283/* N.B. A preliminary note regarding all the ldrs<x>32
10284 instructions
10285
10286 The signed value loaded by these instructions is cast to unsigned
10287 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
10288 64 bit element of the GReg union. this performs a 32 bit sign extension
10289 (as required) but avoids 64 bit sign extension, thus ensuring that the
10290 top half of the register word is zero. this is what the spec demands
10291 when a 32 bit load occurs. */
10292
10293/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
10294static void
10295ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
10296{
ef0d8ffc
NC
10297 unsigned int rn = INSTR (9, 5);
10298 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10299
10300 /* The target register may not be SP but the source may be
10301 there is no scaling required for a byte load. */
10302 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
10303 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10304 (int64_t) aarch64_get_mem_s8 (cpu, address));
10305}
10306
10307/* 32 bit load sign-extended byte scaled or unscaled zero-
10308 or sign-extended 32-bit register offset. */
10309static void
10310ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10311{
ef0d8ffc
NC
10312 unsigned int rm = INSTR (20, 16);
10313 unsigned int rn = INSTR (9, 5);
10314 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10315
10316 /* rn may reference SP, rm and rt must reference ZR. */
10317
10318 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10319 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10320 extension);
10321
10322 /* There is no scaling required for a byte load. */
10323 aarch64_set_reg_u64
10324 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
10325 + displacement));
10326}
10327
10328/* 32 bit load sign-extended byte unscaled signed 9 bit with
10329 pre- or post-writeback. */
10330static void
10331ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10332{
10333 uint64_t address;
ef0d8ffc
NC
10334 unsigned int rn = INSTR (9, 5);
10335 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10336
10337 if (rn == rt && wb != NoWriteBack)
10338 HALT_UNALLOC;
10339
10340 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10341
10342 if (wb == Pre)
10343 address += offset;
10344
10345 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10346 (int64_t) aarch64_get_mem_s8 (cpu, address));
10347
10348 if (wb == Post)
10349 address += offset;
10350
10351 if (wb != NoWriteBack)
10352 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
10353}
10354
10355/* 8 bit store scaled. */
10356static void
10357fstrb_abs (sim_cpu *cpu, uint32_t offset)
10358{
ef0d8ffc
NC
10359 unsigned st = INSTR (4, 0);
10360 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10361
10362 aarch64_set_mem_u8 (cpu,
10363 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
10364 aarch64_get_vec_u8 (cpu, st, 0));
10365}
10366
10367/* 8 bit store scaled or unscaled zero- or
10368 sign-extended 8-bit register offset. */
10369static void
10370fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10371{
ef0d8ffc
NC
10372 unsigned rm = INSTR (20, 16);
10373 unsigned rn = INSTR (9, 5);
10374 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10375
10376 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10377 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10378 extension);
7517e550 10379 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10380
10381 aarch64_set_mem_u8
10382 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10383}
10384
10385/* 16 bit store scaled. */
10386static void
10387fstrh_abs (sim_cpu *cpu, uint32_t offset)
10388{
ef0d8ffc
NC
10389 unsigned st = INSTR (4, 0);
10390 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10391
10392 aarch64_set_mem_u16
10393 (cpu,
10394 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10395 aarch64_get_vec_u16 (cpu, st, 0));
10396}
10397
10398/* 16 bit store scaled or unscaled zero-
10399 or sign-extended 16-bit register offset. */
10400static void
10401fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10402{
ef0d8ffc
NC
10403 unsigned rm = INSTR (20, 16);
10404 unsigned rn = INSTR (9, 5);
10405 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10406
10407 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10408 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10409 extension);
7517e550 10410 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10411
10412 aarch64_set_mem_u16
10413 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10414}
10415
10416/* 32 bit store scaled unsigned 12 bit. */
10417static void
10418fstrs_abs (sim_cpu *cpu, uint32_t offset)
10419{
ef0d8ffc
NC
10420 unsigned st = INSTR (4, 0);
10421 unsigned rn = INSTR (9, 5);
2e8cf49e 10422
e101a78b 10423 aarch64_set_mem_u32
2e8cf49e
NC
10424 (cpu,
10425 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10426 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10427}
10428
10429/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10430static void
10431fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10432{
ef0d8ffc
NC
10433 unsigned rn = INSTR (9, 5);
10434 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10435
10436 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10437
10438 if (wb != Post)
10439 address += offset;
10440
e101a78b 10441 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10442
10443 if (wb == Post)
10444 address += offset;
10445
10446 if (wb != NoWriteBack)
10447 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10448}
10449
10450/* 32 bit store scaled or unscaled zero-
10451 or sign-extended 32-bit register offset. */
10452static void
10453fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10454{
ef0d8ffc
NC
10455 unsigned rm = INSTR (20, 16);
10456 unsigned rn = INSTR (9, 5);
10457 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10458
10459 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10460 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10461 extension);
10462 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10463
e101a78b
NC
10464 aarch64_set_mem_u32
10465 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10466}
10467
10468/* 64 bit store scaled unsigned 12 bit. */
10469static void
10470fstrd_abs (sim_cpu *cpu, uint32_t offset)
10471{
ef0d8ffc
NC
10472 unsigned st = INSTR (4, 0);
10473 unsigned rn = INSTR (9, 5);
2e8cf49e 10474
e101a78b 10475 aarch64_set_mem_u64
2e8cf49e
NC
10476 (cpu,
10477 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10478 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10479}
10480
10481/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10482static void
10483fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10484{
ef0d8ffc
NC
10485 unsigned rn = INSTR (9, 5);
10486 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10487
10488 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10489
10490 if (wb != Post)
10491 address += offset;
10492
e101a78b 10493 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10494
10495 if (wb == Post)
10496 address += offset;
10497
10498 if (wb != NoWriteBack)
10499 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10500}
10501
10502/* 64 bit store scaled or unscaled zero-
10503 or sign-extended 32-bit register offset. */
10504static void
10505fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10506{
ef0d8ffc
NC
10507 unsigned rm = INSTR (20, 16);
10508 unsigned rn = INSTR (9, 5);
10509 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10510
10511 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10512 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10513 extension);
10514 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10515
e101a78b
NC
10516 aarch64_set_mem_u64
10517 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10518}
10519
10520/* 128 bit store scaled unsigned 12 bit. */
10521static void
10522fstrq_abs (sim_cpu *cpu, uint32_t offset)
10523{
10524 FRegister a;
ef0d8ffc
NC
10525 unsigned st = INSTR (4, 0);
10526 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10527 uint64_t addr;
10528
10529 aarch64_get_FP_long_double (cpu, st, & a);
10530
10531 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10532 aarch64_set_mem_long_double (cpu, addr, a);
10533}
10534
10535/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10536static void
10537fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10538{
10539 FRegister a;
ef0d8ffc
NC
10540 unsigned rn = INSTR (9, 5);
10541 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10542 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10543
10544 if (wb != Post)
10545 address += offset;
10546
10547 aarch64_get_FP_long_double (cpu, st, & a);
10548 aarch64_set_mem_long_double (cpu, address, a);
10549
10550 if (wb == Post)
10551 address += offset;
10552
10553 if (wb != NoWriteBack)
10554 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10555}
10556
10557/* 128 bit store scaled or unscaled zero-
10558 or sign-extended 32-bit register offset. */
10559static void
10560fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10561{
ef0d8ffc
NC
10562 unsigned rm = INSTR (20, 16);
10563 unsigned rn = INSTR (9, 5);
10564 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10565
10566 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10567 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10568 extension);
10569 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10570
10571 FRegister a;
10572
10573 aarch64_get_FP_long_double (cpu, st, & a);
10574 aarch64_set_mem_long_double (cpu, address + displacement, a);
10575}
10576
10577static void
10578dexLoadImmediatePrePost (sim_cpu *cpu)
10579{
ef0d8ffc
NC
10580 /* instr[31,30] = size
10581 instr[29,27] = 111
10582 instr[26] = V
10583 instr[25,24] = 00
2e8cf49e 10584 instr[23,22] = opc
ef0d8ffc 10585 instr[21] = 0
2e8cf49e 10586 instr[20,12] = simm9
ef0d8ffc
NC
10587 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10588 instr[10] = 0
10589 instr[9,5] = Rn may be SP.
10590 instr[4,0] = Rt */
10591
10592 uint32_t V = INSTR (26, 26);
10593 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10594 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10595 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10596
10597 if (!V)
10598 {
10599 /* GReg operations. */
10600 switch (dispatch)
10601 {
10602 case 0: strb_wb (cpu, imm, wb); return;
10603 case 1: ldrb32_wb (cpu, imm, wb); return;
10604 case 2: ldrsb_wb (cpu, imm, wb); return;
10605 case 3: ldrsb32_wb (cpu, imm, wb); return;
10606 case 4: strh_wb (cpu, imm, wb); return;
10607 case 5: ldrh32_wb (cpu, imm, wb); return;
10608 case 6: ldrsh64_wb (cpu, imm, wb); return;
10609 case 7: ldrsh32_wb (cpu, imm, wb); return;
10610 case 8: str32_wb (cpu, imm, wb); return;
10611 case 9: ldr32_wb (cpu, imm, wb); return;
10612 case 10: ldrsw_wb (cpu, imm, wb); return;
10613 case 12: str_wb (cpu, imm, wb); return;
10614 case 13: ldr_wb (cpu, imm, wb); return;
10615
10616 default:
10617 case 11:
10618 case 14:
10619 case 15:
10620 HALT_UNALLOC;
10621 }
10622 }
10623
10624 /* FReg operations. */
10625 switch (dispatch)
10626 {
10627 case 2: fstrq_wb (cpu, imm, wb); return;
10628 case 3: fldrq_wb (cpu, imm, wb); return;
10629 case 8: fstrs_wb (cpu, imm, wb); return;
10630 case 9: fldrs_wb (cpu, imm, wb); return;
10631 case 12: fstrd_wb (cpu, imm, wb); return;
10632 case 13: fldrd_wb (cpu, imm, wb); return;
10633
10634 case 0: /* STUR 8 bit FP. */
10635 case 1: /* LDUR 8 bit FP. */
10636 case 4: /* STUR 16 bit FP. */
10637 case 5: /* LDUR 8 bit FP. */
10638 HALT_NYI;
10639
10640 default:
10641 case 6:
10642 case 7:
10643 case 10:
10644 case 11:
10645 case 14:
10646 case 15:
10647 HALT_UNALLOC;
10648 }
10649}
10650
10651static void
10652dexLoadRegisterOffset (sim_cpu *cpu)
10653{
10654 /* instr[31,30] = size
10655 instr[29,27] = 111
10656 instr[26] = V
10657 instr[25,24] = 00
10658 instr[23,22] = opc
10659 instr[21] = 1
10660 instr[20,16] = rm
10661 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10662 110 ==> SXTW, 111 ==> SXTX,
10663 ow ==> RESERVED
10664 instr[12] = scaled
10665 instr[11,10] = 10
10666 instr[9,5] = rn
10667 instr[4,0] = rt. */
10668
ef0d8ffc
NC
10669 uint32_t V = INSTR (26, 26);
10670 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10671 Scaling scale = INSTR (12, 12);
10672 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10673
10674 /* Check for illegal extension types. */
10675 if (uimm (extensionType, 1, 1) == 0)
10676 HALT_UNALLOC;
10677
10678 if (extensionType == UXTX || extensionType == SXTX)
10679 extensionType = NoExtension;
10680
10681 if (!V)
10682 {
10683 /* GReg operations. */
10684 switch (dispatch)
10685 {
10686 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10687 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10688 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10689 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10690 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10691 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10692 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10693 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10694 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10695 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10696 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10697 case 12: str_scale_ext (cpu, scale, extensionType); return;
10698 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10699 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10700
10701 default:
10702 case 11:
10703 case 15:
10704 HALT_UNALLOC;
10705 }
10706 }
10707
10708 /* FReg operations. */
10709 switch (dispatch)
10710 {
10711 case 1: /* LDUR 8 bit FP. */
10712 HALT_NYI;
10713 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
10714 case 5: /* LDUR 8 bit FP. */
10715 HALT_NYI;
10716 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
10717 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
10718
10719 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
10720 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
10721 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
10722 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
10723 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
10724
10725 default:
10726 case 6:
10727 case 7:
10728 case 10:
10729 case 11:
10730 case 14:
10731 case 15:
10732 HALT_UNALLOC;
10733 }
10734}
10735
10736static void
10737dexLoadUnsignedImmediate (sim_cpu *cpu)
10738{
5ab6d79e 10739 /* instr[29,24] == 111_01
2e8cf49e 10740 instr[31,30] = size
5ab6d79e 10741 instr[26] = V
2e8cf49e
NC
10742 instr[23,22] = opc
10743 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
10744 instr[9,5] = rn may be SP.
10745 instr[4,0] = rt. */
ef0d8ffc
NC
10746
10747 uint32_t V = INSTR (26,26);
7517e550 10748 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 10749 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
10750
10751 if (!V)
10752 {
10753 /* GReg operations. */
10754 switch (dispatch)
10755 {
10756 case 0: strb_abs (cpu, imm); return;
10757 case 1: ldrb32_abs (cpu, imm); return;
10758 case 2: ldrsb_abs (cpu, imm); return;
10759 case 3: ldrsb32_abs (cpu, imm); return;
10760 case 4: strh_abs (cpu, imm); return;
10761 case 5: ldrh32_abs (cpu, imm); return;
10762 case 6: ldrsh_abs (cpu, imm); return;
10763 case 7: ldrsh32_abs (cpu, imm); return;
10764 case 8: str32_abs (cpu, imm); return;
10765 case 9: ldr32_abs (cpu, imm); return;
10766 case 10: ldrsw_abs (cpu, imm); return;
10767 case 12: str_abs (cpu, imm); return;
10768 case 13: ldr_abs (cpu, imm); return;
10769 case 14: prfm_abs (cpu, imm); return;
10770
10771 default:
10772 case 11:
10773 case 15:
10774 HALT_UNALLOC;
10775 }
10776 }
10777
10778 /* FReg operations. */
10779 switch (dispatch)
10780 {
2e8cf49e 10781 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
10782 case 4: fstrh_abs (cpu, imm); return;
10783 case 8: fstrs_abs (cpu, imm); return;
10784 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 10785 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 10786
5ab6d79e
NC
10787 case 1: fldrb_abs (cpu, imm); return;
10788 case 5: fldrh_abs (cpu, imm); return;
10789 case 9: fldrs_abs (cpu, imm); return;
10790 case 13: fldrd_abs (cpu, imm); return;
10791 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
10792
10793 default:
10794 case 6:
10795 case 7:
10796 case 10:
10797 case 11:
10798 case 14:
10799 case 15:
10800 HALT_UNALLOC;
10801 }
10802}
10803
10804static void
10805dexLoadExclusive (sim_cpu *cpu)
10806{
10807 /* assert instr[29:24] = 001000;
10808 instr[31,30] = size
10809 instr[23] = 0 if exclusive
10810 instr[22] = L : 1 if load, 0 if store
10811 instr[21] = 1 if pair
10812 instr[20,16] = Rs
10813 instr[15] = o0 : 1 if ordered
10814 instr[14,10] = Rt2
10815 instr[9,5] = Rn
10816 instr[4.0] = Rt. */
10817
ef0d8ffc 10818 switch (INSTR (22, 21))
2e8cf49e
NC
10819 {
10820 case 2: ldxr (cpu); return;
10821 case 0: stxr (cpu); return;
10822 default: HALT_NYI;
10823 }
10824}
10825
10826static void
10827dexLoadOther (sim_cpu *cpu)
10828{
10829 uint32_t dispatch;
10830
10831 /* instr[29,25] = 111_0
10832 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
10833 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 10834 if (INSTR (24, 24))
2e8cf49e
NC
10835 {
10836 dexLoadUnsignedImmediate (cpu);
10837 return;
10838 }
10839
7517e550 10840 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
10841 switch (dispatch)
10842 {
10843 case 0: dexLoadUnscaledImmediate (cpu); return;
10844 case 1: dexLoadImmediatePrePost (cpu); return;
10845 case 3: dexLoadImmediatePrePost (cpu); return;
10846 case 6: dexLoadRegisterOffset (cpu); return;
10847
10848 default:
10849 case 2:
10850 case 4:
10851 case 5:
10852 case 7:
10853 HALT_NYI;
10854 }
10855}
10856
10857static void
10858store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10859{
ef0d8ffc
NC
10860 unsigned rn = INSTR (14, 10);
10861 unsigned rd = INSTR (9, 5);
10862 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10863 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10864
10865 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10866 HALT_UNALLOC; /* ??? */
10867
10868 offset <<= 2;
10869
10870 if (wb != Post)
10871 address += offset;
10872
10873 aarch64_set_mem_u32 (cpu, address,
10874 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10875 aarch64_set_mem_u32 (cpu, address + 4,
10876 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10877
10878 if (wb == Post)
10879 address += offset;
10880
10881 if (wb != NoWriteBack)
10882 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10883}
10884
10885static void
10886store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10887{
ef0d8ffc
NC
10888 unsigned rn = INSTR (14, 10);
10889 unsigned rd = INSTR (9, 5);
10890 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10891 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10892
10893 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10894 HALT_UNALLOC; /* ??? */
10895
10896 offset <<= 3;
10897
10898 if (wb != Post)
10899 address += offset;
10900
10901 aarch64_set_mem_u64 (cpu, address,
7517e550 10902 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 10903 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 10904 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
10905
10906 if (wb == Post)
10907 address += offset;
10908
10909 if (wb != NoWriteBack)
10910 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10911}
10912
10913static void
10914load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10915{
ef0d8ffc
NC
10916 unsigned rn = INSTR (14, 10);
10917 unsigned rd = INSTR (9, 5);
10918 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10919 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10920
7517e550 10921 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
10922 if (rn == rm)
10923 HALT_UNALLOC;
10924
10925 offset <<= 2;
10926
10927 if (wb != Post)
10928 address += offset;
10929
10930 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
10931 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
10932
10933 if (wb == Post)
10934 address += offset;
10935
10936 if (wb != NoWriteBack)
10937 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10938}
10939
10940static void
10941load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10942{
ef0d8ffc
NC
10943 unsigned rn = INSTR (14, 10);
10944 unsigned rd = INSTR (9, 5);
10945 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10946 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10947
10948 /* Treat this as unalloc to make sure we don't do it. */
10949 if (rn == rm)
10950 HALT_UNALLOC;
10951
10952 offset <<= 2;
10953
10954 if (wb != Post)
10955 address += offset;
10956
10957 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10958 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10959
10960 if (wb == Post)
10961 address += offset;
10962
10963 if (wb != NoWriteBack)
10964 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10965}
10966
10967static void
10968load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10969{
ef0d8ffc
NC
10970 unsigned rn = INSTR (14, 10);
10971 unsigned rd = INSTR (9, 5);
10972 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10973 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10974
10975 /* Treat this as unalloc to make sure we don't do it. */
10976 if (rn == rm)
10977 HALT_UNALLOC;
10978
10979 offset <<= 3;
10980
10981 if (wb != Post)
10982 address += offset;
10983
10984 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10985 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10986
10987 if (wb == Post)
10988 address += offset;
10989
10990 if (wb != NoWriteBack)
10991 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10992}
10993
10994static void
10995dex_load_store_pair_gr (sim_cpu *cpu)
10996{
10997 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10998 instr[29,25] = instruction encoding: 101_0
10999 instr[26] = V : 1 if fp 0 if gp
11000 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11001 instr[22] = load/store (1=> load)
11002 instr[21,15] = signed, scaled, offset
11003 instr[14,10] = Rn
11004 instr[ 9, 5] = Rd
11005 instr[ 4, 0] = Rm. */
11006
7517e550 11007 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11008 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11009
11010 switch (dispatch)
11011 {
11012 case 2: store_pair_u32 (cpu, offset, Post); return;
11013 case 3: load_pair_u32 (cpu, offset, Post); return;
11014 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
11015 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
11016 case 6: store_pair_u32 (cpu, offset, Pre); return;
11017 case 7: load_pair_u32 (cpu, offset, Pre); return;
11018
11019 case 11: load_pair_s32 (cpu, offset, Post); return;
11020 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
11021 case 15: load_pair_s32 (cpu, offset, Pre); return;
11022
11023 case 18: store_pair_u64 (cpu, offset, Post); return;
11024 case 19: load_pair_u64 (cpu, offset, Post); return;
11025 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
11026 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
11027 case 22: store_pair_u64 (cpu, offset, Pre); return;
11028 case 23: load_pair_u64 (cpu, offset, Pre); return;
11029
11030 default:
11031 HALT_UNALLOC;
11032 }
11033}
11034
11035static void
11036store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11037{
ef0d8ffc
NC
11038 unsigned rn = INSTR (14, 10);
11039 unsigned rd = INSTR (9, 5);
11040 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11041 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11042
11043 offset <<= 2;
11044
11045 if (wb != Post)
11046 address += offset;
11047
e101a78b
NC
11048 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
11049 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
11050
11051 if (wb == Post)
11052 address += offset;
11053
11054 if (wb != NoWriteBack)
11055 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11056}
11057
11058static void
11059store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11060{
ef0d8ffc
NC
11061 unsigned rn = INSTR (14, 10);
11062 unsigned rd = INSTR (9, 5);
11063 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11064 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11065
11066 offset <<= 3;
11067
11068 if (wb != Post)
11069 address += offset;
11070
e101a78b
NC
11071 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
11072 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
11073
11074 if (wb == Post)
11075 address += offset;
11076
11077 if (wb != NoWriteBack)
11078 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11079}
11080
11081static void
11082store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11083{
11084 FRegister a;
ef0d8ffc
NC
11085 unsigned rn = INSTR (14, 10);
11086 unsigned rd = INSTR (9, 5);
11087 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11088 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11089
11090 offset <<= 4;
11091
11092 if (wb != Post)
11093 address += offset;
11094
11095 aarch64_get_FP_long_double (cpu, rm, & a);
11096 aarch64_set_mem_long_double (cpu, address, a);
11097 aarch64_get_FP_long_double (cpu, rn, & a);
11098 aarch64_set_mem_long_double (cpu, address + 16, a);
11099
11100 if (wb == Post)
11101 address += offset;
11102
11103 if (wb != NoWriteBack)
11104 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11105}
11106
11107static void
11108load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11109{
ef0d8ffc
NC
11110 unsigned rn = INSTR (14, 10);
11111 unsigned rd = INSTR (9, 5);
11112 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11113 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11114
11115 if (rm == rn)
11116 HALT_UNALLOC;
11117
11118 offset <<= 2;
11119
11120 if (wb != Post)
11121 address += offset;
11122
e101a78b
NC
11123 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
11124 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
11125
11126 if (wb == Post)
11127 address += offset;
11128
11129 if (wb != NoWriteBack)
11130 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11131}
11132
11133static void
11134load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11135{
ef0d8ffc
NC
11136 unsigned rn = INSTR (14, 10);
11137 unsigned rd = INSTR (9, 5);
11138 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11139 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11140
11141 if (rm == rn)
11142 HALT_UNALLOC;
11143
11144 offset <<= 3;
11145
11146 if (wb != Post)
11147 address += offset;
11148
e101a78b
NC
11149 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
11150 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
11151
11152 if (wb == Post)
11153 address += offset;
11154
11155 if (wb != NoWriteBack)
11156 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11157}
11158
11159static void
11160load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11161{
11162 FRegister a;
ef0d8ffc
NC
11163 unsigned rn = INSTR (14, 10);
11164 unsigned rd = INSTR (9, 5);
11165 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11166 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11167
11168 if (rm == rn)
11169 HALT_UNALLOC;
11170
11171 offset <<= 4;
11172
11173 if (wb != Post)
11174 address += offset;
11175
11176 aarch64_get_mem_long_double (cpu, address, & a);
11177 aarch64_set_FP_long_double (cpu, rm, a);
11178 aarch64_get_mem_long_double (cpu, address + 16, & a);
11179 aarch64_set_FP_long_double (cpu, rn, a);
11180
11181 if (wb == Post)
11182 address += offset;
11183
11184 if (wb != NoWriteBack)
11185 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11186}
11187
11188static void
11189dex_load_store_pair_fp (sim_cpu *cpu)
11190{
11191 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
11192 instr[29,25] = instruction encoding
11193 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11194 instr[22] = load/store (1=> load)
11195 instr[21,15] = signed, scaled, offset
11196 instr[14,10] = Rn
11197 instr[ 9, 5] = Rd
11198 instr[ 4, 0] = Rm */
11199
7517e550 11200 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11201 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11202
11203 switch (dispatch)
11204 {
11205 case 2: store_pair_float (cpu, offset, Post); return;
11206 case 3: load_pair_float (cpu, offset, Post); return;
11207 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
11208 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
11209 case 6: store_pair_float (cpu, offset, Pre); return;
11210 case 7: load_pair_float (cpu, offset, Pre); return;
11211
11212 case 10: store_pair_double (cpu, offset, Post); return;
11213 case 11: load_pair_double (cpu, offset, Post); return;
11214 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
11215 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
11216 case 14: store_pair_double (cpu, offset, Pre); return;
11217 case 15: load_pair_double (cpu, offset, Pre); return;
11218
11219 case 18: store_pair_long_double (cpu, offset, Post); return;
11220 case 19: load_pair_long_double (cpu, offset, Post); return;
11221 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
11222 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
11223 case 22: store_pair_long_double (cpu, offset, Pre); return;
11224 case 23: load_pair_long_double (cpu, offset, Pre); return;
11225
11226 default:
11227 HALT_UNALLOC;
11228 }
11229}
11230
11231static inline unsigned
11232vec_reg (unsigned v, unsigned o)
11233{
11234 return (v + o) & 0x3F;
11235}
11236
11237/* Load multiple N-element structures to N consecutive registers. */
11238static void
11239vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
11240{
ef0d8ffc
NC
11241 int all = INSTR (30, 30);
11242 unsigned size = INSTR (11, 10);
11243 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11244 unsigned i;
11245
11246 switch (size)
11247 {
11248 case 0: /* 8-bit operations. */
11249 if (all)
11250 for (i = 0; i < (16 * N); i++)
11251 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
11252 aarch64_get_mem_u8 (cpu, address + i));
11253 else
11254 for (i = 0; i < (8 * N); i++)
11255 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
11256 aarch64_get_mem_u8 (cpu, address + i));
11257 return;
11258
11259 case 1: /* 16-bit operations. */
11260 if (all)
11261 for (i = 0; i < (8 * N); i++)
11262 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
11263 aarch64_get_mem_u16 (cpu, address + i * 2));
11264 else
11265 for (i = 0; i < (4 * N); i++)
11266 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
11267 aarch64_get_mem_u16 (cpu, address + i * 2));
11268 return;
11269
11270 case 2: /* 32-bit operations. */
11271 if (all)
11272 for (i = 0; i < (4 * N); i++)
11273 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
11274 aarch64_get_mem_u32 (cpu, address + i * 4));
11275 else
11276 for (i = 0; i < (2 * N); i++)
11277 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
11278 aarch64_get_mem_u32 (cpu, address + i * 4));
11279 return;
11280
11281 case 3: /* 64-bit operations. */
11282 if (all)
11283 for (i = 0; i < (2 * N); i++)
11284 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
11285 aarch64_get_mem_u64 (cpu, address + i * 8));
11286 else
11287 for (i = 0; i < N; i++)
11288 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
11289 aarch64_get_mem_u64 (cpu, address + i * 8));
11290 return;
2e8cf49e
NC
11291 }
11292}
11293
11294/* LD4: load multiple 4-element to four consecutive registers. */
11295static void
11296LD4 (sim_cpu *cpu, uint64_t address)
11297{
11298 vec_load (cpu, address, 4);
11299}
11300
11301/* LD3: load multiple 3-element structures to three consecutive registers. */
11302static void
11303LD3 (sim_cpu *cpu, uint64_t address)
11304{
11305 vec_load (cpu, address, 3);
11306}
11307
11308/* LD2: load multiple 2-element structures to two consecutive registers. */
11309static void
11310LD2 (sim_cpu *cpu, uint64_t address)
11311{
11312 vec_load (cpu, address, 2);
11313}
11314
11315/* Load multiple 1-element structures into one register. */
11316static void
11317LD1_1 (sim_cpu *cpu, uint64_t address)
11318{
ef0d8ffc
NC
11319 int all = INSTR (30, 30);
11320 unsigned size = INSTR (11, 10);
11321 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11322 unsigned i;
11323
11324 switch (size)
11325 {
11326 case 0:
11327 /* LD1 {Vd.16b}, addr, #16 */
11328 /* LD1 {Vd.8b}, addr, #8 */
11329 for (i = 0; i < (all ? 16 : 8); i++)
11330 aarch64_set_vec_u8 (cpu, vd, i,
11331 aarch64_get_mem_u8 (cpu, address + i));
11332 return;
11333
11334 case 1:
11335 /* LD1 {Vd.8h}, addr, #16 */
11336 /* LD1 {Vd.4h}, addr, #8 */
11337 for (i = 0; i < (all ? 8 : 4); i++)
11338 aarch64_set_vec_u16 (cpu, vd, i,
11339 aarch64_get_mem_u16 (cpu, address + i * 2));
11340 return;
11341
11342 case 2:
11343 /* LD1 {Vd.4s}, addr, #16 */
11344 /* LD1 {Vd.2s}, addr, #8 */
11345 for (i = 0; i < (all ? 4 : 2); i++)
11346 aarch64_set_vec_u32 (cpu, vd, i,
11347 aarch64_get_mem_u32 (cpu, address + i * 4));
11348 return;
11349
11350 case 3:
11351 /* LD1 {Vd.2d}, addr, #16 */
11352 /* LD1 {Vd.1d}, addr, #8 */
11353 for (i = 0; i < (all ? 2 : 1); i++)
11354 aarch64_set_vec_u64 (cpu, vd, i,
11355 aarch64_get_mem_u64 (cpu, address + i * 8));
11356 return;
2e8cf49e
NC
11357 }
11358}
11359
11360/* Load multiple 1-element structures into two registers. */
11361static void
11362LD1_2 (sim_cpu *cpu, uint64_t address)
11363{
11364 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
11365 So why have two different instructions ? There must be something
11366 wrong somewhere. */
11367 vec_load (cpu, address, 2);
11368}
11369
11370/* Load multiple 1-element structures into three registers. */
11371static void
11372LD1_3 (sim_cpu *cpu, uint64_t address)
11373{
11374 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
11375 So why have two different instructions ? There must be something
11376 wrong somewhere. */
11377 vec_load (cpu, address, 3);
11378}
11379
11380/* Load multiple 1-element structures into four registers. */
11381static void
11382LD1_4 (sim_cpu *cpu, uint64_t address)
11383{
11384 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
11385 So why have two different instructions ? There must be something
11386 wrong somewhere. */
11387 vec_load (cpu, address, 4);
11388}
11389
11390/* Store multiple N-element structures to N consecutive registers. */
11391static void
11392vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
11393{
ef0d8ffc
NC
11394 int all = INSTR (30, 30);
11395 unsigned size = INSTR (11, 10);
11396 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11397 unsigned i;
11398
11399 switch (size)
11400 {
11401 case 0: /* 8-bit operations. */
11402 if (all)
11403 for (i = 0; i < (16 * N); i++)
11404 aarch64_set_mem_u8
11405 (cpu, address + i,
11406 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
11407 else
11408 for (i = 0; i < (8 * N); i++)
11409 aarch64_set_mem_u8
11410 (cpu, address + i,
11411 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
11412 return;
11413
11414 case 1: /* 16-bit operations. */
11415 if (all)
11416 for (i = 0; i < (8 * N); i++)
11417 aarch64_set_mem_u16
11418 (cpu, address + i * 2,
11419 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
11420 else
11421 for (i = 0; i < (4 * N); i++)
11422 aarch64_set_mem_u16
11423 (cpu, address + i * 2,
11424 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
11425 return;
11426
11427 case 2: /* 32-bit operations. */
11428 if (all)
11429 for (i = 0; i < (4 * N); i++)
11430 aarch64_set_mem_u32
11431 (cpu, address + i * 4,
11432 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
11433 else
11434 for (i = 0; i < (2 * N); i++)
11435 aarch64_set_mem_u32
11436 (cpu, address + i * 4,
11437 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
11438 return;
11439
11440 case 3: /* 64-bit operations. */
11441 if (all)
11442 for (i = 0; i < (2 * N); i++)
11443 aarch64_set_mem_u64
11444 (cpu, address + i * 8,
11445 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
11446 else
11447 for (i = 0; i < N; i++)
11448 aarch64_set_mem_u64
11449 (cpu, address + i * 8,
11450 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
11451 return;
2e8cf49e
NC
11452 }
11453}
11454
11455/* Store multiple 4-element structure to four consecutive registers. */
11456static void
11457ST4 (sim_cpu *cpu, uint64_t address)
11458{
11459 vec_store (cpu, address, 4);
11460}
11461
11462/* Store multiple 3-element structures to three consecutive registers. */
11463static void
11464ST3 (sim_cpu *cpu, uint64_t address)
11465{
11466 vec_store (cpu, address, 3);
11467}
11468
11469/* Store multiple 2-element structures to two consecutive registers. */
11470static void
11471ST2 (sim_cpu *cpu, uint64_t address)
11472{
11473 vec_store (cpu, address, 2);
11474}
11475
11476/* Store multiple 1-element structures into one register. */
11477static void
11478ST1_1 (sim_cpu *cpu, uint64_t address)
11479{
ef0d8ffc
NC
11480 int all = INSTR (30, 30);
11481 unsigned size = INSTR (11, 10);
11482 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11483 unsigned i;
11484
11485 switch (size)
11486 {
11487 case 0:
11488 for (i = 0; i < (all ? 16 : 8); i++)
11489 aarch64_set_mem_u8 (cpu, address + i,
11490 aarch64_get_vec_u8 (cpu, vd, i));
11491 return;
11492
11493 case 1:
11494 for (i = 0; i < (all ? 8 : 4); i++)
11495 aarch64_set_mem_u16 (cpu, address + i * 2,
11496 aarch64_get_vec_u16 (cpu, vd, i));
11497 return;
11498
11499 case 2:
11500 for (i = 0; i < (all ? 4 : 2); i++)
11501 aarch64_set_mem_u32 (cpu, address + i * 4,
11502 aarch64_get_vec_u32 (cpu, vd, i));
11503 return;
11504
11505 case 3:
11506 for (i = 0; i < (all ? 2 : 1); i++)
11507 aarch64_set_mem_u64 (cpu, address + i * 8,
11508 aarch64_get_vec_u64 (cpu, vd, i));
11509 return;
2e8cf49e
NC
11510 }
11511}
11512
11513/* Store multiple 1-element structures into two registers. */
11514static void
11515ST1_2 (sim_cpu *cpu, uint64_t address)
11516{
11517 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
11518 So why have two different instructions ? There must be
11519 something wrong somewhere. */
11520 vec_store (cpu, address, 2);
11521}
11522
11523/* Store multiple 1-element structures into three registers. */
11524static void
11525ST1_3 (sim_cpu *cpu, uint64_t address)
11526{
11527 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
11528 So why have two different instructions ? There must be
11529 something wrong somewhere. */
11530 vec_store (cpu, address, 3);
11531}
11532
11533/* Store multiple 1-element structures into four registers. */
11534static void
11535ST1_4 (sim_cpu *cpu, uint64_t address)
11536{
11537 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
11538 So why have two different instructions ? There must be
11539 something wrong somewhere. */
11540 vec_store (cpu, address, 4);
11541}
11542
11543static void
11544do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11545{
11546 /* instr[31] = 0
11547 instr[30] = element selector 0=>half, 1=>all elements
11548 instr[29,24] = 00 1101
11549 instr[23] = 0=>simple, 1=>post
11550 instr[22] = 1
11551 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11552 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11553 11111 (immediate post inc)
11554 instr[15,14] = 11
11555 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11556 instr[12] = 0
11557 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11558 10=> word(s), 11=> double(d)
11559 instr[9,5] = address
11560 instr[4,0] = Vd */
11561
ef0d8ffc
NC
11562 unsigned full = INSTR (30, 30);
11563 unsigned vd = INSTR (4, 0);
11564 unsigned size = INSTR (11, 10);
2e8cf49e
NC
11565 int i;
11566
11567 NYI_assert (29, 24, 0x0D);
11568 NYI_assert (22, 22, 1);
11569 NYI_assert (15, 14, 3);
11570 NYI_assert (12, 12, 0);
11571
7517e550 11572 switch ((INSTR (13, 13) << 1) | INSTR (21, 21))
2e8cf49e
NC
11573 {
11574 case 0: /* LD1R. */
11575 switch (size)
11576 {
11577 case 0:
11578 {
11579 uint8_t val = aarch64_get_mem_u8 (cpu, address);
11580 for (i = 0; i < (full ? 16 : 8); i++)
11581 aarch64_set_vec_u8 (cpu, vd, i, val);
11582 break;
11583 }
11584
11585 case 1:
11586 {
11587 uint16_t val = aarch64_get_mem_u16 (cpu, address);
11588 for (i = 0; i < (full ? 8 : 4); i++)
11589 aarch64_set_vec_u16 (cpu, vd, i, val);
11590 break;
11591 }
11592
11593 case 2:
11594 {
11595 uint32_t val = aarch64_get_mem_u32 (cpu, address);
11596 for (i = 0; i < (full ? 4 : 2); i++)
11597 aarch64_set_vec_u32 (cpu, vd, i, val);
11598 break;
11599 }
11600
11601 case 3:
11602 {
11603 uint64_t val = aarch64_get_mem_u64 (cpu, address);
11604 for (i = 0; i < (full ? 2 : 1); i++)
11605 aarch64_set_vec_u64 (cpu, vd, i, val);
11606 break;
11607 }
11608
11609 default:
11610 HALT_UNALLOC;
11611 }
11612 break;
11613
11614 case 1: /* LD2R. */
11615 switch (size)
11616 {
11617 case 0:
11618 {
11619 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11620 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11621
11622 for (i = 0; i < (full ? 16 : 8); i++)
11623 {
11624 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11625 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11626 }
11627 break;
11628 }
11629
11630 case 1:
11631 {
11632 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
11633 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11634
11635 for (i = 0; i < (full ? 8 : 4); i++)
11636 {
11637 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11638 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11639 }
11640 break;
11641 }
11642
11643 case 2:
11644 {
11645 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11646 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11647
11648 for (i = 0; i < (full ? 4 : 2); i++)
11649 {
11650 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11651 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11652 }
11653 break;
11654 }
11655
11656 case 3:
11657 {
11658 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11659 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11660
11661 for (i = 0; i < (full ? 2 : 1); i++)
11662 {
11663 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11664 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11665 }
11666 break;
11667 }
11668
11669 default:
11670 HALT_UNALLOC;
11671 }
11672 break;
11673
11674 case 2: /* LD3R. */
11675 switch (size)
11676 {
11677 case 0:
11678 {
11679 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11680 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11681 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11682
11683 for (i = 0; i < (full ? 16 : 8); i++)
11684 {
11685 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11686 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11687 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11688 }
11689 }
11690 break;
11691
11692 case 1:
11693 {
11694 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11695 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11696 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11697
11698 for (i = 0; i < (full ? 8 : 4); i++)
11699 {
11700 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11701 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11702 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11703 }
11704 }
11705 break;
11706
11707 case 2:
11708 {
11709 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11710 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11711 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11712
11713 for (i = 0; i < (full ? 4 : 2); i++)
11714 {
11715 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11716 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11717 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11718 }
11719 }
11720 break;
11721
11722 case 3:
11723 {
11724 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11725 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11726 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11727
11728 for (i = 0; i < (full ? 2 : 1); i++)
11729 {
11730 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11731 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11732 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11733 }
11734 }
11735 break;
11736
11737 default:
11738 HALT_UNALLOC;
11739 }
11740 break;
11741
11742 case 3: /* LD4R. */
11743 switch (size)
11744 {
11745 case 0:
11746 {
11747 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11748 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11749 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11750 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
11751
11752 for (i = 0; i < (full ? 16 : 8); i++)
11753 {
11754 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11755 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11756 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11757 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
11758 }
11759 }
11760 break;
11761
11762 case 1:
11763 {
11764 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11765 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11766 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11767 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
11768
11769 for (i = 0; i < (full ? 8 : 4); i++)
11770 {
11771 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11772 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11773 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11774 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
11775 }
11776 }
11777 break;
11778
11779 case 2:
11780 {
11781 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11782 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11783 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11784 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
11785
11786 for (i = 0; i < (full ? 4 : 2); i++)
11787 {
11788 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11789 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11790 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11791 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
11792 }
11793 }
11794 break;
11795
11796 case 3:
11797 {
11798 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11799 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11800 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11801 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
11802
11803 for (i = 0; i < (full ? 2 : 1); i++)
11804 {
11805 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11806 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11807 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11808 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
11809 }
11810 }
11811 break;
11812
11813 default:
11814 HALT_UNALLOC;
11815 }
11816 break;
11817
11818 default:
11819 HALT_UNALLOC;
11820 }
11821}
11822
11823static void
11824do_vec_load_store (sim_cpu *cpu)
11825{
11826 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11827
11828 instr[31] = 0
11829 instr[30] = element selector 0=>half, 1=>all elements
11830 instr[29,25] = 00110
11831 instr[24] = ?
11832 instr[23] = 0=>simple, 1=>post
11833 instr[22] = 0=>store, 1=>load
11834 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11835 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11836 11111 (immediate post inc)
11837 instr[15,12] = elements and destinations. eg for load:
11838 0000=>LD4 => load multiple 4-element to
11839 four consecutive registers
11840 0100=>LD3 => load multiple 3-element to
11841 three consecutive registers
11842 1000=>LD2 => load multiple 2-element to
11843 two consecutive registers
11844 0010=>LD1 => load multiple 1-element to
11845 four consecutive registers
11846 0110=>LD1 => load multiple 1-element to
11847 three consecutive registers
11848 1010=>LD1 => load multiple 1-element to
11849 two consecutive registers
11850 0111=>LD1 => load multiple 1-element to
11851 one register
11852 1100=>LDR1,LDR2
11853 1110=>LDR3,LDR4
11854 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11855 10=> word(s), 11=> double(d)
11856 instr[9,5] = Vn, can be SP
11857 instr[4,0] = Vd */
11858
11859 int post;
11860 int load;
11861 unsigned vn;
11862 uint64_t address;
11863 int type;
11864
7517e550 11865 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
11866 HALT_NYI;
11867
ef0d8ffc
NC
11868 type = INSTR (15, 12);
11869 if (type != 0xE && type != 0xE && INSTR (21, 21) != 0)
2e8cf49e
NC
11870 HALT_NYI;
11871
ef0d8ffc
NC
11872 post = INSTR (23, 23);
11873 load = INSTR (22, 22);
11874 vn = INSTR (9, 5);
2e8cf49e
NC
11875 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11876
11877 if (post)
11878 {
ef0d8ffc 11879 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
11880
11881 if (vm == R31)
11882 {
11883 unsigned sizeof_operation;
11884
11885 switch (type)
11886 {
11887 case 0: sizeof_operation = 32; break;
11888 case 4: sizeof_operation = 24; break;
11889 case 8: sizeof_operation = 16; break;
11890
11891 case 0xC:
ef0d8ffc
NC
11892 sizeof_operation = INSTR (21, 21) ? 2 : 1;
11893 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11894 break;
11895
11896 case 0xE:
ef0d8ffc
NC
11897 sizeof_operation = INSTR (21, 21) ? 8 : 4;
11898 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11899 break;
11900
2e8cf49e 11901 case 7:
57aa1742
NC
11902 /* One register, immediate offset variant. */
11903 sizeof_operation = 8;
11904 break;
ef0d8ffc 11905
57aa1742
NC
11906 case 10:
11907 /* Two registers, immediate offset variant. */
11908 sizeof_operation = 16;
11909 break;
11910
11911 case 6:
11912 /* Three registers, immediate offset variant. */
11913 sizeof_operation = 24;
11914 break;
11915
11916 case 2:
11917 /* Four registers, immediate offset variant. */
11918 sizeof_operation = 32;
2e8cf49e
NC
11919 break;
11920
11921 default:
11922 HALT_UNALLOC;
11923 }
11924
ef0d8ffc 11925 if (INSTR (30, 30))
2e8cf49e
NC
11926 sizeof_operation *= 2;
11927
11928 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
11929 }
11930 else
11931 aarch64_set_reg_u64 (cpu, vn, SP_OK,
11932 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
11933 }
11934 else
11935 {
11936 NYI_assert (20, 16, 0);
11937 }
11938
11939 if (load)
11940 {
11941 switch (type)
11942 {
11943 case 0: LD4 (cpu, address); return;
11944 case 4: LD3 (cpu, address); return;
11945 case 8: LD2 (cpu, address); return;
11946 case 2: LD1_4 (cpu, address); return;
11947 case 6: LD1_3 (cpu, address); return;
11948 case 10: LD1_2 (cpu, address); return;
11949 case 7: LD1_1 (cpu, address); return;
11950
11951 case 0xE:
11952 case 0xC: do_vec_LDnR (cpu, address); return;
11953
11954 default:
11955 HALT_NYI;
11956 }
11957 }
11958
11959 /* Stores. */
11960 switch (type)
11961 {
11962 case 0: ST4 (cpu, address); return;
11963 case 4: ST3 (cpu, address); return;
11964 case 8: ST2 (cpu, address); return;
11965 case 2: ST1_4 (cpu, address); return;
11966 case 6: ST1_3 (cpu, address); return;
11967 case 10: ST1_2 (cpu, address); return;
11968 case 7: ST1_1 (cpu, address); return;
11969 default:
11970 HALT_NYI;
11971 }
11972}
11973
11974static void
11975dexLdSt (sim_cpu *cpu)
11976{
11977 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11978 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11979 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11980 bits [29,28:26] of a LS are the secondary dispatch vector. */
11981 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11982
11983 switch (group2)
11984 {
11985 case LS_EXCL_000:
11986 dexLoadExclusive (cpu); return;
11987
11988 case LS_LIT_010:
11989 case LS_LIT_011:
11990 dexLoadLiteral (cpu); return;
11991
11992 case LS_OTHER_110:
11993 case LS_OTHER_111:
11994 dexLoadOther (cpu); return;
11995
11996 case LS_ADVSIMD_001:
11997 do_vec_load_store (cpu); return;
11998
11999 case LS_PAIR_100:
12000 dex_load_store_pair_gr (cpu); return;
12001
12002 case LS_PAIR_101:
12003 dex_load_store_pair_fp (cpu); return;
12004
12005 default:
12006 /* Should never reach here. */
12007 HALT_NYI;
12008 }
12009}
12010
12011/* Specific decode and execute for group Data Processing Register. */
12012
12013static void
12014dexLogicalShiftedRegister (sim_cpu *cpu)
12015{
ef0d8ffc
NC
12016 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12017 instr[30,29] = op
12018 instr[28:24] = 01010
2e8cf49e 12019 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
12020 instr[21] = N
12021 instr[20,16] = Rm
2e8cf49e 12022 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
12023 instr[9,5] = Rn
12024 instr[4,0] = Rd */
2e8cf49e 12025
ef0d8ffc
NC
12026 uint32_t size = INSTR (31, 31);
12027 Shift shiftType = INSTR (23, 22);
12028 uint32_t count = INSTR (15, 10);
2e8cf49e 12029
ef0d8ffc
NC
12030 /* 32 bit operations must have count[5] = 0.
12031 or else we have an UNALLOC. */
12032 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
12033 HALT_UNALLOC;
12034
ef0d8ffc
NC
12035 /* Dispatch on size:op:N. */
12036 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
12037 {
12038 case 0: and32_shift (cpu, shiftType, count); return;
12039 case 1: bic32_shift (cpu, shiftType, count); return;
12040 case 2: orr32_shift (cpu, shiftType, count); return;
12041 case 3: orn32_shift (cpu, shiftType, count); return;
12042 case 4: eor32_shift (cpu, shiftType, count); return;
12043 case 5: eon32_shift (cpu, shiftType, count); return;
12044 case 6: ands32_shift (cpu, shiftType, count); return;
12045 case 7: bics32_shift (cpu, shiftType, count); return;
12046 case 8: and64_shift (cpu, shiftType, count); return;
12047 case 9: bic64_shift (cpu, shiftType, count); return;
12048 case 10:orr64_shift (cpu, shiftType, count); return;
12049 case 11:orn64_shift (cpu, shiftType, count); return;
12050 case 12:eor64_shift (cpu, shiftType, count); return;
12051 case 13:eon64_shift (cpu, shiftType, count); return;
12052 case 14:ands64_shift (cpu, shiftType, count); return;
12053 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
12054 }
12055}
12056
12057/* 32 bit conditional select. */
12058static void
12059csel32 (sim_cpu *cpu, CondCode cc)
12060{
ef0d8ffc
NC
12061 unsigned rm = INSTR (20, 16);
12062 unsigned rn = INSTR (9, 5);
12063 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12064
12065 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12066 testConditionCode (cpu, cc)
12067 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12068 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
12069}
12070
12071/* 64 bit conditional select. */
12072static void
12073csel64 (sim_cpu *cpu, CondCode cc)
12074{
ef0d8ffc
NC
12075 unsigned rm = INSTR (20, 16);
12076 unsigned rn = INSTR (9, 5);
12077 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12078
12079 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12080 testConditionCode (cpu, cc)
12081 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12082 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
12083}
12084
12085/* 32 bit conditional increment. */
12086static void
12087csinc32 (sim_cpu *cpu, CondCode cc)
12088{
ef0d8ffc
NC
12089 unsigned rm = INSTR (20, 16);
12090 unsigned rn = INSTR (9, 5);
12091 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12092
12093 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12094 testConditionCode (cpu, cc)
12095 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12096 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
12097}
12098
12099/* 64 bit conditional increment. */
12100static void
12101csinc64 (sim_cpu *cpu, CondCode cc)
12102{
ef0d8ffc
NC
12103 unsigned rm = INSTR (20, 16);
12104 unsigned rn = INSTR (9, 5);
12105 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12106
12107 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12108 testConditionCode (cpu, cc)
12109 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12110 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
12111}
12112
12113/* 32 bit conditional invert. */
12114static void
12115csinv32 (sim_cpu *cpu, CondCode cc)
12116{
ef0d8ffc
NC
12117 unsigned rm = INSTR (20, 16);
12118 unsigned rn = INSTR (9, 5);
12119 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12120
12121 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12122 testConditionCode (cpu, cc)
12123 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12124 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
12125}
12126
12127/* 64 bit conditional invert. */
12128static void
12129csinv64 (sim_cpu *cpu, CondCode cc)
12130{
ef0d8ffc
NC
12131 unsigned rm = INSTR (20, 16);
12132 unsigned rn = INSTR (9, 5);
12133 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12134
12135 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12136 testConditionCode (cpu, cc)
12137 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12138 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
12139}
12140
12141/* 32 bit conditional negate. */
12142static void
12143csneg32 (sim_cpu *cpu, CondCode cc)
12144{
ef0d8ffc
NC
12145 unsigned rm = INSTR (20, 16);
12146 unsigned rn = INSTR (9, 5);
12147 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12148
12149 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12150 testConditionCode (cpu, cc)
12151 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12152 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
12153}
12154
12155/* 64 bit conditional negate. */
12156static void
12157csneg64 (sim_cpu *cpu, CondCode cc)
12158{
ef0d8ffc
NC
12159 unsigned rm = INSTR (20, 16);
12160 unsigned rn = INSTR (9, 5);
12161 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12162
12163 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12164 testConditionCode (cpu, cc)
12165 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12166 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
12167}
12168
12169static void
12170dexCondSelect (sim_cpu *cpu)
12171{
ef0d8ffc
NC
12172 /* instr[28,21] = 11011011
12173 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
12174 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
12175 100 ==> CSINV, 101 ==> CSNEG,
12176 _1_ ==> UNALLOC
12177 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12178 instr[15,12] = cond
12179 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
12180
ef0d8ffc
NC
12181 CondCode cc = INSTR (15, 12);
12182 uint32_t S = INSTR (29, 29);
12183 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
12184
12185 if (S == 1)
12186 HALT_UNALLOC;
12187
12188 if (op2 & 0x2)
12189 HALT_UNALLOC;
12190
ef0d8ffc 12191 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
12192 {
12193 case 0: csel32 (cpu, cc); return;
12194 case 1: csinc32 (cpu, cc); return;
12195 case 2: csinv32 (cpu, cc); return;
12196 case 3: csneg32 (cpu, cc); return;
12197 case 4: csel64 (cpu, cc); return;
12198 case 5: csinc64 (cpu, cc); return;
12199 case 6: csinv64 (cpu, cc); return;
12200 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
12201 }
12202}
12203
12204/* Some helpers for counting leading 1 or 0 bits. */
12205
12206/* Counts the number of leading bits which are the same
12207 in a 32 bit value in the range 1 to 32. */
12208static uint32_t
12209leading32 (uint32_t value)
12210{
12211 int32_t mask= 0xffff0000;
12212 uint32_t count= 16; /* Counts number of bits set in mask. */
12213 uint32_t lo = 1; /* Lower bound for number of sign bits. */
12214 uint32_t hi = 32; /* Upper bound for number of sign bits. */
12215
12216 while (lo + 1 < hi)
12217 {
12218 int32_t test = (value & mask);
12219
12220 if (test == 0 || test == mask)
12221 {
12222 lo = count;
12223 count = (lo + hi) / 2;
12224 mask >>= (count - lo);
12225 }
12226 else
12227 {
12228 hi = count;
12229 count = (lo + hi) / 2;
12230 mask <<= hi - count;
12231 }
12232 }
12233
12234 if (lo != hi)
12235 {
12236 int32_t test;
12237
12238 mask >>= 1;
12239 test = (value & mask);
12240
12241 if (test == 0 || test == mask)
12242 count = hi;
12243 else
12244 count = lo;
12245 }
12246
12247 return count;
12248}
12249
12250/* Counts the number of leading bits which are the same
12251 in a 64 bit value in the range 1 to 64. */
12252static uint64_t
12253leading64 (uint64_t value)
12254{
12255 int64_t mask= 0xffffffff00000000LL;
12256 uint64_t count = 32; /* Counts number of bits set in mask. */
12257 uint64_t lo = 1; /* Lower bound for number of sign bits. */
12258 uint64_t hi = 64; /* Upper bound for number of sign bits. */
12259
12260 while (lo + 1 < hi)
12261 {
12262 int64_t test = (value & mask);
12263
12264 if (test == 0 || test == mask)
12265 {
12266 lo = count;
12267 count = (lo + hi) / 2;
12268 mask >>= (count - lo);
12269 }
12270 else
12271 {
12272 hi = count;
12273 count = (lo + hi) / 2;
12274 mask <<= hi - count;
12275 }
12276 }
12277
12278 if (lo != hi)
12279 {
12280 int64_t test;
12281
12282 mask >>= 1;
12283 test = (value & mask);
12284
12285 if (test == 0 || test == mask)
12286 count = hi;
12287 else
12288 count = lo;
12289 }
12290
12291 return count;
12292}
12293
12294/* Bit operations. */
12295/* N.B register args may not be SP. */
12296
12297/* 32 bit count leading sign bits. */
12298static void
12299cls32 (sim_cpu *cpu)
12300{
ef0d8ffc
NC
12301 unsigned rn = INSTR (9, 5);
12302 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12303
12304 /* N.B. the result needs to exclude the leading bit. */
12305 aarch64_set_reg_u64
12306 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
12307}
12308
12309/* 64 bit count leading sign bits. */
12310static void
12311cls64 (sim_cpu *cpu)
12312{
ef0d8ffc
NC
12313 unsigned rn = INSTR (9, 5);
12314 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12315
12316 /* N.B. the result needs to exclude the leading bit. */
12317 aarch64_set_reg_u64
12318 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
12319}
12320
12321/* 32 bit count leading zero bits. */
12322static void
12323clz32 (sim_cpu *cpu)
12324{
ef0d8ffc
NC
12325 unsigned rn = INSTR (9, 5);
12326 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12327 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12328
12329 /* if the sign (top) bit is set then the count is 0. */
12330 if (pick32 (value, 31, 31))
12331 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12332 else
12333 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
12334}
12335
12336/* 64 bit count leading zero bits. */
12337static void
12338clz64 (sim_cpu *cpu)
12339{
ef0d8ffc
NC
12340 unsigned rn = INSTR (9, 5);
12341 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12342 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12343
12344 /* if the sign (top) bit is set then the count is 0. */
12345 if (pick64 (value, 63, 63))
12346 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12347 else
12348 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
12349}
12350
12351/* 32 bit reverse bits. */
12352static void
12353rbit32 (sim_cpu *cpu)
12354{
ef0d8ffc
NC
12355 unsigned rn = INSTR (9, 5);
12356 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12357 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12358 uint32_t result = 0;
12359 int i;
12360
12361 for (i = 0; i < 32; i++)
12362 {
12363 result <<= 1;
12364 result |= (value & 1);
12365 value >>= 1;
12366 }
12367 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12368}
12369
12370/* 64 bit reverse bits. */
12371static void
12372rbit64 (sim_cpu *cpu)
12373{
ef0d8ffc
NC
12374 unsigned rn = INSTR (9, 5);
12375 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12376 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12377 uint64_t result = 0;
12378 int i;
12379
12380 for (i = 0; i < 64; i++)
12381 {
12382 result <<= 1;
57aa1742 12383 result |= (value & 1UL);
2e8cf49e
NC
12384 value >>= 1;
12385 }
12386 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12387}
12388
12389/* 32 bit reverse bytes. */
12390static void
12391rev32 (sim_cpu *cpu)
12392{
ef0d8ffc
NC
12393 unsigned rn = INSTR (9, 5);
12394 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12395 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12396 uint32_t result = 0;
12397 int i;
12398
12399 for (i = 0; i < 4; i++)
12400 {
12401 result <<= 8;
12402 result |= (value & 0xff);
12403 value >>= 8;
12404 }
12405 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12406}
12407
12408/* 64 bit reverse bytes. */
12409static void
12410rev64 (sim_cpu *cpu)
12411{
ef0d8ffc
NC
12412 unsigned rn = INSTR (9, 5);
12413 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12414 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12415 uint64_t result = 0;
12416 int i;
12417
12418 for (i = 0; i < 8; i++)
12419 {
12420 result <<= 8;
12421 result |= (value & 0xffULL);
12422 value >>= 8;
12423 }
12424 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12425}
12426
12427/* 32 bit reverse shorts. */
12428/* N.B.this reverses the order of the bytes in each half word. */
12429static void
12430revh32 (sim_cpu *cpu)
12431{
ef0d8ffc
NC
12432 unsigned rn = INSTR (9, 5);
12433 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12434 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12435 uint32_t result = 0;
12436 int i;
12437
12438 for (i = 0; i < 2; i++)
12439 {
12440 result <<= 8;
12441 result |= (value & 0x00ff00ff);
12442 value >>= 8;
12443 }
12444 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12445}
12446
12447/* 64 bit reverse shorts. */
12448/* N.B.this reverses the order of the bytes in each half word. */
12449static void
12450revh64 (sim_cpu *cpu)
12451{
ef0d8ffc
NC
12452 unsigned rn = INSTR (9, 5);
12453 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12454 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12455 uint64_t result = 0;
12456 int i;
12457
12458 for (i = 0; i < 2; i++)
12459 {
12460 result <<= 8;
12461 result |= (value & 0x00ff00ff00ff00ffULL);
12462 value >>= 8;
12463 }
12464 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12465}
12466
12467static void
12468dexDataProc1Source (sim_cpu *cpu)
12469{
ef0d8ffc
NC
12470 /* instr[30] = 1
12471 instr[28,21] = 111010110
12472 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12473 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12474 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12475 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12476 000010 ==> REV, 000011 ==> UNALLOC
12477 000100 ==> CLZ, 000101 ==> CLS
12478 ow ==> UNALLOC
ef0d8ffc
NC
12479 instr[9,5] = rn : may not be SP
12480 instr[4,0] = rd : may not be SP. */
2e8cf49e 12481
ef0d8ffc
NC
12482 uint32_t S = INSTR (29, 29);
12483 uint32_t opcode2 = INSTR (20, 16);
12484 uint32_t opcode = INSTR (15, 10);
12485 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12486
12487 if (S == 1)
12488 HALT_UNALLOC;
12489
12490 if (opcode2 != 0)
12491 HALT_UNALLOC;
12492
12493 if (opcode & 0x38)
12494 HALT_UNALLOC;
12495
12496 switch (dispatch)
12497 {
12498 case 0: rbit32 (cpu); return;
12499 case 1: revh32 (cpu); return;
12500 case 2: rev32 (cpu); return;
12501 case 4: clz32 (cpu); return;
12502 case 5: cls32 (cpu); return;
12503 case 8: rbit64 (cpu); return;
12504 case 9: revh64 (cpu); return;
12505 case 10:rev32 (cpu); return;
12506 case 11:rev64 (cpu); return;
12507 case 12:clz64 (cpu); return;
12508 case 13:cls64 (cpu); return;
12509 default: HALT_UNALLOC;
12510 }
12511}
12512
12513/* Variable shift.
12514 Shifts by count supplied in register.
12515 N.B register args may not be SP.
12516 These all use the shifted auxiliary function for
12517 simplicity and clarity. Writing the actual shift
12518 inline would avoid a branch and so be faster but
12519 would also necessitate getting signs right. */
12520
12521/* 32 bit arithmetic shift right. */
12522static void
12523asrv32 (sim_cpu *cpu)
12524{
ef0d8ffc
NC
12525 unsigned rm = INSTR (20, 16);
12526 unsigned rn = INSTR (9, 5);
12527 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12528
12529 aarch64_set_reg_u64
12530 (cpu, rd, NO_SP,
12531 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12532 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12533}
12534
12535/* 64 bit arithmetic shift right. */
12536static void
12537asrv64 (sim_cpu *cpu)
12538{
ef0d8ffc
NC
12539 unsigned rm = INSTR (20, 16);
12540 unsigned rn = INSTR (9, 5);
12541 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12542
12543 aarch64_set_reg_u64
12544 (cpu, rd, NO_SP,
12545 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12546 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12547}
12548
12549/* 32 bit logical shift left. */
12550static void
12551lslv32 (sim_cpu *cpu)
12552{
ef0d8ffc
NC
12553 unsigned rm = INSTR (20, 16);
12554 unsigned rn = INSTR (9, 5);
12555 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12556
12557 aarch64_set_reg_u64
12558 (cpu, rd, NO_SP,
12559 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12560 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12561}
12562
12563/* 64 bit arithmetic shift left. */
12564static void
12565lslv64 (sim_cpu *cpu)
12566{
ef0d8ffc
NC
12567 unsigned rm = INSTR (20, 16);
12568 unsigned rn = INSTR (9, 5);
12569 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12570
12571 aarch64_set_reg_u64
12572 (cpu, rd, NO_SP,
12573 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12574 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12575}
12576
12577/* 32 bit logical shift right. */
12578static void
12579lsrv32 (sim_cpu *cpu)
12580{
ef0d8ffc
NC
12581 unsigned rm = INSTR (20, 16);
12582 unsigned rn = INSTR (9, 5);
12583 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12584
12585 aarch64_set_reg_u64
12586 (cpu, rd, NO_SP,
12587 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12588 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12589}
12590
12591/* 64 bit logical shift right. */
12592static void
12593lsrv64 (sim_cpu *cpu)
12594{
ef0d8ffc
NC
12595 unsigned rm = INSTR (20, 16);
12596 unsigned rn = INSTR (9, 5);
12597 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12598
12599 aarch64_set_reg_u64
12600 (cpu, rd, NO_SP,
12601 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12602 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12603}
12604
12605/* 32 bit rotate right. */
12606static void
12607rorv32 (sim_cpu *cpu)
12608{
ef0d8ffc
NC
12609 unsigned rm = INSTR (20, 16);
12610 unsigned rn = INSTR (9, 5);
12611 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12612
12613 aarch64_set_reg_u64
12614 (cpu, rd, NO_SP,
12615 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12616 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12617}
12618
12619/* 64 bit rotate right. */
12620static void
12621rorv64 (sim_cpu *cpu)
12622{
ef0d8ffc
NC
12623 unsigned rm = INSTR (20, 16);
12624 unsigned rn = INSTR (9, 5);
12625 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12626
12627 aarch64_set_reg_u64
12628 (cpu, rd, NO_SP,
12629 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12630 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12631}
12632
12633
12634/* divide. */
12635
12636/* 32 bit signed divide. */
12637static void
12638cpuiv32 (sim_cpu *cpu)
12639{
ef0d8ffc
NC
12640 unsigned rm = INSTR (20, 16);
12641 unsigned rn = INSTR (9, 5);
12642 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12643 /* N.B. the pseudo-code does the divide using 64 bit data. */
12644 /* TODO : check that this rounds towards zero as required. */
12645 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12646 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12647
12648 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12649 divisor ? ((int32_t) (dividend / divisor)) : 0);
12650}
12651
12652/* 64 bit signed divide. */
12653static void
12654cpuiv64 (sim_cpu *cpu)
12655{
ef0d8ffc
NC
12656 unsigned rm = INSTR (20, 16);
12657 unsigned rn = INSTR (9, 5);
12658 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12659
12660 /* TODO : check that this rounds towards zero as required. */
12661 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12662
12663 aarch64_set_reg_s64
12664 (cpu, rd, NO_SP,
12665 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12666}
12667
12668/* 32 bit unsigned divide. */
12669static void
12670udiv32 (sim_cpu *cpu)
12671{
ef0d8ffc
NC
12672 unsigned rm = INSTR (20, 16);
12673 unsigned rn = INSTR (9, 5);
12674 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12675
12676 /* N.B. the pseudo-code does the divide using 64 bit data. */
12677 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12678 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12679
12680 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12681 divisor ? (uint32_t) (dividend / divisor) : 0);
12682}
12683
12684/* 64 bit unsigned divide. */
12685static void
12686udiv64 (sim_cpu *cpu)
12687{
ef0d8ffc
NC
12688 unsigned rm = INSTR (20, 16);
12689 unsigned rn = INSTR (9, 5);
12690 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12691
12692 /* TODO : check that this rounds towards zero as required. */
12693 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12694
12695 aarch64_set_reg_u64
12696 (cpu, rd, NO_SP,
12697 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12698}
12699
12700static void
12701dexDataProc2Source (sim_cpu *cpu)
12702{
12703 /* assert instr[30] == 0
12704 instr[28,21] == 11010110
12705 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12706 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12707 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12708 001000 ==> LSLV, 001001 ==> LSRV
12709 001010 ==> ASRV, 001011 ==> RORV
12710 ow ==> UNALLOC. */
12711
12712 uint32_t dispatch;
ef0d8ffc
NC
12713 uint32_t S = INSTR (29, 29);
12714 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12715
12716 if (S == 1)
12717 HALT_UNALLOC;
12718
12719 if (opcode & 0x34)
12720 HALT_UNALLOC;
12721
ef0d8ffc 12722 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12723 | (uimm (opcode, 3, 3) << 2)
12724 | uimm (opcode, 1, 0));
12725 switch (dispatch)
12726 {
12727 case 2: udiv32 (cpu); return;
12728 case 3: cpuiv32 (cpu); return;
12729 case 4: lslv32 (cpu); return;
12730 case 5: lsrv32 (cpu); return;
12731 case 6: asrv32 (cpu); return;
12732 case 7: rorv32 (cpu); return;
12733 case 10: udiv64 (cpu); return;
12734 case 11: cpuiv64 (cpu); return;
12735 case 12: lslv64 (cpu); return;
12736 case 13: lsrv64 (cpu); return;
12737 case 14: asrv64 (cpu); return;
12738 case 15: rorv64 (cpu); return;
12739 default: HALT_UNALLOC;
12740 }
12741}
12742
12743
12744/* Multiply. */
12745
12746/* 32 bit multiply and add. */
12747static void
12748madd32 (sim_cpu *cpu)
12749{
ef0d8ffc
NC
12750 unsigned rm = INSTR (20, 16);
12751 unsigned ra = INSTR (14, 10);
12752 unsigned rn = INSTR (9, 5);
12753 unsigned rd = INSTR (4, 0);
2e8cf49e 12754
2cdad34c 12755 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12756 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12757 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12758 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12759 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12760}
12761
12762/* 64 bit multiply and add. */
12763static void
12764madd64 (sim_cpu *cpu)
12765{
ef0d8ffc
NC
12766 unsigned rm = INSTR (20, 16);
12767 unsigned ra = INSTR (14, 10);
12768 unsigned rn = INSTR (9, 5);
12769 unsigned rd = INSTR (4, 0);
2e8cf49e 12770
2cdad34c 12771 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12772 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12773 aarch64_get_reg_u64 (cpu, ra, NO_SP)
2cdad34c
NC
12774 + (aarch64_get_reg_u64 (cpu, rn, NO_SP)
12775 * aarch64_get_reg_u64 (cpu, rm, NO_SP)));
2e8cf49e
NC
12776}
12777
12778/* 32 bit multiply and sub. */
12779static void
12780msub32 (sim_cpu *cpu)
12781{
ef0d8ffc
NC
12782 unsigned rm = INSTR (20, 16);
12783 unsigned ra = INSTR (14, 10);
12784 unsigned rn = INSTR (9, 5);
12785 unsigned rd = INSTR (4, 0);
2e8cf49e 12786
2cdad34c 12787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12788 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12789 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12790 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
12791 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12792}
12793
12794/* 64 bit multiply and sub. */
12795static void
12796msub64 (sim_cpu *cpu)
12797{
ef0d8ffc
NC
12798 unsigned rm = INSTR (20, 16);
12799 unsigned ra = INSTR (14, 10);
12800 unsigned rn = INSTR (9, 5);
12801 unsigned rd = INSTR (4, 0);
2e8cf49e 12802
2cdad34c 12803 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12804 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12805 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12806 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
12807 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12808}
12809
12810/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
12811static void
12812smaddl (sim_cpu *cpu)
12813{
ef0d8ffc
NC
12814 unsigned rm = INSTR (20, 16);
12815 unsigned ra = INSTR (14, 10);
12816 unsigned rn = INSTR (9, 5);
12817 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12818
12819 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12820 obtain a 64 bit product. */
12821 aarch64_set_reg_s64
12822 (cpu, rd, NO_SP,
12823 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12824 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12825 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12826}
12827
12828/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12829static void
12830smsubl (sim_cpu *cpu)
12831{
ef0d8ffc
NC
12832 unsigned rm = INSTR (20, 16);
12833 unsigned ra = INSTR (14, 10);
12834 unsigned rn = INSTR (9, 5);
12835 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12836
12837 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12838 obtain a 64 bit product. */
12839 aarch64_set_reg_s64
12840 (cpu, rd, NO_SP,
12841 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12842 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12843 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12844}
12845
12846/* Integer Multiply/Divide. */
12847
12848/* First some macros and a helper function. */
12849/* Macros to test or access elements of 64 bit words. */
12850
12851/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12852#define LOW_WORD_MASK ((1ULL << 32) - 1)
12853/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12854#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12855/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12856#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12857
12858/* Offset of sign bit in 64 bit signed integger. */
12859#define SIGN_SHIFT_U64 63
12860/* The sign bit itself -- also identifies the minimum negative int value. */
12861#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12862/* Return true if a 64 bit signed int presented as an unsigned int is the
12863 most negative value. */
12864#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12865/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12866 int has its sign bit set to false. */
12867#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12868/* Return 1L or -1L according to whether a 64 bit signed int presented as
12869 an unsigned int has its sign bit set or not. */
12870#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12871/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12872#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12873
12874/* Multiply two 64 bit ints and return.
12875 the hi 64 bits of the 128 bit product. */
12876
12877static uint64_t
12878mul64hi (uint64_t value1, uint64_t value2)
12879{
12880 uint64_t resultmid1;
12881 uint64_t result;
12882 uint64_t value1_lo = lowWordToU64 (value1);
12883 uint64_t value1_hi = highWordToU64 (value1) ;
12884 uint64_t value2_lo = lowWordToU64 (value2);
12885 uint64_t value2_hi = highWordToU64 (value2);
12886
12887 /* Cross-multiply and collect results. */
2e8cf49e
NC
12888 uint64_t xproductlo = value1_lo * value2_lo;
12889 uint64_t xproductmid1 = value1_lo * value2_hi;
12890 uint64_t xproductmid2 = value1_hi * value2_lo;
12891 uint64_t xproducthi = value1_hi * value2_hi;
12892 uint64_t carry = 0;
12893 /* Start accumulating 64 bit results. */
12894 /* Drop bottom half of lowest cross-product. */
12895 uint64_t resultmid = xproductlo >> 32;
12896 /* Add in middle products. */
12897 resultmid = resultmid + xproductmid1;
12898
12899 /* Check for overflow. */
12900 if (resultmid < xproductmid1)
12901 /* Carry over 1 into top cross-product. */
12902 carry++;
12903
12904 resultmid1 = resultmid + xproductmid2;
12905
12906 /* Check for overflow. */
12907 if (resultmid1 < xproductmid2)
12908 /* Carry over 1 into top cross-product. */
12909 carry++;
12910
12911 /* Drop lowest 32 bits of middle cross-product. */
12912 result = resultmid1 >> 32;
12913
12914 /* Add top cross-product plus and any carry. */
12915 result += xproducthi + carry;
12916
12917 return result;
12918}
12919
12920/* Signed multiply high, source, source2 :
12921 64 bit, dest <-- high 64-bit of result. */
12922static void
12923smulh (sim_cpu *cpu)
12924{
12925 uint64_t uresult;
ef0d8ffc
NC
12926 int64_t result;
12927 unsigned rm = INSTR (20, 16);
12928 unsigned rn = INSTR (9, 5);
12929 unsigned rd = INSTR (4, 0);
12930 GReg ra = INSTR (14, 10);
12931 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12932 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
12933 uint64_t uvalue1;
12934 uint64_t uvalue2;
ef0d8ffc 12935 int64_t signum = 1;
2e8cf49e
NC
12936
12937 if (ra != R31)
12938 HALT_UNALLOC;
12939
12940 /* Convert to unsigned and use the unsigned mul64hi routine
12941 the fix the sign up afterwards. */
12942 if (value1 < 0)
12943 {
12944 signum *= -1L;
12945 uvalue1 = -value1;
12946 }
12947 else
12948 {
12949 uvalue1 = value1;
12950 }
12951
12952 if (value2 < 0)
12953 {
12954 signum *= -1L;
12955 uvalue2 = -value2;
12956 }
12957 else
12958 {
12959 uvalue2 = value2;
12960 }
12961
2cdad34c 12962 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12963 uresult = mul64hi (uvalue1, uvalue2);
12964 result = uresult;
12965 result *= signum;
12966
12967 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12968}
12969
12970/* Unsigned multiply add long -- source, source2 :
12971 32 bit, source3 : 64 bit. */
12972static void
12973umaddl (sim_cpu *cpu)
12974{
ef0d8ffc
NC
12975 unsigned rm = INSTR (20, 16);
12976 unsigned ra = INSTR (14, 10);
12977 unsigned rn = INSTR (9, 5);
12978 unsigned rd = INSTR (4, 0);
2e8cf49e 12979
2cdad34c 12980 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12981 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12982 obtain a 64 bit product. */
12983 aarch64_set_reg_u64
12984 (cpu, rd, NO_SP,
12985 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12986 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12987 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12988}
12989
12990/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12991static void
12992umsubl (sim_cpu *cpu)
12993{
ef0d8ffc
NC
12994 unsigned rm = INSTR (20, 16);
12995 unsigned ra = INSTR (14, 10);
12996 unsigned rn = INSTR (9, 5);
12997 unsigned rd = INSTR (4, 0);
2e8cf49e 12998
2cdad34c 12999 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13000 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13001 obtain a 64 bit product. */
13002 aarch64_set_reg_u64
13003 (cpu, rd, NO_SP,
13004 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13005 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13006 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13007}
13008
13009/* Unsigned multiply high, source, source2 :
13010 64 bit, dest <-- high 64-bit of result. */
13011static void
13012umulh (sim_cpu *cpu)
13013{
ef0d8ffc
NC
13014 unsigned rm = INSTR (20, 16);
13015 unsigned rn = INSTR (9, 5);
13016 unsigned rd = INSTR (4, 0);
13017 GReg ra = INSTR (14, 10);
2e8cf49e
NC
13018
13019 if (ra != R31)
13020 HALT_UNALLOC;
13021
2cdad34c 13022 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13023 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13024 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
13025 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
13026}
13027
13028static void
13029dexDataProc3Source (sim_cpu *cpu)
13030{
13031 /* assert instr[28,24] == 11011. */
13032 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
13033 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
13034 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
13035 instr[15] = o0 : 0/1 ==> ok
13036 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
13037 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
13038 0100 ==> SMULH, (64 bit only)
13039 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
13040 1100 ==> UMULH (64 bit only)
13041 ow ==> UNALLOC. */
13042
13043 uint32_t dispatch;
ef0d8ffc
NC
13044 uint32_t size = INSTR (31, 31);
13045 uint32_t op54 = INSTR (30, 29);
13046 uint32_t op31 = INSTR (23, 21);
13047 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
13048
13049 if (op54 != 0)
13050 HALT_UNALLOC;
13051
13052 if (size == 0)
13053 {
13054 if (op31 != 0)
13055 HALT_UNALLOC;
13056
13057 if (o0 == 0)
13058 madd32 (cpu);
13059 else
13060 msub32 (cpu);
13061 return;
13062 }
13063
13064 dispatch = (op31 << 1) | o0;
13065
13066 switch (dispatch)
13067 {
13068 case 0: madd64 (cpu); return;
13069 case 1: msub64 (cpu); return;
13070 case 2: smaddl (cpu); return;
13071 case 3: smsubl (cpu); return;
13072 case 4: smulh (cpu); return;
13073 case 10: umaddl (cpu); return;
13074 case 11: umsubl (cpu); return;
13075 case 12: umulh (cpu); return;
13076 default: HALT_UNALLOC;
13077 }
13078}
13079
13080static void
13081dexDPReg (sim_cpu *cpu)
13082{
13083 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13084 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
13085 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
13086 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
13087
13088 switch (group2)
13089 {
13090 case DPREG_LOG_000:
13091 case DPREG_LOG_001:
13092 dexLogicalShiftedRegister (cpu); return;
13093
13094 case DPREG_ADDSHF_010:
13095 dexAddSubtractShiftedRegister (cpu); return;
13096
13097 case DPREG_ADDEXT_011:
13098 dexAddSubtractExtendedRegister (cpu); return;
13099
13100 case DPREG_ADDCOND_100:
13101 {
13102 /* This set bundles a variety of different operations. */
13103 /* Check for. */
13104 /* 1) add/sub w carry. */
13105 uint32_t mask1 = 0x1FE00000U;
13106 uint32_t val1 = 0x1A000000U;
13107 /* 2) cond compare register/immediate. */
13108 uint32_t mask2 = 0x1FE00000U;
13109 uint32_t val2 = 0x1A400000U;
13110 /* 3) cond select. */
13111 uint32_t mask3 = 0x1FE00000U;
13112 uint32_t val3 = 0x1A800000U;
13113 /* 4) data proc 1/2 source. */
13114 uint32_t mask4 = 0x1FE00000U;
13115 uint32_t val4 = 0x1AC00000U;
13116
13117 if ((aarch64_get_instr (cpu) & mask1) == val1)
13118 dexAddSubtractWithCarry (cpu);
13119
13120 else if ((aarch64_get_instr (cpu) & mask2) == val2)
13121 CondCompare (cpu);
13122
13123 else if ((aarch64_get_instr (cpu) & mask3) == val3)
13124 dexCondSelect (cpu);
13125
13126 else if ((aarch64_get_instr (cpu) & mask4) == val4)
13127 {
13128 /* Bit 30 is clear for data proc 2 source
13129 and set for data proc 1 source. */
13130 if (aarch64_get_instr (cpu) & (1U << 30))
13131 dexDataProc1Source (cpu);
13132 else
13133 dexDataProc2Source (cpu);
13134 }
13135
13136 else
13137 /* Should not reach here. */
13138 HALT_NYI;
13139
13140 return;
13141 }
13142
13143 case DPREG_3SRC_110:
13144 dexDataProc3Source (cpu); return;
13145
13146 case DPREG_UNALLOC_101:
13147 HALT_UNALLOC;
13148
13149 case DPREG_3SRC_111:
13150 dexDataProc3Source (cpu); return;
13151
13152 default:
13153 /* Should never reach here. */
13154 HALT_NYI;
13155 }
13156}
13157
13158/* Unconditional Branch immediate.
13159 Offset is a PC-relative byte offset in the range +/- 128MiB.
13160 The offset is assumed to be raw from the decode i.e. the
13161 simulator is expected to scale them from word offsets to byte. */
13162
13163/* Unconditional branch. */
13164static void
13165buc (sim_cpu *cpu, int32_t offset)
13166{
13167 aarch64_set_next_PC_by_offset (cpu, offset);
13168}
13169
13170static unsigned stack_depth = 0;
13171
13172/* Unconditional branch and link -- writes return PC to LR. */
13173static void
13174bl (sim_cpu *cpu, int32_t offset)
13175{
2cdad34c 13176 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13177 aarch64_save_LR (cpu);
13178 aarch64_set_next_PC_by_offset (cpu, offset);
13179
13180 if (TRACE_BRANCH_P (cpu))
13181 {
13182 ++ stack_depth;
13183 TRACE_BRANCH (cpu,
13184 " %*scall %" PRIx64 " [%s]"
13185 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13186 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13187 aarch64_get_func (CPU_STATE (cpu),
13188 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13189 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13190 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13191 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13192 );
13193 }
13194}
13195
13196/* Unconditional Branch register.
13197 Branch/return address is in source register. */
13198
13199/* Unconditional branch. */
13200static void
13201br (sim_cpu *cpu)
13202{
ef0d8ffc 13203 unsigned rn = INSTR (9, 5);
2cdad34c 13204 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13205 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13206}
13207
13208/* Unconditional branch and link -- writes return PC to LR. */
13209static void
13210blr (sim_cpu *cpu)
13211{
ef0d8ffc 13212 unsigned rn = INSTR (9, 5);
2e8cf49e 13213
2cdad34c 13214 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13215 /* The pseudo code in the spec says we update LR before fetching.
13216 the value from the rn. */
13217 aarch64_save_LR (cpu);
13218 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13219
13220 if (TRACE_BRANCH_P (cpu))
13221 {
13222 ++ stack_depth;
13223 TRACE_BRANCH (cpu,
13224 " %*scall %" PRIx64 " [%s]"
13225 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13226 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13227 aarch64_get_func (CPU_STATE (cpu),
13228 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13229 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13230 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13231 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13232 );
13233 }
13234}
13235
13236/* Return -- assembler will default source to LR this is functionally
13237 equivalent to br but, presumably, unlike br it side effects the
13238 branch predictor. */
13239static void
13240ret (sim_cpu *cpu)
13241{
ef0d8ffc 13242 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
13243 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13244
2cdad34c 13245 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13246 if (TRACE_BRANCH_P (cpu))
13247 {
13248 TRACE_BRANCH (cpu,
13249 " %*sreturn [result: %" PRIx64 "]",
13250 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
13251 -- stack_depth;
13252 }
13253}
13254
13255/* NOP -- we implement this and call it from the decode in case we
13256 want to intercept it later. */
13257
13258static void
13259nop (sim_cpu *cpu)
13260{
2cdad34c 13261 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13262}
13263
13264/* Data synchronization barrier. */
13265
13266static void
13267dsb (sim_cpu *cpu)
13268{
2cdad34c 13269 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13270}
13271
13272/* Data memory barrier. */
13273
13274static void
13275dmb (sim_cpu *cpu)
13276{
2cdad34c 13277 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13278}
13279
13280/* Instruction synchronization barrier. */
13281
13282static void
13283isb (sim_cpu *cpu)
13284{
2cdad34c 13285 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13286}
13287
13288static void
13289dexBranchImmediate (sim_cpu *cpu)
13290{
13291 /* assert instr[30,26] == 00101
13292 instr[31] ==> 0 == B, 1 == BL
13293 instr[25,0] == imm26 branch offset counted in words. */
13294
ef0d8ffc 13295 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
13296 /* We have a 26 byte signed word offset which we need to pass to the
13297 execute routine as a signed byte offset. */
13298 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
13299
13300 if (top)
13301 bl (cpu, offset);
13302 else
13303 buc (cpu, offset);
13304}
13305
13306/* Control Flow. */
13307
13308/* Conditional branch
13309
13310 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
13311 a bit position in the range 0 .. 63
13312
13313 cc is a CondCode enum value as pulled out of the decode
13314
13315 N.B. any offset register (source) can only be Xn or Wn. */
13316
13317static void
13318bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
13319{
2cdad34c
NC
13320 /* The test returns TRUE if CC is met. */
13321 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13322 if (testConditionCode (cpu, cc))
13323 aarch64_set_next_PC_by_offset (cpu, offset);
13324}
13325
13326/* 32 bit branch on register non-zero. */
13327static void
13328cbnz32 (sim_cpu *cpu, int32_t offset)
13329{
ef0d8ffc 13330 unsigned rt = INSTR (4, 0);
2e8cf49e 13331
2cdad34c 13332 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13333 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
13334 aarch64_set_next_PC_by_offset (cpu, offset);
13335}
13336
13337/* 64 bit branch on register zero. */
13338static void
13339cbnz (sim_cpu *cpu, int32_t offset)
13340{
ef0d8ffc 13341 unsigned rt = INSTR (4, 0);
2e8cf49e 13342
2cdad34c 13343 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13344 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
13345 aarch64_set_next_PC_by_offset (cpu, offset);
13346}
13347
13348/* 32 bit branch on register non-zero. */
13349static void
13350cbz32 (sim_cpu *cpu, int32_t offset)
13351{
ef0d8ffc 13352 unsigned rt = INSTR (4, 0);
2e8cf49e 13353
2cdad34c 13354 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13355 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
13356 aarch64_set_next_PC_by_offset (cpu, offset);
13357}
13358
13359/* 64 bit branch on register zero. */
13360static void
13361cbz (sim_cpu *cpu, int32_t offset)
13362{
ef0d8ffc 13363 unsigned rt = INSTR (4, 0);
2e8cf49e 13364
2cdad34c 13365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13366 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
13367 aarch64_set_next_PC_by_offset (cpu, offset);
13368}
13369
13370/* Branch on register bit test non-zero -- one size fits all. */
13371static void
13372tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13373{
ef0d8ffc 13374 unsigned rt = INSTR (4, 0);
2e8cf49e 13375
2cdad34c 13376 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13377 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos))
2e8cf49e
NC
13378 aarch64_set_next_PC_by_offset (cpu, offset);
13379}
13380
2cdad34c 13381/* Branch on register bit test zero -- one size fits all. */
2e8cf49e
NC
13382static void
13383tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13384{
ef0d8ffc 13385 unsigned rt = INSTR (4, 0);
2e8cf49e 13386
2cdad34c 13387 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13388 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos)))
2e8cf49e
NC
13389 aarch64_set_next_PC_by_offset (cpu, offset);
13390}
13391
13392static void
13393dexCompareBranchImmediate (sim_cpu *cpu)
13394{
13395 /* instr[30,25] = 01 1010
13396 instr[31] = size : 0 ==> 32, 1 ==> 64
13397 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13398 instr[23,5] = simm19 branch offset counted in words
13399 instr[4,0] = rt */
13400
ef0d8ffc
NC
13401 uint32_t size = INSTR (31, 31);
13402 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13403 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13404
13405 if (size == 0)
13406 {
13407 if (op == 0)
13408 cbz32 (cpu, offset);
13409 else
13410 cbnz32 (cpu, offset);
13411 }
13412 else
13413 {
13414 if (op == 0)
13415 cbz (cpu, offset);
13416 else
13417 cbnz (cpu, offset);
13418 }
13419}
13420
13421static void
13422dexTestBranchImmediate (sim_cpu *cpu)
13423{
13424 /* instr[31] = b5 : bit 5 of test bit idx
13425 instr[30,25] = 01 1011
13426 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13427 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13428 instr[18,5] = simm14 : signed offset counted in words
13429 instr[4,0] = uimm5 */
13430
668650d5 13431 uint32_t pos = ((INSTR (31, 31) << 5) | INSTR (23, 19));
2e8cf49e
NC
13432 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13433
13434 NYI_assert (30, 25, 0x1b);
13435
ef0d8ffc 13436 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13437 tbz (cpu, pos, offset);
13438 else
13439 tbnz (cpu, pos, offset);
13440}
13441
13442static void
13443dexCondBranchImmediate (sim_cpu *cpu)
13444{
13445 /* instr[31,25] = 010 1010
13446 instr[24] = op1; op => 00 ==> B.cond
13447 instr[23,5] = simm19 : signed offset counted in words
13448 instr[4] = op0
13449 instr[3,0] = cond */
13450
13451 int32_t offset;
ef0d8ffc 13452 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13453
13454 NYI_assert (31, 25, 0x2a);
13455
13456 if (op != 0)
13457 HALT_UNALLOC;
13458
13459 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13460
ef0d8ffc 13461 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13462}
13463
13464static void
13465dexBranchRegister (sim_cpu *cpu)
13466{
13467 /* instr[31,25] = 110 1011
13468 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13469 instr[20,16] = op2 : must be 11111
13470 instr[15,10] = op3 : must be 000000
13471 instr[4,0] = op2 : must be 11111. */
13472
ef0d8ffc
NC
13473 uint32_t op = INSTR (24, 21);
13474 uint32_t op2 = INSTR (20, 16);
13475 uint32_t op3 = INSTR (15, 10);
13476 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13477
13478 NYI_assert (31, 25, 0x6b);
13479
13480 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13481 HALT_UNALLOC;
13482
13483 if (op == 0)
13484 br (cpu);
13485
13486 else if (op == 1)
13487 blr (cpu);
13488
13489 else if (op == 2)
13490 ret (cpu);
13491
13492 else
13493 {
ef0d8ffc 13494 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13495 /* anything else is unallocated. */
ef0d8ffc 13496 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13497
13498 if (rn != 0x1f)
13499 HALT_UNALLOC;
13500
13501 if (op == 4 || op == 5)
13502 HALT_NYI;
13503
13504 HALT_UNALLOC;
13505 }
13506}
13507
13508/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13509 but this may not be available. So instead we define the values we need
13510 here. */
13511#define AngelSVC_Reason_Open 0x01
13512#define AngelSVC_Reason_Close 0x02
13513#define AngelSVC_Reason_Write 0x05
13514#define AngelSVC_Reason_Read 0x06
13515#define AngelSVC_Reason_IsTTY 0x09
13516#define AngelSVC_Reason_Seek 0x0A
13517#define AngelSVC_Reason_FLen 0x0C
13518#define AngelSVC_Reason_Remove 0x0E
13519#define AngelSVC_Reason_Rename 0x0F
13520#define AngelSVC_Reason_Clock 0x10
13521#define AngelSVC_Reason_Time 0x11
13522#define AngelSVC_Reason_System 0x12
13523#define AngelSVC_Reason_Errno 0x13
13524#define AngelSVC_Reason_GetCmdLine 0x15
13525#define AngelSVC_Reason_HeapInfo 0x16
13526#define AngelSVC_Reason_ReportException 0x18
13527#define AngelSVC_Reason_Elapsed 0x30
13528
13529
13530static void
13531handle_halt (sim_cpu *cpu, uint32_t val)
13532{
13533 uint64_t result = 0;
13534
2cdad34c 13535 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13536 if (val != 0xf000)
13537 {
13538 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13539 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13540 sim_stopped, SIM_SIGTRAP);
13541 }
13542
13543 /* We have encountered an Angel SVC call. See if we can process it. */
13544 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13545 {
13546 case AngelSVC_Reason_HeapInfo:
13547 {
13548 /* Get the values. */
13549 uint64_t stack_top = aarch64_get_stack_start (cpu);
13550 uint64_t heap_base = aarch64_get_heap_start (cpu);
13551
13552 /* Get the pointer */
13553 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13554 ptr = aarch64_get_mem_u64 (cpu, ptr);
13555
13556 /* Fill in the memory block. */
13557 /* Start addr of heap. */
13558 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13559 /* End addr of heap. */
13560 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13561 /* Lowest stack addr. */
13562 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13563 /* Initial stack addr. */
13564 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13565
13566 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13567 }
13568 break;
13569
13570 case AngelSVC_Reason_Open:
13571 {
13572 /* Get the pointer */
13573 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13574 /* FIXME: For now we just assume that we will only be asked
13575 to open the standard file descriptors. */
13576 static int fd = 0;
13577 result = fd ++;
13578
13579 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13580 }
13581 break;
13582
13583 case AngelSVC_Reason_Close:
13584 {
13585 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13586 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13587 result = 0;
13588 }
13589 break;
13590
13591 case AngelSVC_Reason_Errno:
13592 result = 0;
13593 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13594 break;
13595
13596 case AngelSVC_Reason_Clock:
13597 result =
13598#ifdef CLOCKS_PER_SEC
13599 (CLOCKS_PER_SEC >= 100)
13600 ? (clock () / (CLOCKS_PER_SEC / 100))
13601 : ((clock () * 100) / CLOCKS_PER_SEC)
13602#else
13603 /* Presume unix... clock() returns microseconds. */
13604 (clock () / 10000)
13605#endif
13606 ;
13607 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13608 break;
13609
13610 case AngelSVC_Reason_GetCmdLine:
13611 {
13612 /* Get the pointer */
13613 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13614 ptr = aarch64_get_mem_u64 (cpu, ptr);
13615
13616 /* FIXME: No command line for now. */
13617 aarch64_set_mem_u64 (cpu, ptr, 0);
13618 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13619 }
13620 break;
13621
13622 case AngelSVC_Reason_IsTTY:
13623 result = 1;
13624 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13625 break;
13626
13627 case AngelSVC_Reason_Write:
13628 {
13629 /* Get the pointer */
13630 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13631 /* Get the write control block. */
13632 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13633 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13634 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13635
13636 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13637 PRIx64 " on descriptor %" PRIx64,
13638 len, buf, fd);
13639
13640 if (len > 1280)
13641 {
13642 TRACE_SYSCALL (cpu,
13643 " AngelSVC: Write: Suspiciously long write: %ld",
13644 (long) len);
13645 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13646 sim_stopped, SIM_SIGBUS);
13647 }
13648 else if (fd == 1)
13649 {
13650 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13651 }
13652 else if (fd == 2)
13653 {
13654 TRACE (cpu, 0, "\n");
13655 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13656 (int) len, aarch64_get_mem_ptr (cpu, buf));
13657 TRACE (cpu, 0, "\n");
13658 }
13659 else
13660 {
13661 TRACE_SYSCALL (cpu,
13662 " AngelSVC: Write: Unexpected file handle: %d",
13663 (int) fd);
13664 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13665 sim_stopped, SIM_SIGABRT);
13666 }
13667 }
13668 break;
13669
13670 case AngelSVC_Reason_ReportException:
13671 {
13672 /* Get the pointer */
13673 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13674 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13675 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13676 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13677
13678 TRACE_SYSCALL (cpu,
13679 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13680 type, state);
13681
13682 if (type == 0x20026)
13683 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13684 sim_exited, state);
13685 else
13686 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13687 sim_stopped, SIM_SIGINT);
13688 }
13689 break;
13690
13691 case AngelSVC_Reason_Read:
13692 case AngelSVC_Reason_FLen:
13693 case AngelSVC_Reason_Seek:
13694 case AngelSVC_Reason_Remove:
13695 case AngelSVC_Reason_Time:
13696 case AngelSVC_Reason_System:
13697 case AngelSVC_Reason_Rename:
13698 case AngelSVC_Reason_Elapsed:
13699 default:
13700 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13701 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13702 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13703 sim_stopped, SIM_SIGTRAP);
13704 }
13705
13706 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13707}
13708
13709static void
13710dexExcpnGen (sim_cpu *cpu)
13711{
13712 /* instr[31:24] = 11010100
13713 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13714 010 ==> HLT, 101 ==> DBG GEN EXCPN
13715 instr[20,5] = imm16
13716 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13717 instr[1,0] = LL : discriminates opc */
13718
ef0d8ffc
NC
13719 uint32_t opc = INSTR (23, 21);
13720 uint32_t imm16 = INSTR (20, 5);
13721 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13722 uint32_t LL;
13723
13724 NYI_assert (31, 24, 0xd4);
13725
13726 if (opc2 != 0)
13727 HALT_UNALLOC;
13728
ef0d8ffc 13729 LL = INSTR (1, 0);
2e8cf49e
NC
13730
13731 /* We only implement HLT and BRK for now. */
13732 if (opc == 1 && LL == 0)
13733 {
13734 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13735 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13736 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13737 }
13738
13739 if (opc == 2 && LL == 0)
13740 handle_halt (cpu, imm16);
13741
13742 else if (opc == 0 || opc == 5)
13743 HALT_NYI;
13744
13745 else
13746 HALT_UNALLOC;
13747}
13748
5ab6d79e 13749/* Stub for accessing system registers. */
caa8d700
NC
13750
13751static uint64_t
13752system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13753 unsigned crm, unsigned op2)
13754{
13755 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13756 /* DCZID_EL0 - the Data Cache Zero ID register.
13757 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13758 we return a value with the disable bit set.
13759 We implement support for the DCZID register since
13760 it is used by the C library's memset function. */
caa8d700
NC
13761 return ((uint64_t) 1) << 4;
13762
5ab6d79e
NC
13763 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13764 /* Cache Type Register. */
13765 return 0x80008000UL;
13766
13767 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13768 /* TPIDR_EL0 - thread pointer id. */
13769 return aarch64_get_thread_id (cpu);
13770
13771 if (op1 == 3 && crm == 4 && op2 == 0)
13772 return aarch64_get_FPCR (cpu);
13773
13774 if (op1 == 3 && crm == 4 && op2 == 1)
13775 return aarch64_get_FPSR (cpu);
13776
13777 else if (op1 == 3 && crm == 2 && op2 == 0)
13778 return aarch64_get_CPSR (cpu);
13779
caa8d700
NC
13780 HALT_NYI;
13781}
13782
5ab6d79e
NC
13783static void
13784system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13785 unsigned crm, unsigned op2, uint64_t val)
13786{
13787 if (op1 == 3 && crm == 4 && op2 == 0)
13788 aarch64_set_FPCR (cpu, val);
13789
13790 else if (op1 == 3 && crm == 4 && op2 == 1)
13791 aarch64_set_FPSR (cpu, val);
13792
13793 else if (op1 == 3 && crm == 2 && op2 == 0)
13794 aarch64_set_CPSR (cpu, val);
13795
13796 else
13797 HALT_NYI;
13798}
ef0d8ffc 13799
caa8d700
NC
13800static void
13801do_mrs (sim_cpu *cpu)
13802{
5ab6d79e 13803 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
13804 instr[19] = op0
13805 instr[18,16] = op1
13806 instr[15,12] = CRn
13807 instr[11,8] = CRm
13808 instr[7,5] = op2
13809 instr[4,0] = Rt */
ef0d8ffc
NC
13810 unsigned sys_op0 = INSTR (19, 19) + 2;
13811 unsigned sys_op1 = INSTR (18, 16);
13812 unsigned sys_crn = INSTR (15, 12);
13813 unsigned sys_crm = INSTR (11, 8);
13814 unsigned sys_op2 = INSTR (7, 5);
13815 unsigned rt = INSTR (4, 0);
caa8d700 13816
2cdad34c 13817 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
caa8d700
NC
13818 aarch64_set_reg_u64 (cpu, rt, NO_SP,
13819 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
13820}
13821
5ab6d79e
NC
13822static void
13823do_MSR_immediate (sim_cpu *cpu)
13824{
13825 /* instr[31:19] = 1101 0101 0000 0
13826 instr[18,16] = op1
13827 instr[15,12] = 0100
13828 instr[11,8] = CRm
13829 instr[7,5] = op2
13830 instr[4,0] = 1 1111 */
13831
ef0d8ffc
NC
13832 unsigned op1 = INSTR (18, 16);
13833 /*unsigned crm = INSTR (11, 8);*/
13834 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
13835
13836 NYI_assert (31, 19, 0x1AA0);
13837 NYI_assert (15, 12, 0x4);
13838 NYI_assert (4, 0, 0x1F);
13839
13840 if (op1 == 0)
13841 {
13842 if (op2 == 5)
13843 HALT_NYI; /* set SPSel. */
13844 else
13845 HALT_UNALLOC;
13846 }
13847 else if (op1 == 3)
13848 {
13849 if (op2 == 6)
13850 HALT_NYI; /* set DAIFset. */
13851 else if (op2 == 7)
13852 HALT_NYI; /* set DAIFclr. */
13853 else
13854 HALT_UNALLOC;
13855 }
13856 else
13857 HALT_UNALLOC;
13858}
13859
13860static void
13861do_MSR_reg (sim_cpu *cpu)
13862{
13863 /* instr[31:20] = 1101 0101 0001
13864 instr[19] = op0
13865 instr[18,16] = op1
13866 instr[15,12] = CRn
13867 instr[11,8] = CRm
13868 instr[7,5] = op2
13869 instr[4,0] = Rt */
13870
ef0d8ffc
NC
13871 unsigned sys_op0 = INSTR (19, 19) + 2;
13872 unsigned sys_op1 = INSTR (18, 16);
13873 unsigned sys_crn = INSTR (15, 12);
13874 unsigned sys_crm = INSTR (11, 8);
13875 unsigned sys_op2 = INSTR (7, 5);
13876 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
13877
13878 NYI_assert (31, 20, 0xD51);
ef0d8ffc 13879
2cdad34c 13880 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
13881 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
13882 aarch64_get_reg_u64 (cpu, rt, NO_SP));
13883}
13884
13885static void
ef0d8ffc 13886do_SYS (sim_cpu *cpu)
5ab6d79e
NC
13887{
13888 /* instr[31,19] = 1101 0101 0000 1
13889 instr[18,16] = op1
13890 instr[15,12] = CRn
13891 instr[11,8] = CRm
13892 instr[7,5] = op2
13893 instr[4,0] = Rt */
13894 NYI_assert (31, 19, 0x1AA1);
13895
13896 /* FIXME: For now we just silently accept system ops. */
13897}
ef0d8ffc 13898
2e8cf49e
NC
13899static void
13900dexSystem (sim_cpu *cpu)
13901{
13902 /* instr[31:22] = 1101 01010 0
13903 instr[21] = L
13904 instr[20,19] = op0
13905 instr[18,16] = op1
13906 instr[15,12] = CRn
13907 instr[11,8] = CRm
13908 instr[7,5] = op2
13909 instr[4,0] = uimm5 */
13910
13911 /* We are interested in HINT, DSB, DMB and ISB
13912
13913 Hint #0 encodes NOOP (this is the only hint we care about)
13914 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
13915 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
13916
13917 DSB, DMB, ISB are data store barrier, data memory barrier and
13918 instruction store barrier, respectively, where
13919
13920 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
13921 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
13922 CRm<3:2> ==> domain, CRm<1:0> ==> types,
13923 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
13924 10 ==> InerShareable, 11 ==> FullSystem
13925 types : 01 ==> Reads, 10 ==> Writes,
13926 11 ==> All, 00 ==> All (domain == FullSystem). */
13927
ef0d8ffc 13928 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
13929
13930 NYI_assert (31, 22, 0x354);
13931
5ab6d79e 13932 switch (INSTR (21, 12))
2e8cf49e
NC
13933 {
13934 case 0x032:
13935 if (rt == 0x1F)
13936 {
13937 /* NOP has CRm != 0000 OR. */
13938 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
13939 uint32_t crm = INSTR (11, 8);
13940 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13941
13942 if (crm != 0 || (op2 == 0 || op2 > 5))
13943 {
13944 /* Actually call nop method so we can reimplement it later. */
13945 nop (cpu);
13946 return;
13947 }
13948 }
13949 HALT_NYI;
13950
13951 case 0x033:
13952 {
ef0d8ffc 13953 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13954
13955 switch (op2)
13956 {
caa8d700 13957 case 2: HALT_NYI;
2e8cf49e
NC
13958 case 4: dsb (cpu); return;
13959 case 5: dmb (cpu); return;
13960 case 6: isb (cpu); return;
2e8cf49e
NC
13961 default: HALT_UNALLOC;
13962 }
13963 }
13964
13965 case 0x3B0:
2e8cf49e
NC
13966 case 0x3B4:
13967 case 0x3BD:
caa8d700 13968 do_mrs (cpu);
2e8cf49e
NC
13969 return;
13970
13971 case 0x0B7:
5ab6d79e 13972 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
13973 return;
13974
13975 default:
ef0d8ffc 13976 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
13977 do_MSR_reg (cpu);
13978 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
13979 do_MSR_immediate (cpu);
13980 else
13981 HALT_NYI;
caa8d700 13982 return;
2e8cf49e
NC
13983 }
13984}
13985
13986static void
13987dexBr (sim_cpu *cpu)
13988{
13989 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13990 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
13991 bits [31,29] of a BrExSys are the secondary dispatch vector. */
13992 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
13993
13994 switch (group2)
13995 {
13996 case BR_IMM_000:
13997 return dexBranchImmediate (cpu);
13998
13999 case BR_IMMCMP_001:
14000 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14001 if (!INSTR (25, 25))
2e8cf49e
NC
14002 dexCompareBranchImmediate (cpu);
14003 else
14004 dexTestBranchImmediate (cpu);
14005 return;
14006
14007 case BR_IMMCOND_010:
14008 /* This is a conditional branch if bit 25 is clear otherwise
14009 unallocated. */
ef0d8ffc 14010 if (!INSTR (25, 25))
2e8cf49e
NC
14011 dexCondBranchImmediate (cpu);
14012 else
14013 HALT_UNALLOC;
14014 return;
14015
14016 case BR_UNALLOC_011:
14017 HALT_UNALLOC;
14018
14019 case BR_IMM_100:
14020 dexBranchImmediate (cpu);
14021 return;
14022
14023 case BR_IMMCMP_101:
14024 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14025 if (!INSTR (25, 25))
2e8cf49e
NC
14026 dexCompareBranchImmediate (cpu);
14027 else
14028 dexTestBranchImmediate (cpu);
14029 return;
14030
14031 case BR_REG_110:
14032 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 14033 if (INSTR (25, 25))
2e8cf49e
NC
14034 dexBranchRegister (cpu);
14035
14036 /* This includes both Excpn Gen, System and unalloc operations.
14037 We need to decode the Excpn Gen operation BRK so we can plant
14038 debugger entry points.
ef0d8ffc 14039 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
14040 we need to decode at least one of the System operations NOP
14041 which is an alias for HINT #0.
ef0d8ffc
NC
14042 System operations have instr [24,22] = 100. */
14043 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
14044 dexExcpnGen (cpu);
14045
ef0d8ffc 14046 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
14047 dexSystem (cpu);
14048
14049 else
14050 HALT_UNALLOC;
14051
14052 return;
14053
14054 case BR_UNALLOC_111:
14055 HALT_UNALLOC;
14056
14057 default:
14058 /* Should never reach here. */
14059 HALT_NYI;
14060 }
14061}
14062
14063static void
14064aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
14065{
14066 /* We need to check if gdb wants an in here. */
14067 /* checkBreak (cpu);. */
14068
14069 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
14070
14071 switch (group)
14072 {
14073 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
14074 case GROUP_LDST_0100: dexLdSt (cpu); break;
14075 case GROUP_DPREG_0101: dexDPReg (cpu); break;
14076 case GROUP_LDST_0110: dexLdSt (cpu); break;
14077 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
14078 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
14079 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
14080 case GROUP_BREXSYS_1010: dexBr (cpu); break;
14081 case GROUP_BREXSYS_1011: dexBr (cpu); break;
14082 case GROUP_LDST_1100: dexLdSt (cpu); break;
14083 case GROUP_DPREG_1101: dexDPReg (cpu); break;
14084 case GROUP_LDST_1110: dexLdSt (cpu); break;
14085 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
14086
14087 case GROUP_UNALLOC_0001:
14088 case GROUP_UNALLOC_0010:
14089 case GROUP_UNALLOC_0011:
14090 HALT_UNALLOC;
14091
14092 default:
14093 /* Should never reach here. */
14094 HALT_NYI;
14095 }
14096}
14097
b14bdb3b 14098static bfd_boolean
2e8cf49e
NC
14099aarch64_step (sim_cpu *cpu)
14100{
14101 uint64_t pc = aarch64_get_PC (cpu);
14102
14103 if (pc == TOP_LEVEL_RETURN_PC)
14104 return FALSE;
14105
14106 aarch64_set_next_PC (cpu, pc + 4);
c7be4414
JW
14107
14108 /* Code is always little-endian. */
14109 sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
14110 & aarch64_get_instr (cpu), pc, 4);
14111 aarch64_get_instr (cpu) = endian_le2h_4 (aarch64_get_instr (cpu));
2e8cf49e 14112
57aa1742 14113 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
14114 aarch64_get_instr (cpu));
14115 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
14116
14117 aarch64_decode_and_execute (cpu, pc);
14118
14119 return TRUE;
14120}
14121
14122void
14123aarch64_run (SIM_DESC sd)
14124{
14125 sim_cpu *cpu = STATE_CPU (sd, 0);
14126
14127 while (aarch64_step (cpu))
b14bdb3b
NC
14128 {
14129 aarch64_update_PC (cpu);
14130
14131 if (sim_events_tick (sd))
14132 sim_events_process (sd);
14133 }
2e8cf49e 14134
b14bdb3b
NC
14135 sim_engine_halt (sd, cpu, NULL, aarch64_get_PC (cpu),
14136 sim_exited, aarch64_get_reg_s32 (cpu, R0, NO_SP));
2e8cf49e
NC
14137}
14138
14139void
14140aarch64_init (sim_cpu *cpu, uint64_t pc)
14141{
14142 uint64_t sp = aarch64_get_stack_start (cpu);
14143
14144 /* Install SP, FP and PC and set LR to -20
14145 so we can detect a top-level return. */
14146 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
14147 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
14148 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
14149 aarch64_set_next_PC (cpu, pc);
14150 aarch64_update_PC (cpu);
14151 aarch64_init_LIT_table ();
14152}
This page took 0.698491 seconds and 4 git commands to generate.